~ubuntu-branches/ubuntu/hoary/binutils/hoary

« back to all changes in this revision

Viewing changes to gas/subsegs.c

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2004-05-19 10:35:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040519103544-17h3o6e8pwndydrg
Tags: 2.14.90.0.7-8
debian/rules: don't use gcc-2.95 on m68k.  Thanks to Adam Conrad for
pointing this out.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* subsegs.c - subsegments -
 
2
   Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
 
3
   1999, 2000, 2002
 
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, 59 Temple Place - Suite 330, Boston, MA
 
21
   02111-1307, 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
#ifndef BFD_ASSEMBLER
 
35
#ifdef MANY_SEGMENTS
 
36
segment_info_type segment_info[SEG_MAXIMUM_ORDINAL];
 
37
 
 
38
#else
 
39
/* Commented in "subsegs.h".  */
 
40
frchainS *data0_frchainP, *bss0_frchainP;
 
41
 
 
42
#endif /* MANY_SEGMENTS */
 
43
char const *const seg_name[] = {
 
44
  "absolute",
 
45
#ifdef MANY_SEGMENTS
 
46
  "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9",
 
47
  "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19",
 
48
  "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29",
 
49
  "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39",
 
50
#else
 
51
  "text",
 
52
  "data",
 
53
  "bss",
 
54
#endif /* MANY_SEGMENTS */
 
55
  "unknown",
 
56
  "ASSEMBLER-INTERNAL-LOGIC-ERROR!",
 
57
  "expr",
 
58
  "debug",
 
59
  "transfert vector preload",
 
60
  "transfert vector postload",
 
61
  "register",
 
62
  "",
 
63
};                              /* Used by error reporters, dumpers etc.  */
 
64
#else /* BFD_ASSEMBLER */
 
65
 
 
66
/* Gas segment information for bfd_abs_section_ptr and
 
67
   bfd_und_section_ptr.  */
 
68
static segment_info_type *abs_seg_info;
 
69
static segment_info_type *und_seg_info;
 
70
 
 
71
#endif /* BFD_ASSEMBLER */
 
72
 
 
73
static void subseg_set_rest PARAMS ((segT, subsegT));
 
74
 
 
75
static fragS dummy_frag;
 
76
 
 
77
static frchainS absolute_frchain;
 
78
 
 
79
void
 
80
subsegs_begin ()
 
81
{
 
82
  /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */
 
83
#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER)
 
84
  know (SEG_ABSOLUTE == 0);
 
85
  know (SEG_TEXT == 1);
 
86
  know (SEG_DATA == 2);
 
87
  know (SEG_BSS == 3);
 
88
  know (SEG_UNKNOWN == 4);
 
89
  know (SEG_GOOF == 5);
 
90
  know (SEG_EXPR == 6);
 
91
  know (SEG_DEBUG == 7);
 
92
  know (SEG_NTV == 8);
 
93
  know (SEG_PTV == 9);
 
94
  know (SEG_REGISTER == 10);
 
95
  know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER);
 
96
#endif
 
97
 
 
98
  obstack_begin (&frchains, chunksize);
 
99
#if __GNUC__ >= 2
 
100
  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
 
101
#endif
 
102
 
 
103
  frchain_root = NULL;
 
104
  frchain_now = NULL;           /* Warn new_subseg() that we are booting.  */
 
105
 
 
106
  frag_now = &dummy_frag;
 
107
 
 
108
#ifndef BFD_ASSEMBLER
 
109
  now_subseg = 42;              /* Lie for 1st call to subseg_new.  */
 
110
#ifdef MANY_SEGMENTS
 
111
  {
 
112
    int i;
 
113
    for (i = SEG_E0; i < SEG_UNKNOWN; i++)
 
114
      {
 
115
        subseg_set (i, 0);
 
116
        segment_info[i].frchainP = frchain_now;
 
117
      }
 
118
  }
 
119
#else
 
120
  subseg_set (SEG_DATA, 0);     /* .data 0 */
 
121
  data0_frchainP = frchain_now;
 
