Initial revision
[external/binutils.git] / gas / subsegs.c
1 /* subsegs.c - subsegments -
2    Copyright (C) 1987, 1990, 1991 Free Software Foundation, Inc.
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /* static const char rcsid[] = "$Id$"; */
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,
32         *       frchain_now,    /* Commented in "subsegs.h". */
33         *       data0_frchainP;
34
35
36 char * const /* in: segT   out: char* */
37 seg_name[] = {
38         "absolute",
39         "text",
40         "data",
41         "bss",
42         "unknown",
43         "absent",
44         "pass1",
45         "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
46         "bignum/flonum",
47         "difference",
48         "debug",
49         "transfert vector preload",
50         "transfert vector postload",
51         "register",
52         "",
53 }; /* Used by error reporters, dumpers etc. */
54
55 \f
56 void
57 subsegs_begin()
58 {
59   /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
60   know( SEG_ABSOLUTE    ==  0 );
61   know( SEG_TEXT        ==  1 );
62   know( SEG_DATA        ==  2 );
63   know( SEG_BSS         ==  3 );
64   know( SEG_UNKNOWN     ==  4 );
65   know( SEG_ABSENT      ==  5 );
66   know( SEG_PASS1       ==  6 );
67   know( SEG_GOOF        ==  7 );
68   know( SEG_BIG         ==  8 );
69   know( SEG_DIFFERENCE  ==  9 );
70   know( SEG_DEBUG       == 10 );
71   know( SEG_NTV         == 11 );
72   know( SEG_PTV         == 12 );
73   know( SEG_REGISTER    == 13 );
74   know( SEG_MAXIMUM_ORDINAL == SEG_REGISTER );
75   know( segment_name (SEG_MAXIMUM_ORDINAL + 1) [0] == 0 );
76
77   obstack_begin( &frags, 5000);
78   frchain_root = NULL;
79   frchain_now  = NULL;          /* Warn new_subseg() that we are booting. */
80                                 /* Fake up 1st frag. */
81                                 /* It won't be used=> is ok if obstack... */
82                                 /* pads the end of it for alignment. */
83   frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
84   /* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */
85                                 /* This 1st frag will not be in any frchain. */
86                                 /* We simply give subseg_new somewhere to scribble. */
87   now_subseg = 42;              /* Lie for 1st call to subseg_new. */
88   subseg_new (SEG_DATA, 0);     /* .data 0 */
89   data0_frchainP = frchain_now;
90 }
91 \f
92 /*
93  *                      subseg_change()
94  *
95  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
96  * subsegment. If we are already in the correct subsegment, change nothing.
97  * This is used eg as a worker for subseg_new [which does make a new frag_now]
98  * and for changing segments after we have read the source. We construct eg
99  * fixSs even after the source file is read, so we do have to keep the
100  * segment context correct.
101  */
102 void
103 subseg_change (seg, subseg)
104      register segT      seg;
105      register int       subseg;
106 {
107   now_seg        = seg;
108   now_subseg = subseg;
109   if (seg == SEG_DATA)
110     {
111       seg_fix_rootP = & data_fix_root;
112       seg_fix_tailP = & data_fix_tail;
113     }
114   else
115     {
116       know (seg == SEG_TEXT);
117       seg_fix_rootP = & text_fix_root;
118       seg_fix_tailP = & text_fix_tail;
119     }
120 }
121 \f
122 /*
123  *                      subseg_new()
124  *
125  * If you attempt to change to the current subsegment, nothing happens.
126  *
127  * In:  segT, subsegT code for new subsegment.
128  *      frag_now -> incomplete frag for current subsegment.
129  *      If frag_now==NULL, then there is no old, incomplete frag, so
130  *      the old frag is not closed off.
131  *
132  * Out: now_subseg, now_seg updated.
133  *      Frchain_now points to the (possibly new) struct frchain for this
134  *      sub-segment.
135  *      Frchain_root updated if needed.
136  */
137
138 void
139 subseg_new (seg, subseg)        /* begin assembly for a new sub-segment */
140      register segT      seg;    /* SEG_DATA or SEG_TEXT */
141      register subsegT   subseg;
142 {
143   long tmp;             /* JF for obstack alignment hacking */
144
145   know( seg == SEG_DATA || seg == SEG_TEXT );
146
147   if (seg != now_seg || subseg != now_subseg)
148     {                           /* we just changed sub-segments */
149       register  frchainS *      frcP;   /* crawl frchain chain */
150       register  frchainS**      lastPP; /* address of last pointer */
151                 frchainS *      newP;   /* address of new frchain */
152       register fragS *          former_last_fragP;
153       register fragS *          new_fragP;
154
155       if (frag_now)             /* If not bootstrapping. */
156         {
157           frag_now -> fr_fix = obstack_next_free(& frags) - frag_now -> fr_literal;
158           frag_wane(frag_now);  /* Close off any frag in old subseg. */
159         }
160 /*
161  * It would be nice to keep an obstack for each subsegment, if we swap
162  * subsegments a lot. Hence we would have much fewer frag_wanes().
163  */
164       {
165
166         obstack_finish( &frags);
167         /*
168          * If we don't do the above, the next object we put on obstack frags
169          * will appear to start at the fr_literal of the current frag.
170          * Also, above ensures that the next object will begin on a
171          * address that is aligned correctly for the engine that runs
172          * this program.
173          */
174       }
175       subseg_change (seg, (int)subseg);
176       /*
177        * Attempt to find or make a frchain for that sub seg.
178        * Crawl along chain of frchainSs, begins @ frchain_root.
179        * If we need to make a frchainS, link it into correct
180        * position of chain rooted in frchain_root.
181        */
182       for (frcP = * (lastPP = & frchain_root);
183            frcP
184            && (int)(frcP -> frch_seg) <= (int)seg;
185            frcP = * ( lastPP = & frcP -> frch_next)
186           )
187         {
188           if (   (int)(frcP -> frch_seg) == (int)seg
189               && frcP -> frch_subseg >= subseg)
190             {
191               break;
192             }
193         }
194       /*
195        * frcP:          Address of the 1st frchainS in correct segment with
196        *                frch_subseg >= subseg.
197        *                We want to either use this frchainS, or we want
198        *                to insert a new frchainS just before it.
199        *
200        *                If frcP==NULL, then we are at the end of the chain
201        *                of frchainS-s. A NULL frcP means we fell off the end
202        *                of the chain looking for a
203        *                frch_subseg >= subseg, so we
204        *                must make a new frchainS.
205        *
206        *                If we ever maintain a pointer to
207        *                the last frchainS in the chain, we change that pointer
208        *                ONLY when frcP==NULL.
209        *
210        * lastPP:        Address of the pointer with value frcP;
211        *                Never NULL.
212        *                May point to frchain_root.
213        *
214        */
215       if (   ! frcP
216           || (   (int)(frcP -> frch_seg) > (int)seg
217               || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
218         {
219           /*
220            * This should be the only code that creates a frchainS.
221            */
222           newP=(frchainS *)obstack_alloc(&frags,sizeof(frchainS));
223           /* obstack_1blank( &frags, sizeof(frchainS), &newP); */
224                                 /* This begines on a good boundary */
225                                 /* because a obstack_done() preceeded  it. */
226                                 /* It implies an obstack_done(), so we */
227                                 /* expect the next object allocated to */
228                                 /* begin on a correct boundary. */
229           *lastPP = newP;
230           newP -> frch_next = frcP; /* perhaps NULL */
231           (frcP = newP) -> frch_subseg          = subseg;
232                   newP  -> frch_seg             = seg;
233                   newP  -> frch_last            = NULL;
234         }
235       /*
236        * Here with frcP ->ing to the frchainS for subseg.
237        */
238       frchain_now = frcP;
239       /*
240        * Make a fresh frag for the subsegment.
241        */
242                                 /* We expect this to happen on a correct */
243                                 /* boundary since it was proceeded by a */
244                                 /* obstack_done(). */
245       tmp=obstack_alignment_mask(&frags);       /* JF disable alignment */
246       obstack_alignment_mask(&frags)=0;
247       frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
248       obstack_alignment_mask(&frags)=tmp;
249       /* know( frags . obstack_c_next_free == frag_now -> fr_literal ); */
250                                 /* But we want any more chars to come */
251                                 /* immediately after the structure we just made. */
252       new_fragP = frag_now;
253       new_fragP -> fr_next = NULL;
254       /*
255        * Append new frag to current frchain.
256        */
257       former_last_fragP = frcP -> frch_last;
258       if (former_last_fragP)
259         {
260           know( former_last_fragP -> fr_next == NULL );
261           know( frchain_now -> frch_root );
262           former_last_fragP -> fr_next = new_fragP;
263         }
264       else
265         {
266           frcP -> frch_root = new_fragP;
267         }
268       frcP -> frch_last = new_fragP;
269     }                           /* if (changing subsegments) */
270 }                               /* subseg_new() */
271
272 /*
273  * Local Variables:
274  * comment-column: 0
275  * fill-column: 131
276  * End:
277  */
278
279 /* end: subsegs.c */