1 /* subsegs.c - subsegments - 2 Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3 1999, 2000, 2001, 2002, 2003, 2004, 2005 4 Free Software Foundation, Inc. 5 6 This file is part of GAS, the GNU Assembler. 7 8 GAS is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2, or (at your option) 11 any later version. 12 13 GAS is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GAS; see the file COPYING. If not, write to the Free 20 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 21 02110-1301, USA. */ 22 23 /* Segments & sub-segments. */ 24 25 #include "as.h" 26 27 #include "subsegs.h" 28 #include "obstack.h" 29 30 frchainS *frchain_root, *frchain_now; 31 32 static struct obstack frchains; 33 34 /* Gas segment information for bfd_abs_section_ptr and 35 bfd_und_section_ptr. */ 36 static segment_info_type *abs_seg_info; 37 static segment_info_type *und_seg_info; 38 39 static void subseg_set_rest (segT, subsegT); 40 41 static fragS dummy_frag; 42 43 static frchainS absolute_frchain; 44 45 void 46 subsegs_begin (void) 47 { 48 obstack_begin (&frchains, chunksize); 49 #if __GNUC__ >= 2 50 obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1; 51 #endif 52 53 frchain_root = NULL; 54 frchain_now = NULL; /* Warn new_subseg() that we are booting. */ 55 56 frag_now = &dummy_frag; 57 58 absolute_frchain.frch_seg = absolute_section; 59 absolute_frchain.frch_subseg = 0; 60 absolute_frchain.fix_root = absolute_frchain.fix_tail = 0; 61 absolute_frchain.frch_frag_now = &zero_address_frag; 62 absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag; 63 } 64 65 /* 66 * subseg_change() 67 * 68 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the 69 * subsegment. If we are already in the correct subsegment, change nothing. 70 * This is used eg as a worker for subseg_set [which does make a new frag_now] 71 * and for changing segments after we have read the source. We construct eg 72 * fixSs even after the source file is read, so we do have to keep the 73 * segment context correct. 74 */ 75 void 76 subseg_change (register segT seg, register int subseg) 77 { 78 segment_info_type *seginfo; 79 now_seg = seg; 80 now_subseg = subseg; 81 82 if (now_seg == absolute_section) 83 return; 84 85 seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg); 86 if (! seginfo) 87 { 88 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); 89 memset ((PTR) seginfo, 0, sizeof (*seginfo)); 90 seginfo->fix_root = NULL; 91 seginfo->fix_tail = NULL; 92 seginfo->bfd_section = seg; 93 seginfo->sym = 0; 94 if (seg == bfd_abs_section_ptr) 95 abs_seg_info = seginfo; 96 else if (seg == bfd_und_section_ptr) 97 und_seg_info = seginfo; 98 else 99 bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo); 100 } 101 } 102 103 static void 104 subseg_set_rest (segT seg, subsegT subseg) 105 { 106 register frchainS *frcP; /* crawl frchain chain */ 107 register frchainS **lastPP; /* address of last pointer */ 108 frchainS *newP; /* address of new frchain */ 109 110 mri_common_symbol = NULL; 111 112 if (frag_now && frchain_now) 113 frchain_now->frch_frag_now = frag_now; 114 115 assert (frchain_now == 0 116 || now_seg == undefined_section 117 || now_seg == absolute_section 118 || frchain_now->frch_last == frag_now); 119 120 subseg_change (seg, (int) subseg); 121 122 if (seg == absolute_section) 123 { 124 frchain_now = &absolute_frchain; 125 frag_now = &zero_address_frag; 126 return; 127 } 128 129 assert (frchain_now == 0 130 || now_seg == undefined_section 131 || frchain_now->frch_last == frag_now); 132 133 /* 134 * Attempt to find or make a frchain for that sub seg. 135 * Crawl along chain of frchainSs, begins @ frchain_root. 136 * If we need to make a frchainS, link it into correct 137 * position of chain rooted in frchain_root. 138 */ 139 for (frcP = *(lastPP = &frchain_root); 140 frcP && frcP->frch_seg <= seg; 141 frcP = *(lastPP = &frcP->frch_next)) 142 { 143 if (frcP->frch_seg == seg 144 && frcP->frch_subseg >= subseg) 145 { 146 break; 147 } 148 } 149 /* 150 * frcP: Address of the 1st frchainS in correct segment with 151 * frch_subseg >= subseg. 152 * We want to either use this frchainS, or we want 153 * to insert a new frchainS just before it. 154 * 155 * If frcP==NULL, then we are at the end of the chain 156 * of frchainS-s. A NULL frcP means we fell off the end 157 * of the chain looking for a 158 * frch_subseg >= subseg, so we 159 * must make a new frchainS. 160 * 161 * If we ever maintain a pointer to 162 * the last frchainS in the chain, we change that pointer 163 * ONLY when frcP==NULL. 164 * 165 * lastPP: Address of the pointer with value frcP; 166 * Never NULL. 167 * May point to frchain_root. 168 * 169 */ 170 if (!frcP 171 || (frcP->frch_seg > seg 172 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ 173 { 174 /* 175 * This should be the only code that creates a frchainS. 176 */ 177 segment_info_type *seginfo; 178 179 newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS)); 180 newP->frch_subseg = subseg; 181 newP->frch_seg = seg; 182 newP->fix_root = NULL; 183 newP->fix_tail = NULL; 184 obstack_begin (&newP->frch_obstack, chunksize); 185 #if __GNUC__ >= 2 186 obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1; 187 #endif 188 newP->frch_frag_now = frag_alloc (&newP->frch_obstack); 189 newP->frch_frag_now->fr_type = rs_fill; 190 191 newP->frch_root = newP->frch_last = newP->frch_frag_now; 192 193 *lastPP = newP; 194 newP->frch_next = frcP; /* perhaps NULL */ 195 196 seginfo = seg_info (seg); 197 if (seginfo && (!seginfo->frchainP || seginfo->frchainP == frcP)) 198 seginfo->frchainP = newP; 199 200 frcP = newP; 201 } 202 /* 203 * Here with frcP pointing to the frchainS for subseg. 204 */ 205 frchain_now = frcP; 206 frag_now = frcP->frch_frag_now; 207 208 assert (frchain_now->frch_last == frag_now); 209 } 210 211 /* 212 * subseg_set(segT, subsegT) 213 * 214 * If you attempt to change to the current subsegment, nothing happens. 215 * 216 * In: segT, subsegT code for new subsegment. 217 * frag_now -> incomplete frag for current subsegment. 218 * If frag_now==NULL, then there is no old, incomplete frag, so 219 * the old frag is not closed off. 220 * 221 * Out: now_subseg, now_seg updated. 222 * Frchain_now points to the (possibly new) struct frchain for this 223 * sub-segment. 224 * Frchain_root updated if needed. 225 */ 226 227 segT 228 subseg_get (const char *segname, int force_new) 229 { 230 segT secptr; 231 segment_info_type *seginfo; 232 const char *now_seg_name = (now_seg 233 ? bfd_get_section_name (stdoutput, now_seg) 234 : 0); 235 236 if (!force_new 237 && now_seg_name 238 && (now_seg_name == segname 239 || !strcmp (now_seg_name, segname))) 240 return now_seg; 241 242 if (!force_new) 243 secptr = bfd_make_section_old_way (stdoutput, segname); 244 else 245 secptr = bfd_make_section_anyway (stdoutput, segname); 246 247 #ifdef obj_sec_set_private_data 248 obj_sec_set_private_data (stdoutput, secptr); 249 #endif 250 251 seginfo = seg_info (secptr); 252 if (! seginfo) 253 { 254 /* Check whether output_section is set first because secptr may 255 be bfd_abs_section_ptr. */ 256 if (secptr->output_section != secptr) 257 secptr->output_section = secptr; 258 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); 259 memset ((PTR) seginfo, 0, sizeof (*seginfo)); 260 seginfo->fix_root = NULL; 261 seginfo->fix_tail = NULL; 262 seginfo->bfd_section = secptr; 263 if (secptr == bfd_abs_section_ptr) 264 abs_seg_info = seginfo; 265 else if (secptr == bfd_und_section_ptr) 266 und_seg_info = seginfo; 267 else 268 bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo); 269 seginfo->frchainP = NULL; 270 seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL; 271 seginfo->sym = NULL; 272 seginfo->dot = NULL; 273 } 274 return secptr; 275 } 276 277 segT 278 subseg_new (const char *segname, subsegT subseg) 279 { 280 segT secptr; 281 segment_info_type *seginfo; 282 283 secptr = subseg_get (segname, 0); 284 subseg_set_rest (secptr, subseg); 285 seginfo = seg_info (secptr); 286 if (! seginfo->frchainP) 287 seginfo->frchainP = frchain_now; 288 return secptr; 289 } 290 291 /* Like subseg_new, except a new section is always created, even if 292 a section with that name already exists. */ 293 segT 294 subseg_force_new (const char *segname, subsegT subseg) 295 { 296 segT secptr; 297 segment_info_type *seginfo; 298 299 secptr = subseg_get (segname, 1); 300 subseg_set_rest (secptr, subseg); 301 seginfo = seg_info (secptr); 302 if (! seginfo->frchainP) 303 seginfo->frchainP = frchain_now; 304 return secptr; 305 } 306 307 void 308 subseg_set (segT secptr, subsegT subseg) 309 { 310 if (! (secptr == now_seg && subseg == now_subseg)) 311 subseg_set_rest (secptr, subseg); 312 mri_common_symbol = NULL; 313 } 314 315 #ifndef obj_sec_sym_ok_for_reloc 316 #define obj_sec_sym_ok_for_reloc(SEC) 0 317 #endif 318 319 /* Get the gas information we are storing for a section. */ 320 321 segment_info_type * 322 seg_info (segT sec) 323 { 324 if (sec == bfd_abs_section_ptr) 325 return abs_seg_info; 326 else if (sec == bfd_und_section_ptr) 327 return und_seg_info; 328 else 329 return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec); 330 } 331 332 symbolS * 333 section_symbol (segT sec) 334 { 335 segment_info_type *seginfo = seg_info (sec); 336 symbolS *s; 337 338 if (seginfo == 0) 339 abort (); 340 if (seginfo->sym) 341 return seginfo->sym; 342 343 #ifndef EMIT_SECTION_SYMBOLS 344 #define EMIT_SECTION_SYMBOLS 1 345 #endif 346 347 if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen) 348 { 349 /* Here we know it won't be going into the symbol table. */ 350 s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag); 351 } 352 else 353 { 354 segT seg; 355 s = symbol_find (sec->symbol->name); 356 /* We have to make sure it is the right symbol when we 357 have multiple sections with the same section name. */ 358 if (s == NULL 359 || ((seg = S_GET_SEGMENT (s)) != sec 360 && seg != undefined_section)) 361 s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag); 362 else if (seg == undefined_section) 363 { 364 S_SET_SEGMENT (s, sec); 365 symbol_set_frag (s, &zero_address_frag); 366 } 367 } 368 369 S_CLEAR_EXTERNAL (s); 370 371 /* Use the BFD section symbol, if possible. */ 372 if (obj_sec_sym_ok_for_reloc (sec)) 373 symbol_set_bfdsym (s, sec->symbol); 374 else 375 symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM; 376 377 seginfo->sym = s; 378 return s; 379 } 380 381 /* Return whether the specified segment is thought to hold text. */ 382 383 int 384 subseg_text_p (segT sec) 385 { 386 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0; 387 } 388 389 /* Return non zero if SEC has at least one byte of data. It is 390 possible that we'll return zero even on a non-empty section because 391 we don't know all the fragment types, and it is possible that an 392 fr_fix == 0 one still contributes data. Think of this as 393 seg_definitely_not_empty_p. */ 394 395 int 396 seg_not_empty_p (segT sec ATTRIBUTE_UNUSED) 397 { 398 segment_info_type *seginfo = seg_info (sec); 399 frchainS *chain; 400 fragS *frag; 401 402 if (!seginfo) 403 return 0; 404 405 for (chain = seginfo->frchainP; chain; chain = chain->frch_next) 406 { 407 for (frag = chain->frch_root; frag; frag = frag->fr_next) 408 if (frag->fr_fix) 409 return 1; 410 if (obstack_next_free (&chain->frch_obstack) 411 != chain->frch_last->fr_literal) 412 return 1; 413 } 414 return 0; 415 } 416 417 void 418 subsegs_print_statistics (FILE *file) 419 { 420 frchainS *frchp; 421 fprintf (file, "frag chains:\n"); 422 for (frchp = frchain_root; frchp; frchp = frchp->frch_next) 423 { 424 int count = 0; 425 fragS *fragp; 426 427 /* If frch_subseg is non-zero, it's probably been chained onto 428 the end of a previous subsection. Don't count it again. */ 429 if (frchp->frch_subseg != 0) 430 continue; 431 432 /* Skip gas-internal sections. */ 433 if (segment_name (frchp->frch_seg)[0] == '*') 434 continue; 435 436 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next) 437 { 438 count++; 439 } 440 fprintf (file, "\n"); 441 fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp, 442 segment_name (frchp->frch_seg), count); 443 } 444 } 445 446 /* end of subsegs.c */ 447