122
 
 
123
  subseg_set (SEG_BSS, 0);
 
124
  bss0_frchainP = frchain_now;
 
125
 
 
126
#endif /* ! MANY_SEGMENTS */
 
127
#endif /* ! BFD_ASSEMBLER */
 
128
 
 
129
  absolute_frchain.frch_seg = absolute_section;
 
130
  absolute_frchain.frch_subseg = 0;
 
131
#ifdef BFD_ASSEMBLER
 
132
  absolute_frchain.fix_root = absolute_frchain.fix_tail = 0;
 
133
#endif
 
134
  absolute_frchain.frch_frag_now = &zero_address_frag;
 
135
  absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag;
 
136
}
 
137
 
 
138
/*
 
139
 *                      subseg_change()
 
140
 *
 
141
 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
 
142
 * subsegment. If we are already in the correct subsegment, change nothing.
 
143
 * This is used eg as a worker for subseg_set [which does make a new frag_now]
 
144
 * and for changing segments after we have read the source. We construct eg
 
145
 * fixSs even after the source file is read, so we do have to keep the
 
146
 * segment context correct.
 
147
 */
 
148
void
 
149
subseg_change (seg, subseg)
 
150
     register segT seg;
 
151
     register int subseg;
 
152
{
 
153
  now_seg = seg;
 
154
  now_subseg = subseg;
 
155
 
 
156
  if (now_seg == absolute_section)
 
157
    return;
 
158
 
 
159
#ifdef BFD_ASSEMBLER
 
160
  {
 
161
    segment_info_type *seginfo;
 
162
    seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg);
 
163
    if (! seginfo)
 
164
      {
 
165
        seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
 
166
        memset ((PTR) seginfo, 0, sizeof (*seginfo));
 
167
        seginfo->fix_root = NULL;
 
168
        seginfo->fix_tail = NULL;
 
169
        seginfo->bfd_section = seg;
 
170
        seginfo->sym = 0;
 
171
        if (seg == bfd_abs_section_ptr)
 
172
          abs_seg_info = seginfo;
 
173
        else if (seg == bfd_und_section_ptr)
 
174
          und_seg_info = seginfo;
 
175
        else
 
176
          bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo);
 
177
      }
 
178
  }
 
179
#else
 
180
#ifdef MANY_SEGMENTS
 
181
  seg_fix_rootP = &segment_info[seg].fix_root;
 
182
  seg_fix_tailP = &segment_info[seg].fix_tail;
 
183
#else
 
184
  if (seg == SEG_DATA)
 
185
    {
 
186
      seg_fix_rootP = &data_fix_root;
 
187
      seg_fix_tailP = &data_fix_tail;
 
188
    }
 
189
  else if (seg == SEG_TEXT)
 
190
    {
 
191
      seg_fix_rootP = &text_fix_root;
 
192
      seg_fix_tailP = &text_fix_tail;
 
193
    }
 
194
  else
 
195
    {
 
196
      know (seg == SEG_BSS);
 
197
      seg_fix_rootP = &bss_fix_root;
 
198
      seg_fix_tailP = &bss_fix_tail;
 
199
    }
 
200
 
 
201
#endif
 
202
#endif
 
203
}
 
204
 
 
205
static void
 
206
subseg_set_rest (seg, subseg)
 
207
     segT seg;
 
208
     subsegT subseg;
 
