xref: /386bsd/usr/src/usr.bin/gas/subsegs.c (revision a2142627)
1 /* subsegs.c - subsegments -
2    Copyright (C) 1987 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 /*
21  * Segments & sub-segments.
22  */
23 
24 #include "as.h"
25 #include "subsegs.h"
26 #include "obstack.h"
27 #include "frags.h"
28 #include "struc-symbol.h"
29 #include "write.h"
30 
31 frchainS*	frchain_root,
32 	*	frchain_now,	/* Commented in "subsegs.h". */
33 	*	data0_frchainP;
34 
35 
36 const int				/* in: segT   out: N_TYPE bits */
37 seg_N_TYPE[] = {
38   N_ABS,
39   N_TEXT,
40   N_DATA,
41   N_BSS,
42   N_UNDF,
43   N_UNDF,
44   N_UNDF,
45   N_UNDF,
46   N_UNDF,
47   N_UNDF
48 };
49 
50 
51 char * const				/* in: segT   out: char* */
52 seg_name[] = {
53   "absolute",
54   "text",
55   "data",
56   "bss",
57   "unknown",
58   "absent",
59   "pass1",
60   "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
61   "bignum/flonum",
62   "difference",
63   ""
64   };				/* Used by error reporters, dumpers etc. */
65 
66 const segT N_TYPE_seg [N_TYPE+2] =	/* N_TYPE == 0x1E = 32-2 */
67 {
68   SEG_UNKNOWN,			/* N_UNDF == 0 */
69   SEG_GOOF,
70   SEG_ABSOLUTE,			/* N_ABS == 2 */
71   SEG_GOOF,
72   SEG_TEXT,			/* N_TEXT == 4 */
73   SEG_GOOF,
74   SEG_DATA,			/* N_DATA == 6 */
75   SEG_GOOF,
76   SEG_BSS,			/* N_BSS == 8 */
77   SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
78   SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF,
79   SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF
80 };
81 
82 void
subsegs_begin()83 subsegs_begin()
84 {
85   /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
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_NONE    	==5 );
92   know( SEG_PASS1	==6 );
93   know( SEG_GOOF	==7 );
94   know( SEG_BIG		==8 );
95   know( SEG_DIFFERENCE	==9 );
96   know( SEG_MAXIMUM_ORDINAL == SEG_DIFFERENCE );
97   know( seg_name [(int) SEG_MAXIMUM_ORDINAL + 1] [0] == 0 );
98 
99   obstack_begin( &frags, 5000);
100   frchain_root = NULL;
101   frchain_now  = NULL;		/* Warn new_subseg() that we are booting. */
102 				/* Fake up 1st frag. */
103 				/* It won't be used=> is ok if obstack... */
104 				/* pads the end of it for alignment. */
105   frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
106   /* obstack_1blank( &frags, SIZEOF_STRUCT_FRAG, & frag_now ); */
107 				/* This 1st frag will not be in any frchain. */
108 				/* We simply give subseg_new somewhere to scribble. */
109   now_subseg = 42;		/* Lie for 1st call to subseg_new. */
110   subseg_new (SEG_DATA, 0);	/* .data 0 */
111   data0_frchainP = frchain_now;
112 }
113 
114 /*
115  *			subseg_change()
116  *
117  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
118  * subsegment. If we are already in the correct subsegment, change nothing.
119  * This is used eg as a worker for subseg_new [which does make a new frag_now]
120  * and for changing segments after we have read the source. We construct eg
121  * fixSs even after the source file is read, so we do have to keep the
122  * segment context correct.
123  */
124 void
subseg_change(seg,subseg)125 subseg_change (seg, subseg)
126      register segT	seg;
127      register int	subseg;
128 {
129   now_seg	 = seg;
130   now_subseg = subseg;
131   if (seg == SEG_DATA)
132     {
133       seg_fix_rootP = & data_fix_root;
134     }
135   else
136     {
137       know (seg == SEG_TEXT);
138       seg_fix_rootP = & text_fix_root;
139     }
140 }
141 
142 /*
143  *			subseg_new()
144  *
145  * If you attempt to change to the current subsegment, nothing happens.
146  *
147  * In:	segT, subsegT code for new subsegment.
148  *	frag_now -> incomplete frag for current subsegment.
149  *	If frag_now==NULL, then there is no old, incomplete frag, so
150  *	the old frag is not closed off.
151  *
152  * Out:	now_subseg, now_seg updated.
153  *	Frchain_now points to the (possibly new) struct frchain for this
154  *	sub-segment.
155  *	Frchain_root updated if needed.
156  */
157 
158 void
subseg_new(seg,subseg)159 subseg_new (seg, subseg)	/* begin assembly for a new sub-segment */
160      register segT	seg;	/* SEG_DATA or SEG_TEXT */
161      register subsegT	subseg;
162 {
163   long tmp;		/* JF for obstack alignment hacking */
164 
165   know( seg == SEG_DATA || seg == SEG_TEXT );
166 
167   if (seg != now_seg || subseg != now_subseg)
168     {				/* we just changed sub-segments */
169       register	frchainS *	frcP;	/* crawl frchain chain */
170       register	frchainS**	lastPP;	/* address of last pointer */
171 		frchainS *	newP;	/* address of new frchain */
172       register fragS *		former_last_fragP;
173       register fragS *		new_fragP;
174 
175       if (frag_now)		/* If not bootstrapping. */
176 	{
177 	  frag_now -> fr_fix = obstack_next_free(& frags) - frag_now -> fr_literal;
178 	  frag_wane(frag_now);	/* Close off any frag in old subseg. */
179 	}
180 /*
181  * It would be nice to keep an obstack for each subsegment, if we swap
182  * subsegments a lot. Hence we would have much fewer frag_wanes().
183  */
184       {
185 
186 	obstack_finish( &frags);
187 	/*
188 	 * If we don't do the above, the next object we put on obstack frags
189 	 * will appear to start at the fr_literal of the current frag.
190 	 * Also, above ensures that the next object will begin on a
191 	 * address that is aligned correctly for the engine that runs
192 	 * this program.
193 	 */
194       }
195       subseg_change (seg, (int)subseg);
196       /*
197        * Attempt to find or make a frchain for that sub seg.
198        * Crawl along chain of frchainSs, begins @ frchain_root.
199        * If we need to make a frchainS, link it into correct
200        * position of chain rooted in frchain_root.
201        */
202       for (frcP = * (lastPP = & frchain_root);
203 	   frcP
204 	   && (int)(frcP -> frch_seg) <= (int)seg;
205 	   frcP = * ( lastPP = & frcP -> frch_next)
206 	  )
207 	{
208 	  if (   (int)(frcP -> frch_seg) == (int)seg
209 	      && frcP -> frch_subseg >= subseg)
210 	    {
211 	      break;
212 	    }
213 	}
214       /*
215        * frcP:		Address of the 1st frchainS in correct segment with
216        *		frch_subseg >= subseg.
217        *		We want to either use this frchainS, or we want
218        *		to insert a new frchainS just before it.
219        *
220        *		If frcP==NULL, then we are at the end of the chain
221        *		of frchainS-s. A NULL frcP means we fell off the end
222        *		of the chain looking for a
223        *		frch_subseg >= subseg, so we
224        *		must make a new frchainS.
225        *
226        *		If we ever maintain a pointer to
227        *		the last frchainS in the chain, we change that pointer
228        *		ONLY when frcP==NULL.
229        *
230        * lastPP:	Address of the pointer with value frcP;
231        *		Never NULL.
232        *		May point to frchain_root.
233        *
234        */
235       if (   ! frcP
236 	  || (   (int)(frcP -> frch_seg) > (int)seg
237 	      || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */
238 	{
239 	  /*
240 	   * This should be the only code that creates a frchainS.
241 	   */
242 	  newP=(frchainS *)obstack_alloc(&frags,sizeof(frchainS));
243 	  /* obstack_1blank( &frags, sizeof(frchainS), &newP); */
244 				/* This begines on a good boundary */
245 				/* because a obstack_done() preceeded  it. */
246 				/* It implies an obstack_done(), so we */
247 				/* expect the next object allocated to */
248 				/* begin on a correct boundary. */
249 	  *lastPP = newP;
250 	  newP -> frch_next = frcP; /* perhaps NULL */
251 	  (frcP = newP) -> frch_subseg		= subseg;
252 		  newP  -> frch_seg		= seg;
253 		  newP  -> frch_last	 	= NULL;
254 	}
255       /*
256        * Here with frcP ->ing to the frchainS for subseg.
257        */
258       frchain_now = frcP;
259       /*
260        * Make a fresh frag for the subsegment.
261        */
262 				/* We expect this to happen on a correct */
263 				/* boundary since it was proceeded by a */
264 				/* obstack_done(). */
265       tmp=obstack_alignment_mask(&frags);	/* JF disable alignment */
266       obstack_alignment_mask(&frags)=0;
267       frag_now=(fragS *)obstack_alloc(&frags,SIZEOF_STRUCT_FRAG);
268       obstack_alignment_mask(&frags)=tmp;
269       /* know( frags . obstack_c_next_free == frag_now -> fr_literal ); */
270 				/* But we want any more chars to come */
271 				/* immediately after the structure we just made. */
272       new_fragP = frag_now;
273       new_fragP -> fr_next = NULL;
274       /*
275        * Append new frag to current frchain.
276        */
277       former_last_fragP = frcP -> frch_last;
278       if (former_last_fragP)
279 	{
280 	  know( former_last_fragP -> fr_next == NULL );
281 	  know( frchain_now -> frch_root );
282 	  former_last_fragP -> fr_next = new_fragP;
283 	}
284       else
285 	{
286 	  frcP -> frch_root = new_fragP;
287 	}
288       frcP -> frch_last = new_fragP;
289     }				/* if (changing subsegments) */
290 }				/* subseg_new() */
291 
292 /* end: subsegs.c */
293