]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/binutils/gas/subsegs.c
Initial import of GNU binutils version 2.8.1. Believe it or not,
[FreeBSD/FreeBSD.git] / contrib / binutils / gas / subsegs.c
1 /* subsegs.c - subsegments -
2    Copyright (C) 1987, 90, 91, 92, 93, 94, 95, 96, 1997
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
31 frchainS *frchain_root, *frchain_now;
32
33 static struct obstack frchains;
34
35 #ifndef BFD_ASSEMBLER
36 #ifdef MANY_SEGMENTS
37 segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
38
39 #else
40 /* Commented in "subsegs.h". */
41 frchainS *data0_frchainP, *bss0_frchainP;
42
43 #endif /* MANY_SEGMENTS */
44 char 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.  */
70 static segment_info_type *abs_seg_info;
71 static segment_info_type *und_seg_info;
72
73 #endif /* BFD_ASSEMBLER */
74
75 static void subseg_set_rest PARAMS ((segT, subsegT));
76
77 static fragS dummy_frag;
78
79 static frchainS absolute_frchain;
80 \f
81 void
82 subsegs_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 \f
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  */
150 void
151 subseg_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 \f
207 static void
208 subseg_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       newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
284       newP->frch_subseg = subseg;
285       newP->frch_seg = seg;
286 #ifdef BFD_ASSEMBLER
287       newP->fix_root = NULL;
288       newP->fix_tail = NULL;
289 #endif
290       obstack_begin (&newP->frch_obstack, 5000);
291 #if __GNUC__ >= 2
292       obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
293 #endif
294       newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
295       newP->frch_frag_now->fr_type = rs_fill;
296
297       newP->frch_root = newP->frch_last = newP->frch_frag_now;
298
299       *lastPP = newP;
300       newP->frch_next = frcP;   /* perhaps NULL */
301       frcP = newP;
302     }
303   /*
304    * Here with frcP pointing to the frchainS for subseg.
305    */
306   frchain_now = frcP;
307   frag_now = frcP->frch_frag_now;
308
309   assert (frchain_now->frch_last == frag_now);
310 }
311
312 /*
313  *                      subseg_set(segT, subsegT)
314  *
315  * If you attempt to change to the current subsegment, nothing happens.
316  *
317  * In:  segT, subsegT code for new subsegment.
318  *      frag_now -> incomplete frag for current subsegment.
319  *      If frag_now==NULL, then there is no old, incomplete frag, so
320  *      the old frag is not closed off.
321  *
322  * Out: now_subseg, now_seg updated.
323  *      Frchain_now points to the (possibly new) struct frchain for this
324  *      sub-segment.
325  *      Frchain_root updated if needed.
326  */
327
328 #ifndef BFD_ASSEMBLER
329
330 segT
331 subseg_new (segname, subseg)
332      const char *segname;
333      subsegT subseg;
334 {
335   int i;
336
337   for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
338     {
339       const char *s;
340
341       s = segment_name ((segT) i);
342       if (strcmp (segname, s) == 0
343           || (segname[0] == '.'
344               && strcmp (segname + 1, s) == 0))
345         {
346           subseg_set ((segT) i, subseg);
347           return (segT) i;
348         }
349 #ifdef obj_segment_name
350       s = obj_segment_name ((segT) i);
351       if (strcmp (segname, s) == 0
352           || (segname[0] == '.'
353               && strcmp (segname + 1, s) == 0))
354         {
355           subseg_set ((segT) i, subseg);
356           return (segT) i;
357         }
358 #endif
359     }
360
361 #ifdef obj_add_segment
362   {
363     segT new_seg;
364     new_seg = obj_add_segment (segname);
365     subseg_set (new_seg, subseg);
366     return new_seg;
367   }
368 #else
369   as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname);
370   return now_seg;
371 #endif
372 }
373
374 void
375 subseg_set (seg, subseg)        /* begin assembly for a new sub-segment */
376      register segT seg;         /* SEG_DATA or SEG_TEXT */
377      register subsegT subseg;
378 {
379 #ifndef MANY_SEGMENTS
380   know (seg == SEG_DATA
381         || seg == SEG_TEXT
382         || seg == SEG_BSS
383         || seg == SEG_ABSOLUTE);
384 #endif
385
386   if (seg != now_seg || subseg != now_subseg)
387     {                           /* we just changed sub-segments */
388       subseg_set_rest (seg, subseg);
389     }
390   mri_common_symbol = NULL;
391 }
392
393 #else /* BFD_ASSEMBLER */
394
395 segT
396 subseg_get (segname, force_new)
397      const char *segname;
398      int force_new;
399 {
400   segT secptr;
401   segment_info_type *seginfo;
402   const char *now_seg_name = (now_seg
403                               ? bfd_get_section_name (stdoutput, now_seg)
404                               : 0);
405
406   if (!force_new
407       && now_seg_name
408       && (now_seg_name == segname
409           || !strcmp (now_seg_name, segname)))
410     return now_seg;
411
412   if (!force_new)
413     secptr = bfd_make_section_old_way (stdoutput, segname);
414   else
415     secptr = bfd_make_section_anyway (stdoutput, segname);
416
417   seginfo = seg_info (secptr);
418   if (! seginfo)
419     {
420       /* Check whether output_section is set first because secptr may
421          be bfd_abs_section_ptr.  */
422       if (secptr->output_section != secptr)
423         secptr->output_section = secptr;
424       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
425       memset ((PTR) seginfo, 0, sizeof (*seginfo));
426       seginfo->fix_root = NULL;
427       seginfo->fix_tail = NULL;
428       seginfo->bfd_section = secptr;
429       if (secptr == bfd_abs_section_ptr)
430         abs_seg_info = seginfo;
431       else if (secptr == bfd_und_section_ptr)
432         und_seg_info = seginfo;
433       else
434         bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
435       seginfo->frchainP = NULL;
436       seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
437       seginfo->sym = NULL;
438       seginfo->dot = NULL;
439     }
440   return secptr;
441 }
442
443 segT
444 subseg_new (segname, subseg)
445      const char *segname;
446      subsegT subseg;
447 {
448   segT secptr;
449   segment_info_type *seginfo;
450
451   secptr = subseg_get (segname, 0);
452   subseg_set_rest (secptr, subseg);
453   seginfo = seg_info (secptr);
454   if (! seginfo->frchainP)
455     seginfo->frchainP = frchain_now;
456   return secptr;
457 }
458
459 /* Like subseg_new, except a new section is always created, even if
460    a section with that name already exists.  */
461 segT
462 subseg_force_new (segname, subseg)
463      const char *segname;
464      subsegT subseg;
465 {
466   segT secptr;
467   segment_info_type *seginfo;
468
469   secptr = subseg_get (segname, 1);
470   subseg_set_rest (secptr, subseg);
471   seginfo = seg_info (secptr);
472   if (! seginfo->frchainP)
473     seginfo->frchainP = frchain_now;
474   return secptr;
475 }
476
477 void
478 subseg_set (secptr, subseg)
479      segT secptr;
480      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 (sec)
495      segT sec;
496 {
497   if (sec == bfd_abs_section_ptr)
498     return abs_seg_info;
499   else if (sec == bfd_und_section_ptr)
500     return und_seg_info;
501   else
502     return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
503 }
504
505 symbolS *
506 section_symbol (sec)
507      segT sec;
508 {
509   segment_info_type *seginfo = seg_info (sec);
510   symbolS *s;
511
512   if (seginfo == 0)
513     abort ();
514   if (seginfo->sym)
515     return seginfo->sym;
516
517 #ifndef EMIT_SECTION_SYMBOLS
518 #define EMIT_SECTION_SYMBOLS 1
519 #endif
520
521   if (! EMIT_SECTION_SYMBOLS
522 #ifdef BFD_ASSEMBLER
523       || symbol_table_frozen
524 #endif
525       )
526     /* Here we know it won't be going into the symbol table.  */
527     s = symbol_create (sec->name, sec, 0, &zero_address_frag);
528   else
529     s = symbol_new (sec->name, sec, 0, &zero_address_frag);
530   S_CLEAR_EXTERNAL (s);
531
532   /* Use the BFD section symbol, if possible.  */
533   if (obj_sec_sym_ok_for_reloc (sec))
534     s->bsym = sec->symbol;
535
536   seginfo->sym = s;
537   return s;
538 }
539
540 #endif /* BFD_ASSEMBLER */
541
542 void
543 subsegs_print_statistics (file)
544      FILE *file;
545 {
546   frchainS *frchp;
547   fprintf (file, "frag chains:\n");
548   for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
549     {
550       int count = 0;
551       fragS *fragp;
552
553       /* If frch_subseg is non-zero, it's probably been chained onto
554          the end of a previous subsection.  Don't count it again.  */
555       if (frchp->frch_subseg != 0)
556         continue;
557
558       /* Skip gas-internal sections.  */
559       if (segment_name (frchp->frch_seg)[0] == '*')
560         continue;
561
562       for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
563         {
564 #if 0
565           switch (fragp->fr_type)
566             {
567             case rs_fill:
568               fprintf (file, "f"); break;
569             case rs_align:
570               fprintf (file, "a"); break;
571             case rs_align_code:
572               fprintf (file, "c"); break;
573             case rs_org:
574               fprintf (file, "o"); break;
575             case rs_machine_dependent:
576               fprintf (file, "m"); break;
577             case rs_space:
578               fprintf (file, "s"); break;
579             case 0:
580               fprintf (file, "0"); break;
581             default:
582               fprintf (file, "?"); break;
583             }
584 #endif
585           count++;
586         }
587       fprintf (file, "\n");
588       fprintf (file, "\t%p %-10s\t%10d frags\n", frchp,
589                segment_name (frchp->frch_seg), count);
590     }
591 }
592
593 /* end of subsegs.c */