xref: /openbsd-src/gnu/usr.bin/binutils-2.17/gas/subsegs.c (revision a51f8248c4852d1631cfe0f5c1956f852b4cf6dc)
1 /* subsegs.c - subsegments -
2    Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
3    1999, 2000, 2001, 2002, 2003, 2004, 2005
4    Free Software Foundation, Inc.
5 
6    This file is part of GAS, the GNU Assembler.
7 
8    GAS is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2, or (at your option)
11    any later version.
12 
13    GAS is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with GAS; see the file COPYING.  If not, write to the Free
20    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, USA.  */
22 
23 /* Segments & sub-segments.  */
24 
25 #include "as.h"
26 
27 #include "subsegs.h"
28 #include "obstack.h"
29 
30 frchainS *frchain_root, *frchain_now;
31 
32 static struct obstack frchains;
33 
34 /* Gas segment information for bfd_abs_section_ptr and
35    bfd_und_section_ptr.  */
36 static segment_info_type *abs_seg_info;
37 static segment_info_type *und_seg_info;
38 
39 static void subseg_set_rest (segT, subsegT);
40 
41 static fragS dummy_frag;
42 
43 static frchainS absolute_frchain;
44 
45 void
subsegs_begin(void)46 subsegs_begin (void)
47 {
48   obstack_begin (&frchains, chunksize);
49 #if __GNUC__ >= 2
50   obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
51 #endif
52 
53   frchain_root = NULL;
54   frchain_now = NULL;		/* Warn new_subseg() that we are booting.  */
55 
56   frag_now = &dummy_frag;
57 
58   absolute_frchain.frch_seg = absolute_section;
59   absolute_frchain.frch_subseg = 0;
60   absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
61   absolute_frchain.frch_frag_now = &zero_address_frag;
62   absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
63 }
64 
65 /*
66  *			subseg_change()
67  *
68  * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
69  * subsegment. If we are already in the correct subsegment, change nothing.
70  * This is used eg as a worker for subseg_set [which does make a new frag_now]
71  * and for changing segments after we have read the source. We construct eg
72  * fixSs even after the source file is read, so we do have to keep the
73  * segment context correct.
74  */
75 void
subseg_change(register segT seg,register int subseg)76 subseg_change (register segT seg, register int subseg)
77 {
78   segment_info_type *seginfo;
79   now_seg = seg;
80   now_subseg = subseg;
81 
82   if (now_seg == absolute_section)
83     return;
84 
85   seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
86   if (! seginfo)
87     {
88       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
89       memset ((PTR) seginfo, 0, sizeof (*seginfo));
90       seginfo->fix_root = NULL;
91       seginfo->fix_tail = NULL;
92       seginfo->bfd_section = seg;
93       seginfo->sym = 0;
94       if (seg == bfd_abs_section_ptr)
95 	abs_seg_info = seginfo;
96       else if (seg == bfd_und_section_ptr)
97 	und_seg_info = seginfo;
98       else
99 	bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
100     }
101 }
102 
103 static void
subseg_set_rest(segT seg,subsegT subseg)104 subseg_set_rest (segT seg, subsegT subseg)
105 {
106   register frchainS *frcP;	/* crawl frchain chain */
107   register frchainS **lastPP;	/* address of last pointer */
108   frchainS *newP;		/* address of new frchain */
109 
110   mri_common_symbol = NULL;
111 
112   if (frag_now && frchain_now)
113     frchain_now->frch_frag_now = frag_now;
114 
115   assert (frchain_now == 0
116 	  || now_seg == undefined_section
117 	  || now_seg == absolute_section
118 	  || frchain_now->frch_last == frag_now);
119 
120   subseg_change (seg, (int) subseg);
121 
122   if (seg == absolute_section)
123     {
124       frchain_now = &absolute_frchain;
125       frag_now = &zero_address_frag;
126       return;
127     }
128 
129   assert (frchain_now == 0
130 	  || now_seg == undefined_section
131 	  || frchain_now->frch_last == frag_now);
132 
133   /*
134    * Attempt to find or make a frchain for that sub seg.
135    * Crawl along chain of frchainSs, begins @ frchain_root.
136    * If we need to make a frchainS, link it into correct
137    * position of chain rooted in frchain_root.
138    */
139   for (frcP = *(lastPP = &frchain_root);
140        frcP && frcP->frch_seg <= seg;
141        frcP = *(lastPP = &frcP->frch_next))
142     {
143       if (frcP->frch_seg == seg
144 	  && frcP->frch_subseg >= subseg)
145 	{
146 	  break;
147 	}
148     }
149   /*
150    * frcP:		Address of the 1st frchainS in correct segment with
151    *		frch_subseg >= subseg.
152    *		We want to either use this frchainS, or we want
153    *		to insert a new frchainS just before it.
154    *
155    *		If frcP==NULL, then we are at the end of the chain
156    *		of frchainS-s. A NULL frcP means we fell off the end
157    *		of the chain looking for a
158    *		frch_subseg >= subseg, so we
159    *		must make a new frchainS.
160    *
161    *		If we ever maintain a pointer to
162    *		the last frchainS in the chain, we change that pointer
163    *		ONLY when frcP==NULL.
164    *
165    * lastPP:	Address of the pointer with value frcP;
166    *		Never NULL.
167    *		May point to frchain_root.
168    *
169    */
170   if (!frcP
171       || (frcP->frch_seg > seg
172 	  || frcP->frch_subseg > subseg))	/* Kinky logic only works with 2 segments.  */
173     {
174       /*
175        * This should be the only code that creates a frchainS.
176        */
177       segment_info_type *seginfo;
178 
179       newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
180       newP->frch_subseg = subseg;
181       newP->frch_seg = seg;
182       newP->fix_root = NULL;
183       newP->fix_tail = NULL;
184       obstack_begin (&newP->frch_obstack, chunksize);
185 #if __GNUC__ >= 2
186       obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
187 #endif
188       newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
189       newP->frch_frag_now->fr_type = rs_fill;
190       newP->frch_cfi_data = NULL;
191 
192       newP->frch_root = newP->frch_last = newP->frch_frag_now;
193 
194       *lastPP = newP;
195       newP->frch_next = frcP;	/* perhaps NULL */
196 
197       seginfo = seg_info (seg);
198       if (seginfo && (!seginfo->frchainP || seginfo->frchainP == frcP))
199 	seginfo->frchainP = newP;
200 
201       frcP = newP;
202     }
203   /*
204    * Here with frcP pointing to the frchainS for subseg.
205    */
206   frchain_now = frcP;
207   frag_now = frcP->frch_frag_now;
208 
209   assert (frchain_now->frch_last == frag_now);
210 }
211 
212 /*
213  *			subseg_set(segT, subsegT)
214  *
215  * If you attempt to change to the current subsegment, nothing happens.
216  *
217  * In:	segT, subsegT code for new subsegment.
218  *	frag_now -> incomplete frag for current subsegment.
219  *	If frag_now==NULL, then there is no old, incomplete frag, so
220  *	the old frag is not closed off.
221  *
222  * Out:	now_subseg, now_seg updated.
223  *	Frchain_now points to the (possibly new) struct frchain for this
224  *	sub-segment.
225  *	Frchain_root updated if needed.
226  */
227 
228 segT
subseg_get(const char * segname,int force_new)229 subseg_get (const char *segname, int force_new)
230 {
231   segT secptr;
232   segment_info_type *seginfo;
233   const char *now_seg_name = (now_seg
234 			      ? bfd_get_section_name (stdoutput, now_seg)
235 			      : 0);
236 
237   if (!force_new
238       && now_seg_name
239       && (now_seg_name == segname
240 	  || !strcmp (now_seg_name, segname)))
241     return now_seg;
242 
243   if (!force_new)
244     secptr = bfd_make_section_old_way (stdoutput, segname);
245   else
246     secptr = bfd_make_section_anyway (stdoutput, segname);
247 
248 #ifdef obj_sec_set_private_data
249   obj_sec_set_private_data (stdoutput, secptr);
250 #endif
251 
252   seginfo = seg_info (secptr);
253   if (! seginfo)
254     {
255       /* Check whether output_section is set first because secptr may
256 	 be bfd_abs_section_ptr.  */
257       if (secptr->output_section != secptr)
258 	secptr->output_section = secptr;
259       seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
260       memset ((PTR) seginfo, 0, sizeof (*seginfo));
261       seginfo->fix_root = NULL;
262       seginfo->fix_tail = NULL;
263       seginfo->bfd_section = secptr;
264       if (secptr == bfd_abs_section_ptr)
265 	abs_seg_info = seginfo;
266       else if (secptr == bfd_und_section_ptr)
267 	und_seg_info = seginfo;
268       else
269 	bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
270       seginfo->frchainP = NULL;
271       seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
272       seginfo->sym = NULL;
273       seginfo->dot = NULL;
274     }
275   return secptr;
276 }
277 
278 segT
subseg_new(const char * segname,subsegT subseg)279 subseg_new (const char *segname, subsegT subseg)
280 {
281   segT secptr;
282   segment_info_type *seginfo;
283 
284   secptr = subseg_get (segname, 0);
285   subseg_set_rest (secptr, subseg);
286   seginfo = seg_info (secptr);
287   if (! seginfo->frchainP)
288     seginfo->frchainP = frchain_now;
289   return secptr;
290 }
291 
292 /* Like subseg_new, except a new section is always created, even if
293    a section with that name already exists.  */
294 segT
subseg_force_new(const char * segname,subsegT subseg)295 subseg_force_new (const char *segname, subsegT subseg)
296 {
297   segT secptr;
298   segment_info_type *seginfo;
299 
300   secptr = subseg_get (segname, 1);
301   subseg_set_rest (secptr, subseg);
302   seginfo = seg_info (secptr);
303   if (! seginfo->frchainP)
304     seginfo->frchainP = frchain_now;
305   return secptr;
306 }
307 
308 void
subseg_set(segT secptr,subsegT subseg)309 subseg_set (segT secptr, subsegT subseg)
310 {
311   if (! (secptr == now_seg && subseg == now_subseg))
312     subseg_set_rest (secptr, subseg);
313   mri_common_symbol = NULL;
314 }
315 
316 #ifndef obj_sec_sym_ok_for_reloc
317 #define obj_sec_sym_ok_for_reloc(SEC)	0
318 #endif
319 
320 /* Get the gas information we are storing for a section.  */
321 
322 segment_info_type *
seg_info(segT sec)323 seg_info (segT sec)
324 {
325   if (sec == bfd_abs_section_ptr)
326     return abs_seg_info;
327   else if (sec == bfd_und_section_ptr)
328     return und_seg_info;
329   else
330     return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
331 }
332 
333 symbolS *
section_symbol(segT sec)334 section_symbol (segT sec)
335 {
336   segment_info_type *seginfo = seg_info (sec);
337   symbolS *s;
338 
339   if (seginfo == 0)
340     abort ();
341   if (seginfo->sym)
342     return seginfo->sym;
343 
344 #ifndef EMIT_SECTION_SYMBOLS
345 #define EMIT_SECTION_SYMBOLS 1
346 #endif
347 
348   if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
349     {
350       /* Here we know it won't be going into the symbol table.  */
351       s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
352     }
353   else
354     {
355       segT seg;
356       s = symbol_find (sec->symbol->name);
357       /* We have to make sure it is the right symbol when we
358 	 have multiple sections with the same section name.  */
359       if (s == NULL
360 	  || ((seg = S_GET_SEGMENT (s)) != sec
361 	      && seg != undefined_section))
362 	s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
363       else if (seg == undefined_section)
364 	{
365 	  S_SET_SEGMENT (s, sec);
366 	  symbol_set_frag (s, &zero_address_frag);
367 	}
368     }
369 
370   S_CLEAR_EXTERNAL (s);
371 
372   /* Use the BFD section symbol, if possible.  */
373   if (obj_sec_sym_ok_for_reloc (sec))
374     symbol_set_bfdsym (s, sec->symbol);
375   else
376     symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
377 
378   seginfo->sym = s;
379   return s;
380 }
381 
382 /* Return whether the specified segment is thought to hold text.  */
383 
384 int
subseg_text_p(segT sec)385 subseg_text_p (segT sec)
386 {
387   return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
388 }
389 
390 /* Return non zero if SEC has at least one byte of data.  It is
391    possible that we'll return zero even on a non-empty section because
392    we don't know all the fragment types, and it is possible that an
393    fr_fix == 0 one still contributes data.  Think of this as
394    seg_definitely_not_empty_p.  */
395 
396 int
seg_not_empty_p(segT sec ATTRIBUTE_UNUSED)397 seg_not_empty_p (segT sec ATTRIBUTE_UNUSED)
398 {
399   segment_info_type *seginfo = seg_info (sec);
400   frchainS *chain;
401   fragS *frag;
402 
403   if (!seginfo)
404     return 0;
405 
406   for (chain = seginfo->frchainP; chain; chain = chain->frch_next)
407     {
408       for (frag = chain->frch_root; frag; frag = frag->fr_next)
409 	if (frag->fr_fix)
410 	  return 1;
411       if (obstack_next_free (&chain->frch_obstack)
412 	  != chain->frch_last->fr_literal)
413 	return 1;
414     }
415   return 0;
416 }
417 
418 void
subsegs_print_statistics(FILE * file)419 subsegs_print_statistics (FILE *file)
420 {
421   frchainS *frchp;
422   fprintf (file, "frag chains:\n");
423   for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
424     {
425       int count = 0;
426       fragS *fragp;
427 
428       /* If frch_subseg is non-zero, it's probably been chained onto
429 	 the end of a previous subsection.  Don't count it again.  */
430       if (frchp->frch_subseg != 0)
431 	continue;
432 
433       /* Skip gas-internal sections.  */
434       if (segment_name (frchp->frch_seg)[0] == '*')
435 	continue;
436 
437       for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
438 	{
439 	  count++;
440 	}
441       fprintf (file, "\n");
442       fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
443 	       segment_name (frchp->frch_seg), count);
444     }
445 }
446 
447 /* end of subsegs.c */
448