209
{
 
210
  register frchainS *frcP;      /* crawl frchain chain */
 
211
  register frchainS **lastPP;   /* address of last pointer */
 
212
  frchainS *newP;               /* address of new frchain */
 
213
 
 
214
  mri_common_symbol = NULL;
 
215
 
 
216
  if (frag_now && frchain_now)
 
217
    frchain_now->frch_frag_now = frag_now;
 
218
 
 
219
  assert (frchain_now == 0
 
220
          || now_seg == undefined_section
 
221
          || now_seg == absolute_section
 
222
          || frchain_now->frch_last == frag_now);
 
223
 
 
224
  subseg_change (seg, (int) subseg);
 
225
 
 
226
  if (seg == absolute_section)
 
227
    {
 
228
      frchain_now = &absolute_frchain;
 
229
      frag_now = &zero_address_frag;
 
230
      return;
 
231
    }
 
232
 
 
233
  assert (frchain_now == 0
 
234
          || now_seg == undefined_section
 
235
          || frchain_now->frch_last == frag_now);
 
236
 
 
237
  /*
 
238
   * Attempt to find or make a frchain for that sub seg.
 
239
   * Crawl along chain of frchainSs, begins @ frchain_root.
 
240
   * If we need to make a frchainS, link it into correct
 
241
   * position of chain rooted in frchain_root.
 
242
   */
 
243
  for (frcP = *(lastPP = &frchain_root);
 
244
       frcP && frcP->frch_seg <= seg;
 
245
       frcP = *(lastPP = &frcP->frch_next))
 
246
    {
 
247
      if (frcP->frch_seg == seg
 
248
          && frcP->frch_subseg >= subseg)
 
249
        {
 
250
          break;
 
251
        }
 
252
    }
 
253
  /*
 
254
   * frcP:              Address of the 1st frchainS in correct segment with
 
255
   *            frch_subseg >= subseg.
 
256
   *            We want to either use this frchainS, or we want
 
257
   *            to insert a new frchainS just before it.
 
258
   *
 
259
   *            If frcP==NULL, then we are at the end of the chain
 
260
   *            of frchainS-s. A NULL frcP means we fell off the end
 
261
   *            of the chain looking for a
 
262
   *            frch_subseg >= subseg, so we
 
263
   *            must make a new frchainS.
 
264
   *
 
265
   *            If we ever maintain a pointer to
 
266
   *            the last frchainS in the chain, we change that pointer
 
267
   *            ONLY when frcP==NULL.
 
268
   *
 
269
   * lastPP:    Address of the pointer with value frcP;
 
270
   *            Never NULL.
 
271
   *            May point to frchain_root.
 
272
   *
 
273
   */
 
274
  if (!frcP
 
275
      || (frcP->frch_seg > seg
 
276
          || frcP->frch_subseg > subseg))       /* Kinky logic only works with 2 segments.  */
 
277
    {
 
278
      /*
 
279
       * This should be the only code that creates a frchainS.
 
280
       */
 
281
      newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS));
 
282
      newP->frch_subseg = subseg;
 
283
      newP->frch_seg = seg;
 
284
#ifdef BFD_ASSEMBLER
 
285
      newP->fix_root = NULL;
 
286
      newP->fix_tail = NULL;
 
287
#endif
 
288
      obstack_begin (&newP->frch_obstack, chunksize);
 
289
#if __GNUC__ >= 2
 
290
      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
 
291
#endif
 
292
      newP->frch_frag_now = frag_alloc (&newP->frch_obstack);
 
293
      newP->frch_frag_now->fr_type = rs_fill;
 
294
 
 
295
      newP->frch_root = newP->frch_last = newP->frch_frag_now;
 
296
 
 
297
      *lastPP = newP;
 
298
      newP->frch_next = frcP;   /* perhaps NULL */
 
299
 
 
300
#ifdef BFD_ASSEMBLER
 
301
      {
 
302
        segment_info_type *seginfo;
 
303
        seginfo = seg_info (seg);
 
304
        if (seginfo && seginfo->frchainP == frcP)
 
305
          seginfo->frchainP = newP;
 
306
      }
 
307
#endif
 
308
 
 
309
      frcP = newP;
 
310
    }
 
311
  /*
 
312
   * Here with frcP pointing to the frchainS for subseg.
 
313
   */
 
314
  frchain_now = frcP;
 
315
  frag_now = frcP->frch_frag_now;
 
316
 
 
317
  assert (frchain_now->frch_last == frag_now);
 
318
}
 
