1 /* subsegs.c - subsegments - 2 Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 3 1999, 2000, 2002 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, 59 Temple Place - Suite 330, Boston, MA 21 02111-1307, 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 #ifndef BFD_ASSEMBLER 35 #ifdef MANY_SEGMENTS 36 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL]; 37 38 #else 39 /* Commented in "subsegs.h". */ 40 frchainS *data0_frchainP, *bss0_frchainP; 41 42 #endif /* MANY_SEGMENTS */ 43 char const *const seg_name[] = { 44 "absolute", 45 #ifdef MANY_SEGMENTS 46 "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", 47 "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19", 48 "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29", 49 "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39", 50 #else 51 "text", 52 "data", 53 "bss", 54 #endif /* MANY_SEGMENTS */ 55 "unknown", 56 "ASSEMBLER-INTERNAL-LOGIC-ERROR!", 57 "expr", 58 "debug", 59 "transfert vector preload", 60 "transfert vector postload", 61 "register", 62 "", 63 }; /* Used by error reporters, dumpers etc. */ 64 #else /* BFD_ASSEMBLER */ 65 66 /* Gas segment information for bfd_abs_section_ptr and 67 bfd_und_section_ptr. */ 68 static segment_info_type *abs_seg_info; 69 static segment_info_type *und_seg_info; 70 71 #endif /* BFD_ASSEMBLER */ 72 73 static void subseg_set_rest (segT, subsegT); 74 75 static fragS dummy_frag; 76 77 static frchainS absolute_frchain; 78 79 void 80 subsegs_begin (void) 81 { 82 /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ 83 #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) 84 know (SEG_ABSOLUTE == 0); 85 know (SEG_TEXT == 1); 86 know (SEG_DATA == 2); 87 know (SEG_BSS == 3); 88 know (SEG_UNKNOWN == 4); 89 know (SEG_GOOF == 5); 90 know (SEG_EXPR == 6); 91 know (SEG_DEBUG == 7); 92 know (SEG_NTV == 8); 93 know (SEG_PTV == 9); 94 know (SEG_REGISTER == 10); 95 know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER); 96 #endif 97 98 obstack_begin (&frchains, chunksize); 99 #if __GNUC__ >= 2 100 obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1; 101 #endif 102 103 frchain_root = NULL; 104 frchain_now = NULL; /* Warn new_subseg() that we are booting. */ 105 106 frag_now = &dummy_frag; 107 108 #ifndef BFD_ASSEMBLER 109 now_subseg = 42; /* Lie for 1st call to subseg_new. */ 110 #ifdef MANY_SEGMENTS 111 { 112 int i; 113 for (i = SEG_E0; i < SEG_UNKNOWN; i++) 114 { 115 subseg_set (i, 0); 116 segment_info[i].frchainP = frchain_now; 117 } 118 } 119 #else 120 subseg_set (SEG_DATA, 0); /* .data 0 */ 121 data0_frchainP = frchain_now; 122 123 subseg_set (SEG_BSS, 0); 124 bss0_frchainP = frchain_now; 125 126 #endif /* ! MANY_SEGMENTS */ 127 #endif /* ! BFD_ASSEMBLER */ 128 129 absolute_frchain.frch_seg = absolute_section; 130 absolute_frchain.frch_subseg = 0; 131 #ifdef BFD_ASSEMBLER 132 absolute_frchain.fix_root = absolute_frchain.fix_tail = 0; 133 #endif 134 absolute_frchain.frch_frag_now = &zero_address_frag; 135 absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag; 136 } 137 138 /* 139 * subseg_change() 140 * 141 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the 142 * subsegment. If we are already in the correct subsegment, change nothing. 143 * This is used eg as a worker for subseg_set [which does make a new frag_now] 144 * and for changing segments after we have read the source. We construct eg 145 * fixSs even after the source file is read, so we do have to keep the 146 * segment context correct. 147 */ 148 void 149 subseg_change (register segT seg, register int subseg) 150 { 151 now_seg = seg; 152 now_subseg = subseg; 153 154 if (now_seg == absolute_section) 155 return; 156 157 #ifdef BFD_ASSEMBLER 158 { 159 segment_info_type *seginfo; 160 seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg); 161 if (! seginfo) 162 { 163 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); 164 memset ((PTR) seginfo, 0, sizeof (*seginfo)); 165 seginfo->fix_root = NULL; 166 seginfo->fix_tail = NULL; 167 seginfo->bfd_section = seg; 168 seginfo->sym = 0; 169 if (seg == bfd_abs_section_ptr) 170 abs_seg_info = seginfo; 171 else if (seg == bfd_und_section_ptr) 172 und_seg_info = seginfo; 173 else 174 bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo); 175 } 176 } 177 #else 178 #ifdef MANY_SEGMENTS 179 seg_fix_rootP = &segment_info[seg].fix_root; 180 seg_fix_tailP = &segment_info[seg].fix_tail; 181 #else 182 if (seg == SEG_DATA) 183 { 184 seg_fix_rootP = &data_fix_root; 185 seg_fix_tailP = &data_fix_tail; 186 } 187 else if (seg == SEG_TEXT) 188 { 189 seg_fix_rootP = &text_fix_root; 190 seg_fix_tailP = &text_fix_tail; 191 } 192 else 193 { 194 know (seg == SEG_BSS); 195 seg_fix_rootP = &bss_fix_root; 196 seg_fix_tailP = &bss_fix_tail; 197 } 198 199 #endif 200 #endif 201 } 202 203 static void 204 subseg_set_rest (segT seg, subsegT subseg) 205 { 206 register frchainS *frcP; /* crawl frchain chain */ 207 register frchainS **lastPP; /* address of last pointer */ 208 frchainS *newP; /* address of new frchain */ 209 210 mri_common_symbol = NULL; 211 212 if (frag_now && frchain_now) 213 frchain_now->frch_frag_now = frag_now; 214 215 assert (frchain_now == 0 216 || now_seg == undefined_section 217 || now_seg == absolute_section 218 || frchain_now->frch_last == frag_now); 219 220 subseg_change (seg, (int) subseg); 221 222 if (seg == absolute_section) 223 { 224 frchain_now = &absolute_frchain; 225 frag_now = &zero_address_frag; 226 return; 227 } 228 229 assert (frchain_now == 0 230 || now_seg == undefined_section 231 || frchain_now->frch_last == frag_now); 232 233 /* 234 * Attempt to find or make a frchain for that sub seg. 235 * Crawl along chain of frchainSs, begins @ frchain_root. 236 * If we need to make a frchainS, link it into correct 237 * position of chain rooted in frchain_root. 238 */ 239 for (frcP = *(lastPP = &frchain_root); 240 frcP && frcP->frch_seg <= seg; 241 frcP = *(lastPP = &frcP->frch_next)) 242 { 243 if (frcP->frch_seg == seg 244 && frcP->frch_subseg >= subseg) 245 { 246 break; 247 } 248 } 249 /* 250 * frcP: Address of the 1st frchainS in correct segment with 251 * frch_subseg >= subseg. 252 * We want to either use this frchainS, or we want 253 * to insert a new frchainS just before it. 254 * 255 * If frcP==NULL, then we are at the end of the chain 256 * of frchainS-s. A NULL frcP means we fell off the end 257 * of the chain looking for a 258 * frch_subseg >= subseg, so we 259 * must make a new frchainS. 260 * 261 * If we ever maintain a pointer to 262 * the last frchainS in the chain, we change that pointer 263 * ONLY when frcP==NULL. 264 * 265 * lastPP: Address of the pointer with value frcP; 266 * Never NULL. 267 * May point to frchain_root. 268 * 269 */ 270 if (!frcP 271 || (frcP->frch_seg > seg 272 || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ 273 { 274 /* 275 * This should be the only code that creates a frchainS. 276 */ 277 newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS)); 278 newP->frch_subseg = subseg; 279 newP->frch_seg = seg; 280 #ifdef BFD_ASSEMBLER 281 newP->fix_root = NULL; 282 newP->fix_tail = NULL; 283 #endif 284 obstack_begin (&newP->frch_obstack, chunksize); 285 #if __GNUC__ >= 2 286 obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1; 287 #endif 288 newP->frch_frag_now = frag_alloc (&newP->frch_obstack); 289 newP->frch_frag_now->fr_type = rs_fill; 290 291 newP->frch_root = newP->frch_last = newP->frch_frag_now; 292 293 *lastPP = newP; 294 newP->frch_next = frcP; /* perhaps NULL */ 295 296 #ifdef BFD_ASSEMBLER 297 { 298 segment_info_type *seginfo; 299 seginfo = seg_info (seg); 300 if (seginfo && seginfo->frchainP == frcP) 301 seginfo->frchainP = newP; 302 } 303 #endif 304 305 frcP = newP; 306 } 307 /* 308 * Here with frcP pointing to the frchainS for subseg. 309 */ 310 frchain_now = frcP; 311 frag_now = frcP->frch_frag_now; 312 313 assert (frchain_now->frch_last == frag_now); 314 } 315 316 /* 317 * subseg_set(segT, subsegT) 318 * 319 * If you attempt to change to the current subsegment, nothing happens. 320 * 321 * In: segT, subsegT code for new subsegment. 322 * frag_now -> incomplete frag for current subsegment. 323 * If frag_now==NULL, then there is no old, incomplete frag, so 324 * the old frag is not closed off. 325 * 326 * Out: now_subseg, now_seg updated. 327 * Frchain_now points to the (possibly new) struct frchain for this 328 * sub-segment. 329 * Frchain_root updated if needed. 330 */ 331 332 #ifndef BFD_ASSEMBLER 333 334 segT 335 subseg_new (segname, subseg) 336 const char *segname; 337 subsegT subseg; 338 { 339 int i; 340 341 for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++) 342 { 343 const char *s; 344 345 s = segment_name ((segT) i); 346 if (strcmp (segname, s) == 0 347 || (segname[0] == '.' 348 && strcmp (segname + 1, s) == 0)) 349 { 350 subseg_set ((segT) i, subseg); 351 return (segT) i; 352 } 353 #ifdef obj_segment_name 354 s = obj_segment_name ((segT) i); 355 if (strcmp (segname, s) == 0 356 || (segname[0] == '.' 357 && strcmp (segname + 1, s) == 0)) 358 { 359 subseg_set ((segT) i, subseg); 360 return (segT) i; 361 } 362 #endif 363 } 364 365 #ifdef obj_add_segment 366 { 367 segT new_seg; 368 new_seg = obj_add_segment (segname); 369 subseg_set (new_seg, subseg); 370 return new_seg; 371 } 372 #else 373 as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname); 374 return now_seg; 375 #endif 376 } 377 378 void 379 subseg_set (seg, subseg) /* begin assembly for a new sub-segment */ 380 register segT seg; /* SEG_DATA or SEG_TEXT */ 381 register subsegT subseg; 382 { 383 #ifndef MANY_SEGMENTS 384 know (seg == SEG_DATA 385 || seg == SEG_TEXT 386 || seg == SEG_BSS 387 || seg == SEG_ABSOLUTE); 388 #endif 389 390 if (seg != now_seg || subseg != now_subseg) 391 { /* we just changed sub-segments */ 392 subseg_set_rest (seg, subseg); 393 } 394 mri_common_symbol = NULL; 395 } 396 397 #else /* BFD_ASSEMBLER */ 398 399 segT 400 subseg_get (const char *segname, int force_new) 401 { 402 segT secptr; 403 segment_info_type *seginfo; 404 const char *now_seg_name = (now_seg 405 ? bfd_get_section_name (stdoutput, now_seg) 406 : 0); 407 408 if (!force_new 409 && now_seg_name 410 && (now_seg_name == segname 411 || !strcmp (now_seg_name, segname))) 412 return now_seg; 413 414 if (!force_new) 415 secptr = bfd_make_section_old_way (stdoutput, segname); 416 else 417 secptr = bfd_make_section_anyway (stdoutput, segname); 418 419 #ifdef obj_sec_set_private_data 420 obj_sec_set_private_data (stdoutput, secptr); 421 #endif 422 423 seginfo = seg_info (secptr); 424 if (! seginfo) 425 { 426 /* Check whether output_section is set first because secptr may 427 be bfd_abs_section_ptr. */ 428 if (secptr->output_section != secptr) 429 secptr->output_section = secptr; 430 seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); 431 memset ((PTR) seginfo, 0, sizeof (*seginfo)); 432 seginfo->fix_root = NULL; 433 seginfo->fix_tail = NULL; 434 seginfo->bfd_section = secptr; 435 if (secptr == bfd_abs_section_ptr) 436 abs_seg_info = seginfo; 437 else if (secptr == bfd_und_section_ptr) 438 und_seg_info = seginfo; 439 else 440 bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo); 441 seginfo->frchainP = NULL; 442 seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL; 443 seginfo->sym = NULL; 444 seginfo->dot = NULL; 445 } 446 return secptr; 447 } 448 449 segT 450 subseg_new (const char *segname, subsegT subseg) 451 { 452 segT secptr; 453 segment_info_type *seginfo; 454 455 secptr = subseg_get (segname, 0); 456 subseg_set_rest (secptr, subseg); 457 seginfo = seg_info (secptr); 458 if (! seginfo->frchainP) 459 seginfo->frchainP = frchain_now; 460 return secptr; 461 } 462 463 /* Like subseg_new, except a new section is always created, even if 464 a section with that name already exists. */ 465 segT 466 subseg_force_new (const char *segname, subsegT subseg) 467 { 468 segT secptr; 469 segment_info_type *seginfo; 470 471 secptr = subseg_get (segname, 1); 472 subseg_set_rest (secptr, subseg); 473 seginfo = seg_info (secptr); 474 if (! seginfo->frchainP) 475 seginfo->frchainP = frchain_now; 476 return secptr; 477 } 478 479 void 480 subseg_set (segT secptr, subsegT subseg) 481 { 482 if (! (secptr == now_seg && subseg == now_subseg)) 483 subseg_set_rest (secptr, subseg); 484 mri_common_symbol = NULL; 485 } 486 487 #ifndef obj_sec_sym_ok_for_reloc 488 #define obj_sec_sym_ok_for_reloc(SEC) 0 489 #endif 490 491 /* Get the gas information we are storing for a section. */ 492 493 segment_info_type * 494 seg_info (segT sec) 495 { 496 if (sec == bfd_abs_section_ptr) 497 return abs_seg_info; 498 else if (sec == bfd_und_section_ptr) 499 return und_seg_info; 500 else 501 return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec); 502 } 503 504 symbolS * 505 section_symbol (segT sec) 506 { 507 segment_info_type *seginfo = seg_info (sec); 508 symbolS *s; 509 510 if (seginfo == 0) 511 abort (); 512 if (seginfo->sym) 513 return seginfo->sym; 514 515 #ifndef EMIT_SECTION_SYMBOLS 516 #define EMIT_SECTION_SYMBOLS 1 517 #endif 518 519 if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen) 520 { 521 /* Here we know it won't be going into the symbol table. */ 522 s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag); 523 } 524 else 525 { 526 s = symbol_find_base (sec->symbol->name, 0); 527 if (s == NULL) 528 s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag); 529 else 530 { 531 if (S_GET_SEGMENT (s) == undefined_section) 532 { 533 S_SET_SEGMENT (s, sec); 534 symbol_set_frag (s, &zero_address_frag); 535 } 536 } 537 } 538 539 S_CLEAR_EXTERNAL (s); 540 541 /* Use the BFD section symbol, if possible. */ 542 if (obj_sec_sym_ok_for_reloc (sec)) 543 symbol_set_bfdsym (s, sec->symbol); 544 else 545 symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM; 546 547 seginfo->sym = s; 548 return s; 549 } 550 551 #endif /* BFD_ASSEMBLER */ 552 553 /* Return whether the specified segment is thought to hold text. */ 554 555 #ifndef BFD_ASSEMBLER 556 const char * const nontext_section_names[] = { 557 ".eh_frame", 558 ".gcc_except_table", 559 #ifdef OBJ_COFF 560 #ifndef COFF_LONG_SECTION_NAMES 561 ".eh_fram", 562 ".gcc_exc", 563 #endif 564 #endif 565 NULL 566 }; 567 #endif /* ! BFD_ASSEMBLER */ 568 569 int 570 subseg_text_p (segT sec) 571 { 572 #ifdef BFD_ASSEMBLER 573 return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0; 574 #else /* ! BFD_ASSEMBLER */ 575 const char * const *p; 576 577 if (sec == data_section || sec == bss_section || sec == absolute_section) 578 return 0; 579 580 for (p = nontext_section_names; *p != NULL; ++p) 581 { 582 if (strcmp (segment_name (sec), *p) == 0) 583 return 0; 584 585 #ifdef obj_segment_name 586 if (strcmp (obj_segment_name (sec), *p) == 0) 587 return 0; 588 #endif 589 } 590 591 return 1; 592 593 #endif /* ! BFD_ASSEMBLER */ 594 } 595 596 void 597 subsegs_print_statistics (FILE *file) 598 { 599 frchainS *frchp; 600 fprintf (file, "frag chains:\n"); 601 for (frchp = frchain_root; frchp; frchp = frchp->frch_next) 602 { 603 int count = 0; 604 fragS *fragp; 605 606 /* If frch_subseg is non-zero, it's probably been chained onto 607 the end of a previous subsection. Don't count it again. */ 608 if (frchp->frch_subseg != 0) 609 continue; 610 611 /* Skip gas-internal sections. */ 612 if (segment_name (frchp->frch_seg)[0] == '*') 613 continue; 614 615 for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next) 616 { 617 #if 0 618 switch (fragp->fr_type) 619 { 620 case rs_fill: 621 fprintf (file, "f"); break; 622 case rs_align: 623 fprintf (file, "a"); break; 624 case rs_align_code: 625 fprintf (file, "c"); break; 626 case rs_org: 627 fprintf (file, "o"); break; 628 case rs_machine_dependent: 629 fprintf (file, "m"); break; 630 case rs_space: 631 fprintf (file, "s"); break; 632 case 0: 633 fprintf (file, "0"); break; 634 default: 635 fprintf (file, "?"); break; 636 } 637 #endif 638 count++; 639 } 640 fprintf (file, "\n"); 641 fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp, 642 segment_name (frchp->frch_seg), count); 643 } 644 } 645 646 /* end of subsegs.c */ 647