1 1.1 christos /* subsegs.c - subsegments - 2 1.10 christos Copyright (C) 1987-2025 Free Software Foundation, Inc. 3 1.1 christos 4 1.1 christos This file is part of GAS, the GNU Assembler. 5 1.1 christos 6 1.1 christos GAS is free software; you can redistribute it and/or modify 7 1.1 christos it under the terms of the GNU General Public License as published by 8 1.1 christos the Free Software Foundation; either version 3, or (at your option) 9 1.1 christos any later version. 10 1.1 christos 11 1.1 christos GAS is distributed in the hope that it will be useful, 12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos GNU General Public License for more details. 15 1.1 christos 16 1.1 christos You should have received a copy of the GNU General Public License 17 1.1 christos along with GAS; see the file COPYING. If not, write to the Free 18 1.1 christos Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 19 1.1 christos 02110-1301, USA. */ 20 1.1 christos 21 1.1 christos /* Segments & sub-segments. */ 22 1.1 christos 23 1.1 christos #include "as.h" 24 1.1 christos 25 1.1 christos #include "subsegs.h" 26 1.1 christos #include "obstack.h" 27 1.1 christos 28 1.1 christos frchainS *frchain_now; 29 1.1 christos 30 1.1 christos static struct obstack frchains; 31 1.1 christos 32 1.1 christos static fragS dummy_frag; 33 1.1 christos 34 1.1 christos 35 1.1 christos void 37 1.1 christos subsegs_begin (void) 38 1.1 christos { 39 1.1 christos obstack_begin (&frchains, chunksize); 40 1.1 christos #if __GNUC__ >= 2 41 1.1 christos obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1; 42 1.1 christos #endif 43 1.1 christos 44 1.1 christos frchain_now = NULL; /* Warn new_subseg() that we are booting. */ 45 1.1 christos frag_now = &dummy_frag; 46 1.8 christos } 47 1.8 christos 48 1.8 christos void 49 1.8 christos subsegs_end (struct obstack **obs) 50 1.8 christos { 51 1.8 christos for (; *obs; obs++) 52 1.8 christos _obstack_free (*obs, NULL); 53 1.10 christos _obstack_free (&frchains, NULL); 54 1.10 christos bfd_set_section_userdata (bfd_com_section_ptr, NULL); 55 1.9 christos bfd_set_section_userdata (bfd_und_section_ptr, NULL); 56 1.10 christos bfd_set_section_userdata (bfd_abs_section_ptr, NULL); 57 1.10 christos bfd_set_section_userdata (bfd_ind_section_ptr, NULL); 58 1.10 christos /* Reverse bfd_std_section_init, so the sections look as they did 59 1.10 christos initially. This, and clearing out userdata above, is so we don't 60 1.10 christos leave dangling pointers into freed memory for oss-fuzz to mess 61 1.10 christos with. */ 62 1.10 christos asymbol *global_syms = bfd_com_section_ptr->symbol; 63 1.10 christos bfd_und_section_ptr->used_by_bfd = NULL; 64 1.10 christos bfd_und_section_ptr->symbol = global_syms + (bfd_und_section_ptr 65 1.10 christos - bfd_com_section_ptr); 66 1.10 christos bfd_abs_section_ptr->used_by_bfd = NULL; 67 1.10 christos bfd_abs_section_ptr->symbol = global_syms + (bfd_abs_section_ptr 68 1.8 christos - bfd_com_section_ptr); 69 1.1 christos } 70 1.8 christos 71 1.8 christos static void 73 1.8 christos alloc_seginfo (segT seg) 74 1.8 christos { 75 1.8 christos segment_info_type *seginfo; 76 1.8 christos 77 1.8 christos seginfo = obstack_alloc (¬es, sizeof (*seginfo)); 78 1.8 christos memset (seginfo, 0, sizeof (*seginfo)); 79 1.1 christos bfd_set_section_userdata (seg, seginfo); 80 1.1 christos } 81 1.1 christos /* 82 1.1 christos * subseg_change() 83 1.1 christos * 84 1.1 christos * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the 85 1.1 christos * subsegment. If we are already in the correct subsegment, change nothing. 86 1.1 christos * This is used eg as a worker for subseg_set [which does make a new frag_now] 87 1.1 christos * and for changing segments after we have read the source. We construct eg 88 1.1 christos * fixSs even after the source file is read, so we do have to keep the 89 1.1 christos * segment context correct. 90 1.3 christos */ 91 1.1 christos void 92 1.1 christos subseg_change (segT seg, int subseg) 93 1.1 christos { 94 1.1 christos now_seg = seg; 95 1.8 christos now_subseg = subseg; 96 1.8 christos 97 1.1 christos if (!seg_info (seg)) 98 1.1 christos alloc_seginfo (seg); 99 1.1 christos } 100 1.1 christos 101 1.1 christos static void 103 1.1 christos subseg_set_rest (segT seg, subsegT subseg) 104 1.1 christos { 105 1.1 christos frchainS *frcP; /* crawl frchain chain */ 106 1.1 christos frchainS **lastPP; /* address of last pointer */ 107 1.1 christos frchainS *newP; /* address of new frchain */ 108 1.1 christos segment_info_type *seginfo; 109 1.1 christos 110 1.1 christos mri_common_symbol = NULL; 111 1.1 christos 112 1.1 christos if (frag_now && frchain_now) 113 1.1 christos frchain_now->frch_frag_now = frag_now; 114 1.1 christos 115 1.1 christos gas_assert (frchain_now == 0 116 1.1 christos || frchain_now->frch_last == frag_now); 117 1.1 christos 118 1.1 christos subseg_change (seg, (int) subseg); 119 1.8 christos 120 1.8 christos seginfo = seg_info (seg); 121 1.8 christos 122 1.8 christos /* Should the section symbol be kept? */ 123 1.1 christos if (bfd_keep_unused_section_symbols (stdoutput)) 124 1.1 christos seg->symbol->flags |= BSF_SECTION_SYM_USED; 125 1.1 christos 126 1.1 christos /* Attempt to find or make a frchain for that subsection. 127 1.1 christos We keep the list sorted by subsection number. */ 128 1.1 christos for (frcP = *(lastPP = &seginfo->frchainP); 129 1.1 christos frcP != NULL; 130 1.1 christos frcP = *(lastPP = &frcP->frch_next)) 131 1.1 christos if (frcP->frch_subseg >= subseg) 132 1.1 christos break; 133 1.1 christos 134 1.1 christos if (frcP == NULL || frcP->frch_subseg != subseg) 135 1.10 christos { 136 1.1 christos /* This should be the only code that creates a frchainS. */ 137 1.1 christos 138 1.1 christos newP = obstack_alloc (&frchains, sizeof (frchainS)); 139 1.1 christos newP->frch_subseg = subseg; 140 1.1 christos newP->fix_root = NULL; 141 1.1 christos newP->fix_tail = NULL; 142 1.1 christos obstack_begin (&newP->frch_obstack, chunksize); 143 1.10 christos #if __GNUC__ >= 2 144 1.1 christos obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1; 145 1.1 christos #endif 146 1.9 christos newP->frch_frag_now = frag_alloc (&newP->frch_obstack, 0); 147 1.1 christos newP->frch_frag_now->fr_type = rs_fill; 148 1.1 christos newP->frch_cfi_data = NULL; 149 1.1 christos newP->frch_ginsn_data = NULL; 150 1.1 christos 151 1.1 christos newP->frch_root = newP->frch_last = newP->frch_frag_now; 152 1.1 christos 153 1.1 christos *lastPP = newP; 154 1.1 christos newP->frch_next = frcP; 155 1.1 christos frcP = newP; 156 1.1 christos } 157 1.1 christos 158 1.1 christos frchain_now = frcP; 159 1.1 christos frag_now = frcP->frch_frag_now; 160 1.1 christos 161 1.1 christos gas_assert (frchain_now->frch_last == frag_now); 162 1.1 christos } 163 1.1 christos 164 1.1 christos /* 165 1.1 christos * subseg_set(segT, subsegT) 166 1.1 christos * 167 1.1 christos * If you attempt to change to the current subsegment, nothing happens. 168 1.1 christos * 169 1.1 christos * In: segT, subsegT code for new subsegment. 170 1.1 christos * frag_now -> incomplete frag for current subsegment. 171 1.1 christos * If frag_now==NULL, then there is no old, incomplete frag, so 172 1.1 christos * the old frag is not closed off. 173 1.1 christos * 174 1.1 christos * Out: now_subseg, now_seg updated. 175 1.1 christos * Frchain_now points to the (possibly new) struct frchain for this 176 1.1 christos * sub-segment. 177 1.1 christos */ 178 1.1 christos 179 1.1 christos segT 180 1.7 christos subseg_get (const char *segname, int force_new) 181 1.1 christos { 182 1.1 christos segT secptr; 183 1.1 christos const char *now_seg_name = now_seg ? bfd_section_name (now_seg) : 0; 184 1.1 christos 185 1.1 christos if (!force_new 186 1.1 christos && now_seg_name 187 1.1 christos && (now_seg_name == segname 188 1.1 christos || !strcmp (now_seg_name, segname))) 189 1.1 christos return now_seg; 190 1.1 christos 191 1.1 christos if (!force_new) 192 1.1 christos secptr = bfd_make_section_old_way (stdoutput, segname); 193 1.8 christos else 194 1.1 christos secptr = bfd_make_section_anyway (stdoutput, segname); 195 1.1 christos 196 1.8 christos if (!seg_info (secptr)) 197 1.1 christos { 198 1.1 christos secptr->output_section = secptr; 199 1.1 christos alloc_seginfo (secptr); 200 1.1 christos } 201 1.1 christos return secptr; 202 1.1 christos } 203 1.1 christos 204 1.1 christos segT 205 1.1 christos subseg_new (const char *segname, subsegT subseg) 206 1.1 christos { 207 1.1 christos segT secptr; 208 1.1 christos 209 1.1 christos secptr = subseg_get (segname, 0); 210 1.1 christos subseg_set_rest (secptr, subseg); 211 1.1 christos return secptr; 212 1.1 christos } 213 1.1 christos 214 1.1 christos /* Like subseg_new, except a new section is always created, even if 215 1.1 christos a section with that name already exists. */ 216 1.1 christos segT 217 1.1 christos subseg_force_new (const char *segname, subsegT subseg) 218 1.1 christos { 219 1.1 christos segT secptr; 220 1.1 christos 221 1.1 christos secptr = subseg_get (segname, 1); 222 1.1 christos subseg_set_rest (secptr, subseg); 223 1.1 christos return secptr; 224 1.1 christos } 225 1.1 christos 226 1.1 christos void 227 1.1 christos subseg_set (segT secptr, subsegT subseg) 228 1.1 christos { 229 1.1 christos if (! (secptr == now_seg && subseg == now_subseg)) 230 1.1 christos subseg_set_rest (secptr, subseg); 231 1.1 christos mri_common_symbol = NULL; 232 1.1 christos } 233 1.1 christos 234 1.1 christos #ifndef obj_sec_sym_ok_for_reloc 235 1.1 christos #define obj_sec_sym_ok_for_reloc(SEC) 0 236 1.1 christos #endif 237 1.1 christos 238 1.1 christos symbolS * 239 1.1 christos section_symbol (segT sec) 240 1.1 christos { 241 1.1 christos segment_info_type *seginfo = seg_info (sec); 242 1.1 christos symbolS *s; 243 1.1 christos 244 1.1 christos if (seginfo == 0) 245 1.1 christos abort (); 246 1.1 christos if (seginfo->sym) 247 1.1 christos return seginfo->sym; 248 1.1 christos 249 1.1 christos #ifndef EMIT_SECTION_SYMBOLS 250 1.1 christos #define EMIT_SECTION_SYMBOLS 1 251 1.1 christos #endif 252 1.1 christos 253 1.8 christos if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen) 254 1.1 christos { 255 1.1 christos /* Here we know it won't be going into the symbol table. */ 256 1.1 christos s = symbol_create (sec->symbol->name, sec, &zero_address_frag, 0); 257 1.1 christos } 258 1.1 christos else 259 1.1 christos { 260 1.1 christos segT seg; 261 1.1 christos s = symbol_find (sec->symbol->name); 262 1.1 christos /* We have to make sure it is the right symbol when we 263 1.1 christos have multiple sections with the same section name. */ 264 1.8 christos if (s == NULL 265 1.1 christos || ((seg = S_GET_SEGMENT (s)) != sec 266 1.1 christos && seg != undefined_section)) 267 1.1 christos s = symbol_new (sec->symbol->name, sec, &zero_address_frag, 0); 268 1.1 christos else if (seg == undefined_section) 269 1.1 christos { 270 1.1 christos S_SET_SEGMENT (s, sec); 271 1.1 christos symbol_set_frag (s, &zero_address_frag); 272 1.1 christos } 273 1.1 christos } 274 1.1 christos 275 1.1 christos S_CLEAR_EXTERNAL (s); 276 1.1 christos 277 1.1 christos /* Use the BFD section symbol, if possible. */ 278 1.1 christos if (obj_sec_sym_ok_for_reloc (sec)) 279 1.1 christos symbol_set_bfdsym (s, sec->symbol); 280 1.1 christos else 281 1.1 christos symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM; 282 1.1 christos 283 1.1 christos seginfo->sym = s; 284 1.1 christos return s; 285 1.1 christos } 286 1.1 christos 287 1.1 christos /* Return whether the specified segment is thought to hold text. */ 288 1.1 christos 289 1.7 christos int 290 1.1 christos subseg_text_p (segT sec) 291 1.1 christos { 292 1.1 christos return (bfd_section_flags (sec) & SEC_CODE) != 0; 293 1.1 christos } 294 1.1 christos 295 1.1 christos /* Return non zero if SEC has at least one byte of data. It is 296 1.1 christos possible that we'll return zero even on a non-empty section because 297 1.1 christos we don't know all the fragment types, and it is possible that an 298 1.1 christos fr_fix == 0 one still contributes data. Think of this as 299 1.1 christos seg_definitely_not_empty_p. */ 300 1.1 christos 301 1.1 christos int 302 1.1 christos seg_not_empty_p (segT sec ATTRIBUTE_UNUSED) 303 1.1 christos { 304 1.1 christos segment_info_type *seginfo = seg_info (sec); 305 1.1 christos frchainS *chain; 306 1.1 christos fragS *frag; 307 1.3 christos 308 1.1 christos if (!seginfo) 309 1.1 christos return 0; 310 1.1 christos 311 1.1 christos for (chain = seginfo->frchainP; chain; chain = chain->frch_next) 312 1.1 christos { 313 1.1 christos for (frag = chain->frch_root; frag; frag = frag->fr_next) 314 1.1 christos if (frag->fr_fix) 315 1.1 christos return 1; 316 1.1 christos if (obstack_next_free (&chain->frch_obstack) 317 1.1 christos != chain->frch_last->fr_literal) 318 1.1 christos return 1; 319 1.1 christos } 320 1.1 christos return 0; 321 1.1 christos } 322 1.1 christos 323 1.1 christos void 324 1.1 christos subsegs_print_statistics (FILE *file) 325 1.1 christos { 326 1.6 christos frchainS *frchp; 327 1.6 christos asection *s; 328 1.6 christos 329 1.6 christos /* PR 20897 - check to see if the output bfd was actually created. */ 330 1.1 christos if (stdoutput == NULL) 331 1.1 christos return; 332 1.1 christos 333 1.1 christos fprintf (file, "frag chains:\n"); 334 1.1 christos for (s = stdoutput->sections; s; s = s->next) 335 1.1 christos { 336 1.1 christos segment_info_type *seginfo; 337 1.1 christos 338 1.1 christos /* Skip gas-internal sections. */ 339 1.1 christos if (segment_name (s)[0] == '*') 340 1.1 christos continue; 341 1.1 christos 342 1.1 christos seginfo = seg_info (s); 343 1.1 christos if (!seginfo) 344 1.1 christos continue; 345 1.1 christos 346 1.1 christos for (frchp = seginfo->frchainP; frchp; frchp = frchp->frch_next) 347 1.1 christos { 348 1.1 christos int count = 0; 349 1.1 christos fragS *fragp; 350 1.1 christos 351 1.1 christos for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next) 352 1.1 christos count++; 353 1.1 christos 354 1.1 christos fprintf (file, "\n"); 355 1.1 christos fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp, 356 1.1 christos segment_name (s), count); 357 1.1 christos } 358 1.1 christos } 359 } 360 361 /* end of subsegs.c */ 362