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