319
 
 
320
/*
 
321
 *                      subseg_set(segT, subsegT)
 
322
 *
 
323
 * If you attempt to change to the current subsegment, nothing happens.
 
324
 *
 
325
 * In:  segT, subsegT code for new subsegment.
 
326
 *      frag_now -> incomplete frag for current subsegment.
 
327
 *      If frag_now==NULL, then there is no old, incomplete frag, so
 
328
 *      the old frag is not closed off.
 
329
 *
 
330
 * Out: now_subseg, now_seg updated.
 
331
 *      Frchain_now points to the (possibly new) struct frchain for this
 
332
 *      sub-segment.
 
333
 *      Frchain_root updated if needed.
 
334
 */
 
335
 
 
336
#ifndef BFD_ASSEMBLER
 
337
 
 
338
segT
 
339
subseg_new (segname, subseg)
 
340
     const char *segname;
 
341
     subsegT subseg;
 
342
{
 
343
  int i;
 
344
 
 
345
  for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++)
 
346
    {
 
347
      const char *s;
 
348
 
 
349
      s = segment_name ((segT) i);
 
350
      if (strcmp (segname, s) == 0
 
351
          || (segname[0] == '.'
 
352
              && strcmp (segname + 1, s) == 0))
 
353
        {
 
354
          subseg_set ((segT) i, subseg);
 
355
          return (segT) i;
 
356
        }
 
357
#ifdef obj_segment_name
 
358
      s = obj_segment_name ((segT) i);
 
359
      if (strcmp (segname, s) == 0
 
360
          || (segname[0] == '.'
 
361
              && strcmp (segname + 1, s) == 0))
 
362
        {
 
363
          subseg_set ((segT) i, subseg);
 
364
          return (segT) i;
 
365
        }
 
366
#endif
 
367
    }
 
368
 
 
369
#ifdef obj_add_segment
 
370
  {
 
371
    segT new_seg;
 
372
    new_seg = obj_add_segment (segname);
 
373
    subseg_set (new_seg, subseg);
 
374
    return new_seg;
 
375
  }
 
376
#else
 
377
  as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname);
 
378
  return now_seg;
 
379
#endif
 
380
}
 
381
 
 
382
void
 
383
subseg_set (seg, subseg)        /* begin assembly for a new sub-segment */
 
384
     register segT seg;         /* SEG_DATA or SEG_TEXT */
 
385
     register subsegT subseg;
 
386
{
 
387
#ifndef MANY_SEGMENTS
 
388
  know (seg == SEG_DATA
 
389
        || seg == SEG_TEXT
 
390
        || seg == SEG_BSS
 
391
        || seg == SEG_ABSOLUTE);
 
392
#endif
 
393
 
 
394
  if (seg != now_seg || subseg != now_subseg)
 
395
    {                           /* we just changed sub-segments */
 
396
      subseg_set_rest (seg, subseg);
 
397
    }
 
398
  mri_common_symbol = NULL;
 
399
}
 
400
 
 
401
#else /* BFD_ASSEMBLER */
 
402
 
 
403
segT
 
404
subseg_get (segname, force_new)
 
405
     const char *segname;
 
406
     int force_new;
 
407
{
 
408
  segT secptr;
 
409
  segment_info_type *seginfo;
 
410
  const char *now_seg_name = (now_seg
 
411
                              ? bfd_get_section_name (stdoutput, now_seg)
 
412
                              : 0);
 
413
 
 
414
  if (!force_new
 
415
      && now_seg_name
 
416
      && (now_seg_name == segname
 
417
          || !strcmp (now_seg_name, segname)))
 
418
    return now_seg;
 
419
 
 
420
  if (!force_new)
 
421
    secptr = bfd_make_section_old_way (stdoutput, segname);
 
422
  else
 
423
    secptr = bfd_make_section_anyway (stdoutput, segname);
 
424
 
 
425
#ifdef obj_sec_set_private_data
 
426
  obj_sec_set_private_data (stdoutput, secptr);
 
427
#endif
 
428
 
 
429
  seginfo = seg_info (secptr);
 
430
  if (! seginfo)
 
431
    {
 
432
      /* Check whether output_section is set first because secptr may
 
433
         be bfd_abs_section_ptr.  */
 
434
      if (secptr->output_section != secptr)
 
435
        secptr->output_section = secptr;
 
436
      seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo));
 
