Coverage Report

Created: 2026-09-14 08:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/gas/subsegs.c
Line
Count
Source
1
/* subsegs.c - subsegments -
2
   Copyright (C) 1987-2026 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 3, 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 the Free
18
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19
   02110-1301, USA.  */
20
21
/* Segments & sub-segments.  */
22
23
#include "as.h"
24
25
#include "subsegs.h"
26
#include "obstack.h"
27
28
frchainS *frchain_now;
29
30
static struct obstack frchains;
31
32
static fragS dummy_frag;
33
34

35
void
36
subsegs_begin (void)
37
339
{
38
339
  obstack_begin (&frchains, chunksize);
39
339
#if __GNUC__ >= 2
40
339
  obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1;
41
339
#endif
42
43
339
  frchain_now = NULL;   /* Warn new_subseg() that we are booting.  */
44
339
  frag_now = &dummy_frag;
45
339
}
46
47
void
48
subsegs_end (struct obstack **obs)
49
339
{
50
339
  if (!ENABLE_LEAK_CHECK)
51
0
    return;
52
4.46k
  for (; *obs; obs++)
53
4.12k
    _obstack_free (*obs, NULL);
54
339
  _obstack_free (&frchains, NULL);
55
339
  bfd_set_section_userdata (bfd_com_section_ptr, NULL);
56
339
  bfd_set_section_userdata (bfd_und_section_ptr, NULL);
57
339
  bfd_set_section_userdata (bfd_abs_section_ptr, NULL);
58
339
  bfd_set_section_userdata (bfd_ind_section_ptr, NULL);
59
  /* Reverse bfd_std_section_init, so the sections look as they did
60
     initially.  This, and clearing out userdata above, is so we don't
61
     leave dangling pointers into freed memory for oss-fuzz to mess
62
     with.  */
63
339
  asymbol *global_syms = bfd_com_section_ptr->symbol;
64
339
  bfd_und_section_ptr->used_by_bfd = NULL;
65
339
  bfd_und_section_ptr->symbol = global_syms + (bfd_und_section_ptr
66
339
                 - bfd_com_section_ptr);
67
339
  bfd_abs_section_ptr->used_by_bfd = NULL;
68
339
  bfd_abs_section_ptr->symbol = global_syms + (bfd_abs_section_ptr
69
339
                 - bfd_com_section_ptr);
70
339
}
71

72
static void
73
alloc_seginfo (segT seg)
74
4.10k
{
75
4.10k
  segment_info_type *seginfo;
76
77
4.10k
  seginfo = obstack_alloc (&notes, sizeof (*seginfo));
78
4.10k
  memset (seginfo, 0, sizeof (*seginfo));
79
4.10k
  bfd_set_section_userdata (seg, seginfo);
80
4.10k
}
81
/*
82
 *      subseg_change()
83
 *
84
 * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the
85
 * subsegment. If we are already in the correct subsegment, change nothing.
86
 * This is used eg as a worker for subseg_set [which does make a new frag_now]
87
 * and for changing segments after we have read the source. We construct eg
88
 * fixSs even after the source file is read, so we do have to keep the
89
 * segment context correct.
90
 */
91
void
92
subseg_change (segT seg, int subseg)
93
6.04k
{
94
6.04k
  now_seg = seg;
95
6.04k
  now_subseg = subseg;
96
97
6.04k
  if (!seg_info (seg))
98
0
    alloc_seginfo (seg);
99
6.04k
}
100

