]>
Commit | Line | Data |
---|---|---|
fecd2382 | 1 | /* subsegs.c - subsegments - |
6d5460ab | 2 | Copyright (C) 1987, 1990, 1991, 1992 Free Software Foundation, Inc. |
604633ae | 3 | |
a39116f1 | 4 | This file is part of GAS, the GNU Assembler. |
604633ae | 5 | |
a39116f1 RP |
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 2, or (at your option) | |
9 | any later version. | |
604633ae | 10 | |
a39116f1 RP |
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. | |
604633ae | 15 | |
a39116f1 RP |
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. */ | |
fecd2382 RP |
19 | |
20 | /* | |
21 | * Segments & sub-segments. | |
22 | */ | |
23 | ||
24 | #include "as.h" | |
25 | ||
26 | #include "subsegs.h" | |
27 | #include "obstack.h" | |
28 | ||
604633ae ILT |
29 | frchainS *frchain_root, *frchain_now; |
30 | ||
31 | #ifndef BFD_ASSEMBLER | |
a39116f1 RP |
32 | #ifdef MANY_SEGMENTS |
33 | segment_info_type segment_info[SEG_MAXIMUM_ORDINAL]; | |
34 | ||
a39116f1 | 35 | #else |
604633ae ILT |
36 | /* Commented in "subsegs.h". */ |
37 | frchainS *data0_frchainP, *bss0_frchainP; | |
fecd2382 | 38 | |
604633ae ILT |
39 | #endif /* MANY_SEGMENTS */ |
40 | char *const seg_name[] = | |
41 | { | |
42 | "absolute", | |
a39116f1 | 43 | #ifdef MANY_SEGMENTS |
604633ae | 44 | "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", |
a39116f1 | 45 | #else |
604633ae ILT |
46 | "text", |
47 | "data", | |
48 | "bss", | |
49 | #endif /* MANY_SEGMENTS */ | |
50 | "unknown", | |
51 | "ASSEMBLER-INTERNAL-LOGIC-ERROR!", | |
52 | "expr", | |
53 | "debug", | |
54 | "transfert vector preload", | |
55 | "transfert vector postload", | |
56 | "register", | |
57 | "", | |
58 | }; /* Used by error reporters, dumpers etc. */ | |
59 | #endif /* BFD_ASSEMBLER */ | |
fecd2382 | 60 | |
604633ae | 61 | static void subseg_set_rest PARAMS ((segT, subsegT)); |
fecd2382 RP |
62 | \f |
63 | void | |
604633ae | 64 | subsegs_begin () |
fecd2382 | 65 | { |
604633ae ILT |
66 | /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ |
67 | #if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) | |
68 | know (SEG_ABSOLUTE == 0); | |
69 | know (SEG_TEXT == 1); | |
70 | know (SEG_DATA == 2); | |
71 | know (SEG_BSS == 3); | |
72 | know (SEG_UNKNOWN == 4); | |
73 | know (SEG_GOOF == 5); | |
74 | know (SEG_EXPR == 6); | |
75 | know (SEG_DEBUG == 7); | |
76 | know (SEG_NTV == 8); | |
77 | know (SEG_PTV == 9); | |
78 | know (SEG_REGISTER == 10); | |
79 | know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER); | |
a39116f1 | 80 | #endif |
604633ae ILT |
81 | |
82 | obstack_begin (&frags, 5000); | |
83 | frchain_root = NULL; | |
84 | frchain_now = NULL; /* Warn new_subseg() that we are booting. */ | |
85 | /* Fake up 1st frag. It won't be used=> is ok if obstack... | |
86 | pads the end of it for alignment. */ | |
87 | frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG); | |
88 | memset (frag_now, SIZEOF_STRUCT_FRAG, 0); | |
89 | ||
90 | #ifndef BFD_ASSEMBLER | |
91 | /* This 1st frag will not be in any frchain. | |
92 | We simply give subseg_new somewhere to scribble. */ | |
93 | now_subseg = 42; /* Lie for 1st call to subseg_new. */ | |
a39116f1 | 94 | #ifdef MANY_SEGMENTS |
604633ae ILT |
95 | { |
96 | int i; | |
97 | for (i = SEG_E0; i < SEG_UNKNOWN; i++) | |
98 | { | |
99 | subseg_set (i, 0); | |
100 | segment_info[i].frchainP = frchain_now; | |
101 | } | |
102 | } | |
a39116f1 | 103 | #else |
604633ae ILT |
104 | subseg_set (SEG_DATA, 0); /* .data 0 */ |
105 | data0_frchainP = frchain_now; | |
65bfcf2e | 106 | |
604633ae ILT |
107 | subseg_set (SEG_BSS, 0); |
108 | bss0_frchainP = frchain_now; | |
109 | ||
110 | #endif /* ! MANY_SEGMENTS */ | |
111 | #endif /* ! BFD_ASSEMBLER */ | |
65bfcf2e | 112 | |
fecd2382 RP |
113 | } |
114 | \f | |
115 | /* | |
116 | * subseg_change() | |
117 | * | |
118 | * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the | |
119 | * subsegment. If we are already in the correct subsegment, change nothing. | |
604633ae | 120 | * This is used eg as a worker for subseg_set [which does make a new frag_now] |
fecd2382 RP |
121 | * and for changing segments after we have read the source. We construct eg |
122 | * fixSs even after the source file is read, so we do have to keep the | |
123 | * segment context correct. | |
124 | */ | |
125 | void | |
604633ae ILT |
126 | subseg_change (seg, subseg) |
127 | register segT seg; | |
128 | register int subseg; | |
fecd2382 | 129 | { |
604633ae ILT |
130 | now_seg = seg; |
131 | now_subseg = subseg; | |
132 | ||
133 | #ifdef BFD_ASSEMBLER | |
134 | { | |
135 | segment_info_type *seginfo; | |
136 | seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg); | |
137 | if (! seginfo) | |
138 | { | |
139 | seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); | |
140 | if (! seginfo) | |
141 | abort (); | |
142 | seginfo->fix_root = 0; | |
143 | seginfo->fix_tail = 0; | |
144 | seginfo->bfd_section = seg; | |
145 | seginfo->sym = 0; | |
146 | bfd_set_section_userdata (stdoutput, seg, (char *) seginfo); | |
147 | } | |
148 | } | |
149 | #else | |
a39116f1 | 150 | #ifdef MANY_SEGMENTS |
604633ae ILT |
151 | seg_fix_rootP = &segment_info[seg].fix_root; |
152 | seg_fix_tailP = &segment_info[seg].fix_tail; | |
a39116f1 | 153 | #else |
604633ae ILT |
154 | if (seg == SEG_DATA) |
155 | { | |
156 | seg_fix_rootP = &data_fix_root; | |
157 | seg_fix_tailP = &data_fix_tail; | |
158 | } | |
159 | else if (seg == SEG_TEXT) | |
160 | { | |
161 | seg_fix_rootP = &text_fix_root; | |
162 | seg_fix_tailP = &text_fix_tail; | |
163 | } | |
164 | else | |
165 | { | |
166 | know (seg == SEG_BSS); | |
167 | seg_fix_rootP = &bss_fix_root; | |
168 | seg_fix_tailP = &bss_fix_tail; | |
169 | } | |
170 | ||
171 | #endif | |
a39116f1 | 172 | #endif |
fecd2382 RP |
173 | } |
174 | \f | |
604633ae ILT |
175 | static void |
176 | subseg_set_rest (seg, subseg) | |
177 | segT seg; | |
178 | subsegT subseg; | |
179 | { | |
180 | long tmp; /* JF for obstack alignment hacking */ | |
181 | register frchainS *frcP; /* crawl frchain chain */ | |
182 | register frchainS **lastPP; /* address of last pointer */ | |
183 | frchainS *newP; /* address of new frchain */ | |
184 | register fragS *former_last_fragP; | |
185 | register fragS *new_fragP; | |
186 | ||
187 | if (frag_now) /* If not bootstrapping. */ | |
188 | { | |
189 | frag_now->fr_fix = (char*) obstack_next_free (&frags) - frag_now->fr_literal; | |
190 | frag_wane (frag_now); /* Close off any frag in old subseg. */ | |
191 | } | |
192 | /* | |
193 | * It would be nice to keep an obstack for each subsegment, if we swap | |
194 | * subsegments a lot. Hence we would have much fewer frag_wanes(). | |
195 | */ | |
196 | { | |
197 | obstack_finish (&frags); | |
198 | /* | |
199 | * If we don't do the above, the next object we put on obstack frags | |
200 | * will appear to start at the fr_literal of the current frag. | |
201 | * Also, above ensures that the next object will begin on a | |
202 | * address that is aligned correctly for the engine that runs | |
203 | * this program. | |
204 | */ | |
205 | } | |
206 | subseg_change (seg, (int) subseg); | |
207 | /* | |
208 | * Attempt to find or make a frchain for that sub seg. | |
209 | * Crawl along chain of frchainSs, begins @ frchain_root. | |
210 | * If we need to make a frchainS, link it into correct | |
211 | * position of chain rooted in frchain_root. | |
212 | */ | |
213 | for (frcP = *(lastPP = &frchain_root); | |
214 | frcP && (int) (frcP->frch_seg) <= (int) seg; | |
215 | frcP = *(lastPP = &frcP->frch_next)) | |
216 | { | |
217 | if ((int) (frcP->frch_seg) == (int) seg | |
218 | && frcP->frch_subseg >= subseg) | |
219 | { | |
220 | break; | |
221 | } | |
222 | } | |
223 | /* | |
224 | * frcP: Address of the 1st frchainS in correct segment with | |
225 | * frch_subseg >= subseg. | |
226 | * We want to either use this frchainS, or we want | |
227 | * to insert a new frchainS just before it. | |
228 | * | |
229 | * If frcP==NULL, then we are at the end of the chain | |
230 | * of frchainS-s. A NULL frcP means we fell off the end | |
231 | * of the chain looking for a | |
232 | * frch_subseg >= subseg, so we | |
233 | * must make a new frchainS. | |
234 | * | |
235 | * If we ever maintain a pointer to | |
236 | * the last frchainS in the chain, we change that pointer | |
237 | * ONLY when frcP==NULL. | |
238 | * | |
239 | * lastPP: Address of the pointer with value frcP; | |
240 | * Never NULL. | |
241 | * May point to frchain_root. | |
242 | * | |
243 | */ | |
244 | if (!frcP | |
245 | || ((int) (frcP->frch_seg) > (int) seg | |
246 | || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ | |
247 | { | |
248 | /* | |
249 | * This should be the only code that creates a frchainS. | |
250 | */ | |
251 | newP = (frchainS *) obstack_alloc (&frags, sizeof (frchainS)); | |
252 | memset (newP, sizeof (frchainS), 0); | |
253 | /* This begines on a good boundary because a obstack_done() | |
254 | preceeded it. It implies an obstack_done(), so we expect | |
255 | the next object allocated to begin on a correct boundary. */ | |
256 | *lastPP = newP; | |
257 | newP->frch_next = frcP; /* perhaps NULL */ | |
258 | (frcP = newP)->frch_subseg = subseg; | |
259 | newP->frch_seg = seg; | |
260 | newP->frch_last = NULL; | |
261 | } | |
262 | /* | |
263 | * Here with frcP ->ing to the frchainS for subseg. | |
264 | */ | |
265 | frchain_now = frcP; | |
266 | /* | |
267 | * Make a fresh frag for the subsegment. | |
268 | */ | |
269 | /* We expect this to happen on a correct boundary since it was | |
270 | proceeded by a obstack_done(). */ | |
271 | tmp = obstack_alignment_mask (&frags); /* JF disable alignment */ | |
272 | obstack_alignment_mask (&frags) = 0; | |
273 | frag_now = (fragS *) obstack_alloc (&frags, SIZEOF_STRUCT_FRAG); | |
274 | memset (frag_now, 0, SIZEOF_STRUCT_FRAG); | |
275 | obstack_alignment_mask (&frags) = tmp; | |
276 | /* But we want any more chars to come immediately after the | |
277 | structure we just made. */ | |
278 | new_fragP = frag_now; | |
279 | new_fragP->fr_next = NULL; | |
280 | /* | |
281 | * Append new frag to current frchain. | |
282 | */ | |
283 | former_last_fragP = frcP->frch_last; | |
284 | if (former_last_fragP) | |
285 | { | |
286 | know (former_last_fragP->fr_next == NULL); | |
287 | know (frchain_now->frch_root); | |
288 | former_last_fragP->fr_next = new_fragP; | |
289 | } | |
290 | else | |
291 | { | |
292 | frcP->frch_root = new_fragP; | |
293 | } | |
294 | frcP->frch_last = new_fragP; | |
295 | } | |
296 | ||
fecd2382 | 297 | /* |
604633ae | 298 | * subseg_set(segT, subsegT) |
fecd2382 RP |
299 | * |
300 | * If you attempt to change to the current subsegment, nothing happens. | |
301 | * | |
302 | * In: segT, subsegT code for new subsegment. | |
303 | * frag_now -> incomplete frag for current subsegment. | |
304 | * If frag_now==NULL, then there is no old, incomplete frag, so | |
305 | * the old frag is not closed off. | |
306 | * | |
307 | * Out: now_subseg, now_seg updated. | |
308 | * Frchain_now points to the (possibly new) struct frchain for this | |
309 | * sub-segment. | |
310 | * Frchain_root updated if needed. | |
311 | */ | |
312 | ||
604633ae ILT |
313 | #ifndef BFD_ASSEMBLER |
314 | ||
315 | segT | |
316 | subseg_new (segname, subseg) | |
317 | const char *segname; | |
318 | subsegT subseg; | |
fecd2382 | 319 | { |
604633ae ILT |
320 | int i; |
321 | ||
322 | for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++) | |
323 | { | |
324 | const char *s; | |
325 | ||
326 | s = segment_name ((segT) i); | |
327 | if (strcmp (segname, s) == 0 | |
328 | || (segname[0] == '.' | |
329 | && strcmp (segname + 1, s) == 0)) | |
f8701a3f | 330 | { |
604633ae ILT |
331 | subseg_set ((segT) i, subseg); |
332 | return (segT) i; | |
333 | } | |
334 | #ifdef obj_segment_name | |
335 | s = obj_segment_name ((segT) i); | |
336 | if (strcmp (segname, s) == 0 | |
337 | || (segname[0] == '.' | |
338 | && strcmp (segname + 1, s) == 0)) | |
339 | { | |
340 | subseg_set ((segT) i, subseg); | |
341 | return (segT) i; | |
f8701a3f | 342 | } |
a39116f1 | 343 | #endif |
604633ae | 344 | } |
fecd2382 | 345 | |
604633ae ILT |
346 | #ifdef obj_add_segment |
347 | { | |
348 | segT new_seg; | |
349 | new_seg = obj_add_segment (segname); | |
350 | subseg_set (new_seg, subseg); | |
351 | return new_seg; | |
352 | } | |
353 | #else | |
354 | as_bad ("Attempt to switch to nonexistent segment \"%s\"", segname); | |
355 | return now_seg; | |
356 | #endif | |
357 | } | |
358 | ||
359 | void | |
360 | subseg_set (seg, subseg) /* begin assembly for a new sub-segment */ | |
361 | register segT seg; /* SEG_DATA or SEG_TEXT */ | |
362 | register subsegT subseg; | |
363 | { | |
364 | #ifndef MANY_SEGMENTS | |
365 | know (seg == SEG_DATA || seg == SEG_TEXT || seg == SEG_BSS); | |
366 | #endif | |
367 | ||
368 | if (seg != now_seg || subseg != now_subseg) | |
369 | { /* we just changed sub-segments */ | |
370 | subseg_set_rest (seg, subseg); | |
371 | } | |
372 | } | |
373 | ||
374 | #else /* BFD_ASSEMBLER */ | |
375 | ||
376 | segT | |
377 | subseg_new (segname, subseg) | |
378 | const char *segname; | |
379 | subsegT subseg; | |
380 | { | |
381 | segT secptr; | |
382 | segment_info_type *seginfo; | |
383 | const char *now_seg_name = (now_seg | |
384 | ? bfd_get_section_name (stdoutput, now_seg) | |
385 | : 0); | |
386 | ||
387 | if (now_seg_name | |
388 | && (now_seg_name == segname | |
389 | || !strcmp (now_seg_name, segname)) | |
390 | && subseg == now_subseg) | |
391 | return now_seg; | |
392 | ||
393 | secptr = bfd_make_section_old_way (stdoutput, segname); | |
394 | seginfo = seg_info (secptr); | |
395 | if (! seginfo) | |
396 | { | |
397 | secptr->output_section = secptr; | |
398 | seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); | |
399 | seginfo->fix_root = 0; | |
400 | seginfo->fix_tail = 0; | |
401 | seginfo->bfd_section = secptr; | |
402 | bfd_set_section_userdata (stdoutput, secptr, (char *) seginfo); | |
403 | subseg_set_rest (secptr, subseg); | |
404 | seginfo->frchainP = frchain_now; | |
405 | seginfo->lineno_list_head = seginfo->lineno_list_tail = 0; | |
406 | seginfo->sym = 0; | |
407 | seginfo->dot = 0; | |
408 | seginfo->hadone = 0; | |
409 | seginfo->user_stuff = 0; | |
410 | } | |
411 | else | |
412 | subseg_set_rest (secptr, subseg); | |
413 | return secptr; | |
414 | } | |
415 | ||
416 | void | |
417 | subseg_set (secptr, subseg) | |
418 | segT secptr; | |
419 | subsegT subseg; | |
420 | { | |
421 | if (! (secptr == now_seg && subseg == now_subseg)) | |
422 | subseg_set_rest (secptr, subseg); | |
423 | } | |
424 | ||
425 | #endif /* BFD_ASSEMBLER */ | |
fecd2382 | 426 | |
8b228fe9 | 427 | /* end of subsegs.c */ |