437
      memset ((PTR) seginfo, 0, sizeof (*seginfo));
 
438
      seginfo->fix_root = NULL;
 
439
      seginfo->fix_tail = NULL;
 
440
      seginfo->bfd_section = secptr;
 
441
      if (secptr == bfd_abs_section_ptr)
 
442
        abs_seg_info = seginfo;
 
443
      else if (secptr == bfd_und_section_ptr)
 
444
        und_seg_info = seginfo;
 
445
      else
 
446
        bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo);
 
447
      seginfo->frchainP = NULL;
 
448
      seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL;
 
449
      seginfo->sym = NULL;
 
450
      seginfo->dot = NULL;
 
451
    }
 
452
  return secptr;
 
453
}
 
454
 
 
455
segT
 
456
subseg_new (segname, subseg)
 
457
     const char *segname;
 
458
     subsegT subseg;
 
459
{
 
460
  segT secptr;
 
461
  segment_info_type *seginfo;
 
462
 
 
463
  secptr = subseg_get (segname, 0);
 
464
  subseg_set_rest (secptr, subseg);
 
465
  seginfo = seg_info (secptr);
 
466
  if (! seginfo->frchainP)
 
467
    seginfo->frchainP = frchain_now;
 
468
  return secptr;
 
469
}
 
470
 
 
471
/* Like subseg_new, except a new section is always created, even if
 
472
   a section with that name already exists.  */
 
473
segT
 
474
subseg_force_new (segname, subseg)
 
475
     const char *segname;
 
476
     subsegT subseg;
 
477
{
 
478
  segT secptr;
 
479
  segment_info_type *seginfo;
 
480
 
 
481
  secptr = subseg_get (segname, 1);
 
482
  subseg_set_rest (secptr, subseg);
 
483
  seginfo = seg_info (secptr);
 
484
  if (! seginfo->frchainP)
 
485
    seginfo->frchainP = frchain_now;
 
486
  return secptr;
 
487
}
 
488
 
 
489
void
 
490
subseg_set (secptr, subseg)
 
491
     segT secptr;
 
492
     subsegT subseg;
 
493
{
 
494
  if (! (secptr == now_seg && subseg == now_subseg))
 
495
    subseg_set_rest (secptr, subseg);
 
496
  mri_common_symbol = NULL;
 
497
}
 
498
 
 
499
#ifndef obj_sec_sym_ok_for_reloc
 
500
#define obj_sec_sym_ok_for_reloc(SEC)   0
 
501
#endif
 
502
 
 
503
/* Get the gas information we are storing for a section.  */
 
504
 
 
505
segment_info_type *
 
506
seg_info (sec)
 
507
     segT sec;
 
508
{
 
509
  if (sec == bfd_abs_section_ptr)
 
510
    return abs_seg_info;
 
511
  else if (sec == bfd_und_section_ptr)
 
512
    return und_seg_info;
 
513
  else
 
514
    return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec);
 
515
}
 
516
 
 
517
symbolS *
 
518
section_symbol (sec)
 
519
     segT sec;
 
520
{
 
521
  segment_info_type *seginfo = seg_info (sec);
 
522
  symbolS *s;
 
523
 
 
524
  if (seginfo == 0)
 
525
    abort ();
 
526
  if (seginfo->sym)
 
527
    return seginfo->sym;
 
528
 
 
529
#ifndef EMIT_SECTION_SYMBOLS
 
530
#define EMIT_SECTION_SYMBOLS 1
 
531
#endif
 
532
 
 
533
  if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen)
 
534
    {
 
535
      /* Here we know it won't be going into the symbol table.  */
 
536
      s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag);
 
537
    }
 
538
  else
 
539
    {
 
540
      s = symbol_find_base (sec->symbol->name, 0);
 
541
      if (s == NULL)
 
542
        s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag);
 
543
      else
 