101
static void
102
subseg_set_rest (segT seg, subsegT subseg)
103
6.04k
{
104
6.04k
  frchainS *frcP;   /* crawl frchain chain */
105
6.04k
  frchainS **lastPP;    /* address of last pointer */
106
6.04k
  frchainS *newP;   /* address of new frchain */
107
6.04k
  segment_info_type *seginfo;
108
109
6.04k
  mri_common_symbol = NULL;
110
111
6.04k
  if (frag_now && frchain_now)
112
5.70k
    frchain_now->frch_frag_now = frag_now;
113
114
6.04k
  gas_assert (frchain_now == 0
115
6.04k
    || frchain_now->frch_last == frag_now);
116
117
6.04k
  subseg_change (seg, (int) subseg);
118
119
6.04k
  seginfo = seg_info (seg);
120
121
  /* Should the section symbol be kept?  */
122
6.04k
  if (bfd_keep_unused_section_symbols (stdoutput))
123
0
    seg->symbol->flags |= BSF_SECTION_SYM_USED;
124
125
  /* Attempt to find or make a frchain for that subsection.
126
     We keep the list sorted by subsection number.  */
127
6.04k
  for (frcP = *(lastPP = &seginfo->frchainP);
128
6.08k
       frcP != NULL;
129
6.04k
       frcP = *(lastPP = &frcP->frch_next))
130
1.96k
    if (frcP->frch_subseg >= subseg)
131
1.92k
      break;
132
133
6.04k
  if (frcP == NULL || frcP->frch_subseg != subseg)
134
4.12k
    {
135
      /* This should be the only code that creates a frchainS.  */
136
137
4.12k
      newP = obstack_alloc (&frchains, sizeof (frchainS));
138
4.12k
      newP->frch_subseg = subseg;
139
4.12k
      newP->fix_root = NULL;
140
4.12k
      newP->fix_tail = NULL;
141
4.12k
      obstack_begin (&newP->frch_obstack, chunksize);
142
4.12k
#if __GNUC__ >= 2
143
4.12k
      obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1;
144
4.12k
#endif
145
4.12k
      newP->frch_frag_now = frag_alloc (&newP->frch_obstack, 0);
146
4.12k
      newP->frch_frag_now->fr_type = rs_fill;
147
4.12k
      newP->frch_cfi_data = NULL;
148
4.12k
      newP->frch_ginsn_data = NULL;
149
150
4.12k
      newP->frch_root = newP->frch_last = newP->frch_frag_now;
151
152
4.12k
      *lastPP = newP;
153
4.12k
      newP->frch_next = frcP;
154
4.12k
      frcP = newP;
155
4.12k
    }
156
157
6.04k
  frchain_now = frcP;
158
6.04k
  frag_now = frcP->frch_frag_now;
159
160
6.04k
  gas_assert (frchain_now->frch_last == frag_now);
161
6.04k
}
162
163
/*
164
 *      subseg_set(segT, subsegT)
165
 *
166
 * If you attempt to change to the current subsegment, nothing happens.
167
 *
168
 * In:  segT, subsegT code for new subsegment.
169
 *  frag_now -> incomplete frag for current subsegment.
170
 *  If frag_now==NULL, then there is no old, incomplete frag, so
171
 *  the old frag is not closed off.
172
 *
173
 * Out: now_subseg, now_seg updated.
174
 *  Frchain_now points to the (possibly new) struct frchain for this
175
 *  sub-segment.
176
 */
177
178
segT
179
subseg_get (const char *segname, int force_new)
180
4.40k
{
181
4.40k
  segT secptr;
182
4.40k
  const char *now_seg_name = now_seg ? bfd_section_name (now_seg) : 0;
183
184
4.40k
  if (!force_new
185
3.26k
      && now_seg_name
186
2.92k
      && (now_seg_name == segname
187
2.92k
    || !strcmp (now_seg_name, segname)))
188
0
    return now_seg;
189
190
4.40k
  if (!force_new)
191
3.26k
    secptr = bfd_make_section_old_way (stdoutput, segname);
192
1.13k
  else
193
1.13k
    secptr = bfd_make_section_anyway (stdoutput, segname);
194
195
4.40k
  if (!seg_info (secptr))
196
4.10k
    {
197
4.10k
      secptr->output_section = secptr;
198
4.10k
      alloc_seginfo (secptr);
199
4.10k
    }
200
4.40k
  return secptr;
201
4.40k
}
202
203
segT
204
subseg_new (const char *segname, subsegT subseg)
205
3.26k
{
206
3.26k
  segT secptr;
207
208
3.26k
  secptr = subseg_get (segname, 0);
209
3.26k
  subseg_set_rest (secptr, subseg);
210
3.26k
  return secptr;
211
3.26k
}
212
213
/* Like subseg_new, except a new section is always created, even if
214
   a section with that name already exists.  */