544
        {
 
545
          if (S_GET_SEGMENT (s) == undefined_section)
 
546
            {
 
547
              S_SET_SEGMENT (s, sec);
 
548
              symbol_set_frag (s, &zero_address_frag);
 
549
            }
 
550
        }
 
551
    }
 
552
 
 
553
  S_CLEAR_EXTERNAL (s);
 
554
 
 
555
  /* Use the BFD section symbol, if possible.  */
 
556
  if (obj_sec_sym_ok_for_reloc (sec))
 
557
    symbol_set_bfdsym (s, sec->symbol);
 
558
  else
 
559
    symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
 
560
 
 
561
  seginfo->sym = s;
 
562
  return s;
 
563
}
 
564
 
 
565
#endif /* BFD_ASSEMBLER */
 
566
 
 
567
/* Return whether the specified segment is thought to hold text.  */
 
568
 
 
569
#ifndef BFD_ASSEMBLER
 
570
const char * const nontext_section_names[] = {
 
571
  ".eh_frame",
 
572
  ".gcc_except_table",
 
573
#ifdef OBJ_COFF
 
574
#ifndef COFF_LONG_SECTION_NAMES
 
575
  ".eh_fram",
 
576
  ".gcc_exc",
 
577
#endif
 
578
#endif
 
579
  NULL
 
580
};
 
581
#endif /* ! BFD_ASSEMBLER */
 
582
 
 
583
int
 
584
subseg_text_p (sec)
 
585
     segT sec;
 
586
{
 
587
#ifdef BFD_ASSEMBLER
 
588
  return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0;
 
589
#else /* ! BFD_ASSEMBLER */
 
590
  const char * const *p;
 
591
 
 
592
  if (sec == data_section || sec == bss_section || sec == absolute_section)
 
593
    return 0;
 
594
 
 
595
  for (p = nontext_section_names; *p != NULL; ++p)
 
596
    {
 
597
      if (strcmp (segment_name (sec), *p) == 0)
 
598
        return 0;
 
599
 
 
600
#ifdef obj_segment_name
 
601
      if (strcmp (obj_segment_name (sec), *p) == 0)
 
602
        return 0;
 
603
#endif
 
604
    }
 
605
 
 
606
  return 1;
 
607
 
 
608
#endif /* ! BFD_ASSEMBLER */
 
609
}
 
610
 
 
611
void
 
612
subsegs_print_statistics (file)
 
613
     FILE *file;
 
614
{
 
615
  frchainS *frchp;
 
616
  fprintf (file, "frag chains:\n");
 
617
  for (frchp = frchain_root; frchp; frchp = frchp->frch_next)
 
618
    {
 
619
      int count = 0;
 
620
      fragS *fragp;
 
621
 
 
622
      /* If frch_subseg is non-zero, it's probably been chained onto
 
623
         the end of a previous subsection.  Don't count it again.  */
 
624
      if (frchp->frch_subseg != 0)
 
625
        continue;
 
626
 
 
627
      /* Skip gas-internal sections.  */
 
628
      if (segment_name (frchp->frch_seg)[0] == '*')
 
629
        continue;
 
630
 
 
631
      for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
 
632
        {
 
633
#if 0
 
634
          switch (fragp->fr_type)
 
635
            {
 
636
            case rs_fill:
 
637
              fprintf (file, "f"); break;
 
638
            case rs_align:
 
639
              fprintf (file, "a"); break;
 
640
            case rs_align_code:
 
641
              fprintf (file, "c"); break;
 
642
            case rs_org:
 
643
              fprintf (file, "o"); break;
 
644
            case rs_machine_dependent:
 
645
              fprintf (file, "m"); break;
 
646
            case rs_space:
 
647
              fprintf (file, "s"); break;
 
648
            case 0:
 
649
              fprintf (file, "0"); break;
 
650
            default:
 
651
              fprintf (file, "?"); break;
 
652
            }
 
653
#endif
 
654
          count++;
 
655
        }
 
656
      fprintf (file, "\n");
 
657
      fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
 
658
               segment_name (frchp->frch_seg), count);
 
659
    }
 
660
}
 
661
 
 
662
/* end of subsegs.c */