215
segT
216
subseg_force_new (const char *segname, subsegT subseg)
217
1.13k
{
218
1.13k
  segT secptr;
219
220
1.13k
  secptr = subseg_get (segname, 1);
221
1.13k
  subseg_set_rest (secptr, subseg);
222
1.13k
  return secptr;
223
1.13k
}
224
225
void
226
subseg_set (segT secptr, subsegT subseg)
227
32.5k
{
228
32.5k
  if (! (secptr == now_seg && subseg == now_subseg))
229
1.63k
    subseg_set_rest (secptr, subseg);
230
32.5k
  mri_common_symbol = NULL;
231
32.5k
}
232
233
#ifndef obj_sec_sym_ok_for_reloc
234
#define obj_sec_sym_ok_for_reloc(SEC) 0
235
#endif
236
237
symbolS *
238
section_symbol (segT sec)
239
2.26k
{
240
2.26k
  segment_info_type *seginfo = seg_info (sec);
241
2.26k
  symbolS *s;
242
243
2.26k
  if (seginfo == 0)
244
0
    abort ();
245
2.26k
  if (seginfo->sym)
246
35
    return seginfo->sym;
247
248
2.22k
#ifndef EMIT_SECTION_SYMBOLS
249
4.45k
#define EMIT_SECTION_SYMBOLS 1
250
2.22k
#endif
251
252
  /* A reference to the section (ie. an undefined symbol)
253
     should now become defined, but any other symbol that happens to
254
     have the same name as the section should not be modified.  Make
255
     sure an undefined_section symbol isn't equated to some other
256
     undefined symbol.  */
257
2.22k
  s = symbol_find (sec->symbol->name);
258
2.22k
  if (s == NULL
259
225
      || S_GET_SEGMENT (s) != undefined_section
260
0
      || !symbol_constant_p (s))
261
2.22k
    {
262
2.22k
      if (!EMIT_SECTION_SYMBOLS || symbol_table_frozen)
263
0
  s = symbol_create (sec->symbol->name, sec, &zero_address_frag, 0);
264
2.22k
      else
265
2.22k
  s = symbol_new (sec->symbol->name, sec, &zero_address_frag, 0);
266
2.22k
    }
267
0
  else
268
0
    S_SET_SEGMENT (s, sec);
269
270
2.22k
  S_CLEAR_EXTERNAL (s);
271
272
  /* Use the BFD section symbol, if possible.  */
273
2.22k
  if (obj_sec_sym_ok_for_reloc (sec))
274
2.22k
    symbol_set_bfdsym (s, sec->symbol);
275
1
  else
276
1
    symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM;
277
278
2.22k
  seginfo->sym = s;
279
2.22k
  return s;
280
2.26k
}
281
282
/* Return whether the specified segment is thought to hold text.  */
283
284
int
285
subseg_text_p (segT sec)
286
1.83k
{
287
1.83k
  return (bfd_section_flags (sec) & SEC_CODE) != 0;
288
1.83k
}
289
290
/* Return non zero if SEC has at least one byte of data.  It is
291
   possible that we'll return zero even on a non-empty section because
292
   we don't know all the fragment types, and it is possible that an
293
   fr_fix == 0 one still contributes data.  Think of this as
294
   seg_definitely_not_empty_p.  */
295
296
int
297
seg_not_empty_p (segT sec ATTRIBUTE_UNUSED)
298
2
{
299
2
  segment_info_type *seginfo = seg_info (sec);
300
2
  frchainS *chain;
301
2
  fragS *frag;
302
303
2
  if (!seginfo)
304
0
    return 0;
305
306
2
  for (chain = seginfo->frchainP; chain; chain = chain->frch_next)
307
2
    {
308
4
      for (frag = chain->frch_root; frag; frag = frag->fr_next)
309
2
  if (frag->fr_fix)
310
0
    return 1;
311
2
      if (obstack_next_free (&chain->frch_obstack)
312
2
    != chain->frch_last->fr_literal)
313
2
  return 1;
314
2
    }
315
0
  return 0;
316
2
}
317
318
void
319
subsegs_print_statistics (FILE *file)
320
0
{
321
0
  frchainS *frchp;
322
0
  asection *s;
323
324
  /* PR 20897 - check to see if the output bfd was actually created.  */
325
0
  if (stdoutput == NULL)
326
0
    return;
327
328
0
  fprintf (file, "frag chains:\n");
329
0
  for (s = stdoutput->sections; s; s = s->next)
330
0
    {
331
0
      segment_info_type *seginfo;
332
333
      /* Skip gas-internal sections.  */
334
0
      if (segment_name (s)[0] == '*')
335
0
  continue;
336
337
0
      seginfo = seg_info (s);
338
0
      if (!seginfo)
339
0
  continue;
340
341
0
      for (frchp = seginfo->frchainP; frchp; frchp = frchp->frch_next)
342
0
  {
343
0
    int count = 0;
344
0
    fragS *fragp;
345
346
0
    for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next)
347
0
      count++;
348
349
0
    fprintf (file, "\n");
350
0
    fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp,
351
0
       segment_name (s), count);
352
0
  }
353
0
    }
354
0
}
355
356
/* end of subsegs.c */