Coverage Report

Created: 2026-05-11 07:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/bfd/elf-properties.c
Line
Count
Source
1
/* ELF program property support.
2
   Copyright (C) 2017-2026 Free Software Foundation, Inc.
3
4
   This file is part of BFD, the Binary File Descriptor library.
5
6
   This program 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 of the License, or
9
   (at your option) any later version.
10
11
   This program 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 this program; if not, write to the Free Software
18
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19
   MA 02110-1301, USA.  */
20
21
/* GNU program property draft is at:
22
23
   https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf
24
 */
25
26
#include "sysdep.h"
27
#include "bfd.h"
28
#include "libbfd.h"
29
#include "elf-bfd.h"
30
31
/* Find a property.  */
32
elf_property_list *
33
_bfd_elf_find_property (elf_property_list *l,
34
      unsigned int type,
35
      elf_property_list **prev)
36
418
{
37
418
  if (prev != NULL)
38
418
    *prev = NULL;
39
40
  /* The properties are supposed to be sorted in the list.  */
41
450
  for (elf_property_list *n = l; n != NULL; n = n->next)
42
120
    {
43
120
      if (type == n->property.pr_type)
44
43
  return n;
45
77
      else if (type < n->property.pr_type)
46
45
  break;
47
32
      else if (prev != NULL)
48
32
  *prev = n;
49
120
    }
50
375
  return NULL;
51
418
}
52
53
/* Insert a property into the list after prev.  */
54
static elf_property_list *
55
_bfd_elf_insert_property (elf_property_list *l,
56
        elf_property_list *what,
57
        elf_property_list *prev)
58
375
{
59
375
  if (l == NULL) // First node.
60
316
    return what;
61
62
59
  if (prev == NULL) // Prepend.
63
39
    {
64
39
      what->next = l;
65
39
      return what;
66
39
    }
67
68
20
  what->next = prev->next;
69
20
  prev->next = what;
70
20
  return l;
71
59
}
72
73
/* Remove a property from the list after prev.  */
74
static elf_property_list *
75
_bfd_elf_remove_property (elf_property_list *l,
76
        elf_property_list *what,
77
        elf_property_list *prev)
78
0
{
79
0
  if (l == NULL)
80
0
    return l;
81
82
0
  if (prev == NULL) // Pop front
83
0
    {
84
0
      BFD_ASSERT (what == l);
85
0
      l = what->next;
86
0
    }
87
0
  else
88
0
    prev->next = what->next;
89
90
0
  what->next = NULL;
91
0
  return l;
92
0
}
93
94
/* Get a property, allocate a new one if needed.  */
95
96
elf_property *
97
_bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz)
98
418
{
99
418
  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
100
0
    {
101
      /* Never should happen.  */
102
0
      abort ();
103
0
    }
104
105
418
  elf_property_list *prev;
106
418
  elf_property_list *p =
107
418
    _bfd_elf_find_property (elf_properties (abfd), type, &prev);
108
418
  if (p != NULL)  /* Reuse the existing entry.  */
109
43
    {
110
43
      if (datasz > p->property.pr_datasz)
111
0
  {
112
    /* This can happen when mixing 32-bit and 64-bit objects.  */
113
0
    p->property.pr_datasz = datasz;
114
0
  }
115
43
      return &p->property;
116
43
    }
117
118
375
  p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p));
119
375
  if (p == NULL)
120
0
    {
121
0
      _bfd_error_handler (_("%pB: out of memory in _bfd_elf_get_property"),
122
0
        abfd);
123
0
      _exit (EXIT_FAILURE);
124
0
    }
125
126
375
  memset (p, 0, sizeof (*p));
127
375
  p->property.pr_type = type;
128
375
  p->property.pr_datasz = datasz;
129
130
375
  elf_properties (abfd) =
131
375
    _bfd_elf_insert_property (elf_properties (abfd), p, prev);
132
133
375
  return &p->property;
134
375
}
135
136
/* Parse GNU properties.  */
137
138
bool
139
_bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
140
362
{
141
362
  elf_backend_data *bed = get_elf_backend_data (abfd);
142
362
  unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
143
362
  bfd_byte *ptr = (bfd_byte *) note->descdata;
144
362
  bfd_byte *ptr_end = ptr + note->descsz;
145
146
362
  if (note->descsz < 8 || (note->descsz % align_size) != 0)
147
52
    {
148
52
    bad_size:
149
52
      _bfd_error_handler
150
52
  (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"),
151
52
   abfd, note->type, note->descsz);
152
52
      return false;
153
52
    }
154
155
1.22k
  while (ptr != ptr_end)
156
1.12k
    {
157
1.12k
      unsigned int type;
158
1.12k
      unsigned int datasz;
159
1.12k
      elf_property *prop;
160
161
1.12k
      if ((size_t) (ptr_end - ptr) < 8)
162
0
  goto bad_size;
163
164
1.12k
      type = bfd_h_get_32 (abfd, ptr);
165
1.12k
      datasz = bfd_h_get_32 (abfd, ptr + 4);
166
1.12k
      ptr += 8;
167
168
1.12k
      if (datasz > (size_t) (ptr_end - ptr))
169
105
  {
170
105
    _bfd_error_handler
171
105
      (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x"),
172
105
       abfd, note->type, type, datasz);
173
    /* Clear all properties.  */
174
105
    elf_properties (abfd) = NULL;
175
105
    return false;
176
105
  }
177
178
1.02k
      if (type >= GNU_PROPERTY_LOPROC)
179
355
  {
180
355
    if (bed->elf_machine_code == EM_NONE)
181
98
      {
182
        /* Ignore processor-specific properties with generic ELF
183
     target vector.  They should be handled by the matching
184
     ELF target vector.  */
185
98
        goto next;
186
98
      }
187
257
    else if (type < GNU_PROPERTY_LOUSER
188
139
       && bed->parse_gnu_properties)
189
125
      {
190
125
        enum elf_property_kind kind
191
125
    = bed->parse_gnu_properties (abfd, type, ptr, datasz);
192
125
        if (kind == property_corrupt)
193
32
    {
194
      /* Clear all properties.  */
195
32
      elf_properties (abfd) = NULL;
196
32
      return false;
197
32
    }
198
93
        else if (kind != property_ignored)
199
24
    goto next;
200
125
      }
201
355
  }
202
668
      else
203
668
  {
204
668
    switch (type)
205
668
      {
206
111
      case GNU_PROPERTY_STACK_SIZE:
207
111
        if (datasz != align_size)
208
37
    {
209
37
      _bfd_error_handler
210
37
        (_("warning: %pB: corrupt stack size: 0x%x"),
211
37
         abfd, datasz);
212
      /* Clear all properties.  */
213
37
      elf_properties (abfd) = NULL;
214
37
      return false;
215
37
    }
216
74
        prop = _bfd_elf_get_property (abfd, type, datasz);
217
74
        if (datasz == 8)
218
74
    prop->u.number = bfd_h_get_64 (abfd, ptr);
219
0
        else
220
0
    prop->u.number = bfd_h_get_32 (abfd, ptr);
221
74
        prop->pr_kind = property_number;
222
74
        goto next;
223
224
75
      case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
225
75
        if (datasz != 0)
226
12
    {
227
12
      _bfd_error_handler
228
12
        (_("warning: %pB: corrupt no copy on protected size: 0x%x"),
229
12
         abfd, datasz);
230
      /* Clear all properties.  */
231
12
      elf_properties (abfd) = NULL;
232
12
      return false;
233
12
    }
234
63
        prop = _bfd_elf_get_property (abfd, type, datasz);
235
63
        elf_has_no_copy_on_protected (abfd) = true;
236
63
        prop->pr_kind = property_number;
237
63
        goto next;
238
239
76
      case GNU_PROPERTY_MEMORY_SEAL:
240
76
        if (datasz != 0)
241
18
    {
242
18
      _bfd_error_handler
243
18
        (_("warning: %pB: corrupt memory sealing size: 0x%x"),
244
18
         abfd, datasz);
245
      /* Clear all properties.  */
246
18
      elf_properties (abfd) = NULL;
247
18
      return false;
248
18
    }
249
58
        prop = _bfd_elf_get_property (abfd, type, datasz);
250
58
        prop->pr_kind = property_number;
251
58
        goto next;
252
253
406
      default:
254
406
        if ((type >= GNU_PROPERTY_UINT32_AND_LO
255
59
       && type <= GNU_PROPERTY_UINT32_AND_HI)
256
391
      || (type >= GNU_PROPERTY_UINT32_OR_LO
257
44
          && type <= GNU_PROPERTY_UINT32_OR_HI))
258
55
    {
259
55
      if (datasz != 4)
260
13
        {
261
13
          _bfd_error_handler
262
13
      (_("error: %pB: <corrupt property (0x%x) size: 0x%x>"),
263
13
       abfd, type, datasz);
264
          /* Clear all properties.  */
265
13
          elf_properties (abfd) = NULL;
266
13
          return false;
267
13
        }
268
42
      prop = _bfd_elf_get_property (abfd, type, datasz);
269
42
      prop->u.number |= bfd_h_get_32 (abfd, ptr);
270
42
      prop->pr_kind = property_number;
271
42
      if (type == GNU_PROPERTY_1_NEEDED
272
28
          && ((prop->u.number
273
28
         & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
274
28
        != 0))
275
18
        {
276
18
          elf_has_indirect_extern_access (abfd) = true;
277
          /* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied.  */
278
18
          elf_has_no_copy_on_protected (abfd) = true;
279
18
        }
280
42
      goto next;
281
55
    }
282
351
        break;
283
668
      }
284
668
  }
285
286
552
      _bfd_error_handler
287
552
  (_("warning: %pB: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"),
288
552
   abfd, note->type, type);
289
290
911
    next:
291
911
      ptr += (datasz + (align_size - 1)) & ~ (align_size - 1);
292
911
    }
293
294
93
  return true;
295
310
}
296
297
/* Merge GNU property BPROP with APROP.  If APROP isn't NULL, return TRUE
298
   if APROP is updated.  Otherwise, return TRUE if BPROP should be merged
299
   with ABFD.  */
300
301
static bool
302
elf_merge_gnu_properties (struct bfd_link_info *info, bfd *abfd, bfd *bbfd,
303
        elf_property *aprop, elf_property *bprop)
304
0
{
305
0
  elf_backend_data *bed = get_elf_backend_data (abfd);
306
0
  unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type;
307
0
  unsigned int number;
308
0
  bool updated;
309
310
0
  if (bed->merge_gnu_properties != NULL
311
0
      && pr_type >= GNU_PROPERTY_LOPROC
312
0
      && pr_type < GNU_PROPERTY_LOUSER)
313
0
    return bed->merge_gnu_properties (info, abfd, bbfd, aprop, bprop);
314
315
0
  switch (pr_type)
316
0
    {
317
0
    case GNU_PROPERTY_STACK_SIZE:
318
0
      if (aprop != NULL && bprop != NULL)
319
0
  {
320
0
    if (bprop->u.number > aprop->u.number)
321
0
      {
322
0
        aprop->u.number = bprop->u.number;
323
0
        return true;
324
0
      }
325
0
    break;
326
0
  }
327
      /* FALLTHROUGH */
328
329
0
    case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
330
0
    case GNU_PROPERTY_MEMORY_SEAL:
331
      /* Return TRUE if APROP is NULL to indicate that BPROP should
332
   be added to ABFD.  */
333
0
      return aprop == NULL;
334
335
0
    default:
336
0
      updated = false;
337
0
      if (pr_type >= GNU_PROPERTY_UINT32_OR_LO
338
0
    && pr_type <= GNU_PROPERTY_UINT32_OR_HI)
339
0
  {
340
0
    if (aprop != NULL && bprop != NULL)
341
0
      {
342
0
        number = aprop->u.number;
343
0
        aprop->u.number = number | bprop->u.number;
344
        /* Remove the property if all bits are empty.  */
345
0
        if (aprop->u.number == 0)
346
0
    {
347
0
      aprop->pr_kind = property_remove;
348
0
      updated = true;
349
0
    }
350
0
        else
351
0
    updated = number != (unsigned int) aprop->u.number;
352
0
      }
353
0
    else
354
0
      {
355
        /* Only one of APROP and BPROP can be NULL.  */
356
0
        if (aprop != NULL)
357
0
    {
358
0
      if (aprop->u.number == 0)
359
0
        {
360
          /* Remove APROP if all bits are empty.  */
361
0
          aprop->pr_kind = property_remove;
362
0
          updated = true;
363
0
        }
364
0
    }
365
0
        else
366
0
    {
367
      /* Return TRUE if APROP is NULL and all bits of BPROP
368
         aren't empty to indicate that BPROP should be added
369
         to ABFD.  */
370
0
      updated = bprop->u.number != 0;
371
0
    }
372
0
      }
373
0
    return updated;
374
0
  }
375
0
      else if (pr_type >= GNU_PROPERTY_UINT32_AND_LO
376
0
         && pr_type <= GNU_PROPERTY_UINT32_AND_HI)
377
0
  {
378
    /* Only one of APROP and BPROP can be NULL:
379
       1. APROP & BPROP when both APROP and BPROP aren't NULL.
380
       2. If APROP is NULL, remove x86 feature.
381
       3. Otherwise, do nothing.
382
       */
383
0
    if (aprop != NULL && bprop != NULL)
384
0
      {
385
0
        number = aprop->u.number;
386
0
        aprop->u.number = number & bprop->u.number;
387
0
        updated = number != (unsigned int) aprop->u.number;
388
        /* Remove the property if all feature bits are cleared.  */
389
0
        if (aprop->u.number == 0)
390
0
    aprop->pr_kind = property_remove;
391
0
      }
392
0
    else
393
0
      {
394
        /* There should be no AND properties since some input
395
           doesn't have them.   */
396
0
        if (aprop != NULL)
397
0
    {
398
0
      aprop->pr_kind = property_remove;
399
0
      updated = true;
400
0
    }
401
0
      }
402
0
    return updated;
403
0
  }
404
405
      /* Never should happen.  */
406
0
      abort ();
407
0
    }
408
409
0
  return false;
410
0
}
411
412
/* Return the property of TYPE on *LISTP and remove it from *LISTP if RM is
413
   true.  Return NULL if not found.  */
414
415
static elf_property *
416
elf_find_and_remove_property (elf_property_list **listp,
417
            unsigned int type, bool rm)
418
0
{
419
0
  elf_property_list *prev;
420
0
  elf_property_list *p = _bfd_elf_find_property (*listp, type, &prev);
421
0
  if (p == NULL)
422
0
    return NULL;
423
424
0
  if (rm)
425
0
    *listp = _bfd_elf_remove_property (*listp, p, prev);
426
427
  /* FIXME: we leak memory with this approach.  */
428
0
  return &p->property;
429
0
}
430
431
/* Merge GNU property list *LISTP in ABFD with FIRST_PBFD.  */
432
433
static void
434
elf_merge_gnu_property_list (struct bfd_link_info *info, bfd *first_pbfd,
435
           bfd *abfd, elf_property_list **listp)
436
0
{
437
0
  elf_property_list *p, **lastp;
438
0
  elf_property *pr;
439
0
  bool number_p;
440
0
  bfd_vma number = 0;
441
442
  /* Merge each GNU property in FIRST_PBFD with the one on *LISTP.  */
443
0
  lastp = &elf_properties (first_pbfd);
444
0
  for (p = *lastp; p; p = p->next)
445
0
    if (p->property.pr_kind != property_remove)
446
0
      {
447
0
  if (p->property.pr_kind == property_number)
448
0
    {
449
0
      number_p = true;
450
0
      number = p->property.u.number;
451
0
    }
452
0
  else
453
0
    number_p = false;
454
0
  pr = elf_find_and_remove_property (listp, p->property.pr_type,
455
0
             true);
456
  /* Pass NULL to elf_merge_gnu_properties for the property which
457
     isn't on *LISTP.  */
458
0
  elf_merge_gnu_properties (info, first_pbfd, abfd, &p->property, pr);
459
0
  if (p->property.pr_kind == property_remove)
460
0
    {
461
0
      if (info->has_map_file)
462
0
        {
463
0
    if (number_p)
464
0
      {
465
0
        if (pr != NULL)
466
0
          info->callbacks->minfo
467
0
      (_("Removed property %W to merge %pB (0x%v) "
468
0
         "and %pB (0x%v)\n"),
469
0
       (bfd_vma) p->property.pr_type, first_pbfd,
470
0
       number, abfd, pr->u.number);
471
0
        else
472
0
          info->callbacks->minfo
473
0
      (_("Removed property %W to merge %pB (0x%v) "
474
0
         "and %pB (not found)\n"),
475
0
       (bfd_vma) p->property.pr_type, first_pbfd,
476
0
       number, abfd);
477
0
      }
478
0
    else
479
0
      {
480
0
        if (pr != NULL)
481
0
          info->callbacks->minfo
482
0
      (_("Removed property %W to merge %pB and %pB\n"),
483
0
       (bfd_vma) p->property.pr_type, first_pbfd, abfd);
484
0
        else
485
0
          info->callbacks->minfo
486
0
      (_("Removed property %W to merge %pB and %pB "
487
0
         "(not found)\n"),
488
0
       (bfd_vma) p->property.pr_type, first_pbfd, abfd);
489
0
      }
490
0
        }
491
492
      /* Remove this property.  */
493
0
      *lastp = p->next;
494
0
      continue;
495
0
    }
496
0
  else if (number_p)
497
0
    {
498
0
      if (pr != NULL)
499
0
        {
500
0
    if (p->property.u.number != number
501
0
        || p->property.u.number != pr->u.number)
502
0
      info->callbacks->minfo
503
0
        (_("Updated property %W (0x%v) to merge %pB (0x%v) "
504
0
           "and %pB (0x%v)\n"),
505
0
         (bfd_vma) p->property.pr_type, p->property.u.number,
506
0
         first_pbfd, number, abfd, pr->u.number);
507
0
        }
508
0
      else
509
0
        {
510
0
    if (p->property.u.number != number)
511
0
      info->callbacks->minfo
512
0
        (_("Updated property %W (%v) to merge %pB (0x%v) "
513
0
           "and %pB (not found)\n"),
514
0
         (bfd_vma) p->property.pr_type, p->property.u.number,
515
0
         first_pbfd, number, abfd);
516
0
        }
517
0
    }
518
0
  lastp = &p->next;
519
0
      }
520
521
  /* Merge the remaining properties on *LISTP with FIRST_PBFD.  */
522
0
  for (p = *listp; p != NULL; p = p->next)
523
0
    {
524
0
      if (p->property.pr_kind == property_number)
525
0
  {
526
0
    number_p = true;
527
0
    number = p->property.u.number;
528
0
  }
529
0
      else
530
0
  number_p = false;
531
532
0
      if (elf_merge_gnu_properties (info, first_pbfd, abfd, NULL, &p->property))
533
0
  {
534
0
    if (p->property.pr_type == GNU_PROPERTY_NO_COPY_ON_PROTECTED)
535
0
      elf_has_no_copy_on_protected (first_pbfd) = true;
536
537
0
    pr = _bfd_elf_get_property (first_pbfd, p->property.pr_type,
538
0
              p->property.pr_datasz);
539
    /* It must be a new property.  */
540
0
    if (pr->pr_kind != property_unknown)
541
0
      abort ();
542
    /* Add a new property.  */
543
0
    *pr = p->property;
544
0
  }
545
0
      else
546
0
  {
547
0
    pr = elf_find_and_remove_property (&elf_properties (first_pbfd),
548
0
               p->property.pr_type,
549
0
               false);
550
0
    if (pr == NULL)
551
0
      {
552
0
        if (number_p)
553
0
    info->callbacks->minfo
554
0
      (_("Removed property %W to merge %pB (not found) and "
555
0
         "%pB (0x%v)\n"),
556
0
       (bfd_vma) p->property.pr_type, first_pbfd, abfd,
557
0
       number);
558
0
        else
559
0
    info->callbacks->minfo
560
0
      (_("Removed property %W to merge %pB and %pB\n"),
561
0
       (bfd_vma) p->property.pr_type, first_pbfd, abfd);
562
0
      }
563
0
    else if (pr->pr_kind != property_remove)
564
0
      abort ();
565
0
  }
566
0
    }
567
0
}
568
569
/* Get GNU property section size.  */
570
571
static bfd_size_type
572
elf_get_gnu_property_section_size (elf_property_list *list,
573
           unsigned int align_size)
574
0
{
575
0
  bfd_size_type size;
576
0
  unsigned int descsz;
577
578
  /* Compute the output section size.  */
579
0
  descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]);
580
0
  descsz = (descsz + 3) & -(unsigned int) 4;
581
0
  size = descsz;
582
0
  for (; list != NULL; list = list->next)
583
0
    {
584
0
      unsigned int datasz;
585
      /* Check if this property should be skipped.  */
586
0
      if (list->property.pr_kind == property_remove)
587
0
  continue;
588
      /* There are 4 byte type + 4 byte datasz for each property.  */
589
0
      if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE)
590
0
  datasz = align_size;
591
0
      else
592
0
  datasz = list->property.pr_datasz;
593
0
      size += 4 + 4 + datasz;
594
      /* Align each property.  */
595
0
      size = (size + (align_size - 1)) & ~(align_size - 1);
596
0
    }
597
598
0
  return size;
599
0
}
600
601
/* Write GNU properties.  */
602
603
static void
604
elf_write_gnu_properties (struct bfd_link_info *info,
605
        bfd *abfd, bfd_byte *contents,
606
        elf_property_list *list, unsigned int size,
607
        unsigned int align_size)
608
0
{
609
0
  unsigned int descsz;
610
0
  unsigned int datasz;
611
0
  Elf_External_Note *e_note;
612
613
0
  e_note = (Elf_External_Note *) contents;
614
0
  descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]);
615
0
  descsz = (descsz + 3) & -(unsigned int) 4;
616
0
  bfd_h_put_32 (abfd, sizeof "GNU", &e_note->namesz);
617
0
  bfd_h_put_32 (abfd, size - descsz, &e_note->descsz);
618
0
  bfd_h_put_32 (abfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type);
619
0
  memcpy (e_note->name, "GNU", sizeof "GNU");
620
621
0
  size = descsz;
622
0
  for (; list != NULL; list = list->next)
623
0
    {
624
      /* Check if this property should be skipped.  */
625
0
      if (list->property.pr_kind == property_remove)
626
0
  continue;
627
      /* There are 4 byte type + 4 byte datasz for each property.  */
628
0
      if (list->property.pr_type == GNU_PROPERTY_STACK_SIZE)
629
0
  datasz = align_size;
630
0
      else
631
0
  datasz = list->property.pr_datasz;
632
0
      bfd_h_put_32 (abfd, list->property.pr_type, contents + size);
633
0
      bfd_h_put_32 (abfd, datasz, contents + size + 4);
634
0
      size += 4 + 4;
635
636
      /* Write out property value.  */
637
0
      switch (list->property.pr_kind)
638
0
  {
639
0
  case property_number:
640
0
    switch (datasz)
641
0
      {
642
0
      default:
643
        /* Never should happen.  */
644
0
        abort ();
645
646
0
      case 0:
647
0
        break;
648
649
0
      case 4:
650
        /* Save the pointer to GNU_PROPERTY_1_NEEDED so that it
651
     can be updated later if needed.  */
652
0
        if (info != NULL
653
0
      && list->property.pr_type == GNU_PROPERTY_1_NEEDED)
654
0
    info->needed_1_p = contents + size;
655
0
        bfd_h_put_32 (abfd, list->property.u.number,
656
0
          contents + size);
657
0
        break;
658
659
0
      case 8:
660
0
        bfd_h_put_64 (abfd, list->property.u.number,
661
0
          contents + size);
662
0
        break;
663
0
      }
664
0
    break;
665
666
0
  default:
667
    /* Never should happen.  */
668
0
    abort ();
669
0
  }
670
0
      size += datasz;
671
672
      /* Align each property.  */
673
0
      datasz = -size & (align_size - 1);
674
0
      if (datasz)
675
0
  {
676
0
    memset (contents + size, 0, datasz);
677
0
    size += datasz;
678
0
  }
679
0
    }
680
0
}
681
682
static asection *
683
_bfd_elf_link_create_gnu_property_sec (struct bfd_link_info *info, bfd *elf_bfd,
684
               unsigned int elfclass)
685
0
{
686
0
  asection *sec;
687
688
0
  sec = bfd_make_section_with_flags (elf_bfd,
689
0
             NOTE_GNU_PROPERTY_SECTION_NAME,
690
0
             (SEC_ALLOC
691
0
              | SEC_LOAD
692
0
              | SEC_IN_MEMORY
693
0
              | SEC_READONLY
694
0
              | SEC_HAS_CONTENTS
695
0
              | SEC_DATA));
696
0
  if (sec == NULL
697
0
      || !bfd_set_section_alignment (sec, elfclass == ELFCLASS64 ? 3 : 2))
698
0
    info->callbacks->fatal (_("%P: failed to create %s\n"),
699
0
          NOTE_GNU_PROPERTY_SECTION_NAME);
700
701
0
  elf_section_type (sec) = SHT_NOTE;
702
0
  return sec;
703
0
}
704
705
/* Prune empty generic properties.  */
706
707
static void
708
elf_prune_empty_properties (elf_property_list **pp)
709
0
{
710
0
  elf_property_list *p;
711
712
0
  while ((p = *pp) != NULL)
713
0
    if ((p->property.pr_type < GNU_PROPERTY_LOPROC
714
0
   || p->property.pr_type >= GNU_PROPERTY_LOUSER)
715
0
  && p->property.pr_datasz != 0
716
0
  && p->property.pr_kind == property_number
717
0
  && p->property.u.number == 0)
718
0
      *pp = p->next;
719
0
    else
720
0
      pp = &p->next;
721
0
}
722
723
/* Set up GNU properties.  Return the first relocatable ELF input with
724
   GNU properties if found.  Otherwise, return NULL.  */
725
726
bfd *
727
_bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
728
0
{
729
0
  bfd *abfd, *first_pbfd = NULL, *elf_bfd = NULL;
730
0
  elf_property_list *list;
731
0
  asection *sec;
732
0
  bool has_properties = false;
733
0
  elf_backend_data *bed = get_elf_backend_data (info->output_bfd);
734
0
  unsigned int elfclass = bed->s->elfclass;
735
0
  int elf_machine_code = bed->elf_machine_code;
736
0
  elf_property *p;
737
738
  /* Find the first relocatable ELF input with GNU properties.  */
739
0
  for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
740
0
    if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
741
0
  && (abfd->flags & DYNAMIC) == 0
742
0
  && (elf_machine_code
743
0
      == get_elf_backend_data (abfd)->elf_machine_code)
744
0
  && (elfclass == get_elf_backend_data (abfd)->s->elfclass))
745
0
      {
746
  /* Ignore GNU properties from ELF objects with different machine
747
     code or class.  Also skip objects without a GNU_PROPERTY note
748
     section.  */
749
0
  elf_bfd = abfd;
750
751
0
  if (elf_properties (abfd) != NULL)
752
0
    {
753
0
      has_properties = true;
754
755
0
      if (bfd_get_section_by_name (abfd,
756
0
           NOTE_GNU_PROPERTY_SECTION_NAME)
757
0
    != NULL)
758
0
        {
759
    /* Keep .note.gnu.property section in FIRST_PBFD.  */
760
0
    first_pbfd = abfd;
761
0
    break;
762
0
        }
763
0
    }
764
0
      }
765
766
0
  if (info->indirect_extern_access > 0 && elf_bfd != NULL)
767
0
    {
768
      /* Support -z indirect-extern-access.  */
769
0
      if (first_pbfd == NULL)
770
0
  {
771
0
    sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass);
772
0
    first_pbfd = elf_bfd;
773
0
    has_properties = true;
774
0
  }
775
776
0
      p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_1_NEEDED, 4);
777
0
      if (p->pr_kind == property_unknown)
778
0
  {
779
    /* Create GNU_PROPERTY_1_NEEDED.  */
780
0
    p->u.number
781
0
      = GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
782
0
    p->pr_kind = property_number;
783
0
  }
784
0
      else
785
0
  p->u.number
786
0
    |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
787
0
    }
788
789
0
  if (elf_bfd != NULL)
790
0
    {
791
0
      if (info->memory_seal)
792
0
  {
793
    /* Support -z no-memory-seal.  */
794
0
    if (first_pbfd == NULL)
795
0
      {
796
0
        sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass);
797
0
        first_pbfd = elf_bfd;
798
0
        has_properties = true;
799
0
      }
800
801
0
    p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_MEMORY_SEAL, 0);
802
0
    if (p->pr_kind == property_unknown)
803
0
      {
804
        /* Create GNU_PROPERTY_NO_MEMORY_SEAL.  */
805
0
        p->u.number = GNU_PROPERTY_MEMORY_SEAL;
806
0
        p->pr_kind = property_number;
807
0
      }
808
0
  }
809
0
      else
810
0
  elf_find_and_remove_property (&elf_properties (elf_bfd),
811
0
              GNU_PROPERTY_MEMORY_SEAL, true);
812
0
    }
813
814
  /* Do nothing if there is no .note.gnu.property section.  */
815
0
  if (!has_properties)
816
0
    return NULL;
817
818
  /* Merge .note.gnu.property sections.  */
819
0
  info->callbacks->minfo (_("\n"));
820
0
  info->callbacks->minfo (_("Merging program properties\n"));
821
0
  info->callbacks->minfo (_("\n"));
822
823
0
  for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
824
0
    if (abfd != first_pbfd
825
0
  && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0)
826
0
      {
827
0
  elf_property_list *null_ptr = NULL;
828
0
  elf_property_list **listp = &null_ptr;
829
830
  /* Merge .note.gnu.property section in relocatable ELF input.  */
831
0
  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
832
0
    {
833
0
      list = elf_properties (abfd);
834
835
      /* Ignore GNU properties from ELF objects with different
836
         machine code.  */
837
0
      if (list != NULL
838
0
    && (elf_machine_code
839
0
        == get_elf_backend_data (abfd)->elf_machine_code))
840
0
        listp = &elf_properties (abfd);
841
0
    }
842
0
  else
843
0
    list = NULL;
844
845
  /* Merge properties with FIRST_PBFD.  FIRST_PBFD can be NULL
846
     when all properties are from ELF objects with different
847
     machine code or class.  */
848
0
  if (first_pbfd != NULL)
849
0
    elf_merge_gnu_property_list (info, first_pbfd, abfd, listp);
850
851
0
  if (list != NULL)
852
0
    {
853
      /* Discard the .note.gnu.property section in this bfd.  */
854
0
      sec = bfd_get_section_by_name (abfd,
855
0
             NOTE_GNU_PROPERTY_SECTION_NAME);
856
0
      if (sec != NULL)
857
0
        sec->output_section = bfd_abs_section_ptr;
858
0
    }
859
0
      }
860
861
  /* Rewrite .note.gnu.property section so that GNU properties are
862
     always sorted by type even if input GNU properties aren't sorted.  */
863
0
  if (first_pbfd != NULL)
864
0
    {
865
0
      bfd_size_type size;
866
0
      bfd_byte *contents;
867
0
      unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4;
868
869
0
      sec = bfd_get_section_by_name (first_pbfd,
870
0
             NOTE_GNU_PROPERTY_SECTION_NAME);
871
0
      BFD_ASSERT (sec != NULL);
872
873
      /* Update stack size in .note.gnu.property with -z stack-size=N
874
   if N > 0.  */
875
0
      if (info->stacksize > 0)
876
0
  {
877
0
    bfd_vma stacksize = info->stacksize;
878
879
0
    p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE,
880
0
             align_size);
881
0
    if (p->pr_kind == property_unknown)
882
0
      {
883
        /* Create GNU_PROPERTY_STACK_SIZE.  */
884
0
        p->u.number = stacksize;
885
0
        p->pr_kind = property_number;
886
0
      }
887
0
    else if (stacksize > p->u.number)
888
0
      p->u.number = stacksize;
889
0
  }
890
0
      else if (elf_properties (first_pbfd) == NULL)
891
0
  {
892
    /* Discard .note.gnu.property section if all properties have
893
       been removed.  */
894
0
    sec->output_section = bfd_abs_section_ptr;
895
0
    return NULL;
896
0
  }
897
898
      /* Fix up GNU properties.  */
899
0
      if (bed->fixup_gnu_properties)
900
0
  bed->fixup_gnu_properties (info, &elf_properties (first_pbfd));
901
902
0
      if (info->indirect_extern_access <= 0)
903
0
  {
904
    /* Get GNU_PROPERTY_1_NEEDED properties.  */
905
0
    p = elf_find_and_remove_property (&elf_properties (first_pbfd),
906
0
              GNU_PROPERTY_1_NEEDED, false);
907
0
    if (p != NULL)
908
0
      {
909
0
        if (info->indirect_extern_access < 0)
910
0
    {
911
      /* Set indirect_extern_access to 1 to indicate that
912
         it is turned on by input properties.  */
913
0
      if ((p->u.number
914
0
           & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
915
0
          != 0)
916
0
        info->indirect_extern_access = 1;
917
0
    }
918
0
        else
919
    /* Turn off indirect external access.  */
920
0
    p->u.number
921
0
      &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
922
0
      }
923
0
  }
924
925
0
      elf_prune_empty_properties (&elf_properties (first_pbfd));
926
927
0
      if (elf_properties (first_pbfd) == NULL)
928
0
  {
929
    /* Discard .note.gnu.property section if all properties have
930
       been removed.  */
931
0
    sec->output_section = bfd_abs_section_ptr;
932
0
    return NULL;
933
0
  }
934
935
      /* Compute the section size.  */
936
0
      list = elf_properties (first_pbfd);
937
0
      size = elf_get_gnu_property_section_size (list, align_size);
938
939
      /* Update .note.gnu.property section now.  */
940
0
      sec->size = size;
941
0
      contents = bfd_alloc (first_pbfd, size);
942
943
0
      elf_write_gnu_properties (info, first_pbfd, contents, list, size,
944
0
        align_size);
945
946
      /* Cache the section contents for elf_link_input_bfd.  */
947
0
      sec->alloced = 1;
948
0
      elf_section_data (sec)->this_hdr.contents = contents;
949
950
      /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data
951
   symbol is defined in the shared object.  */
952
0
      if (elf_has_no_copy_on_protected (first_pbfd))
953
0
  info->extern_protected_data = false;
954
955
0
      if (info->indirect_extern_access > 0)
956
0
  {
957
    /* For indirect external access, don't generate copy
958
       relocations.  NB: Set to nocopyreloc to 2 to indicate
959
       that it is implied by indirect_extern_access.  */
960
0
    info->nocopyreloc = 2;
961
0
    info->extern_protected_data = false;
962
0
  }
963
0
    }
964
965
0
  return first_pbfd;
966
0
}
967
968
/* Convert GNU property size.  */
969
970
bfd_size_type
971
_bfd_elf_convert_gnu_property_size (bfd *ibfd, bfd *obfd)
972
0
{
973
0
  unsigned int align_size;
974
0
  elf_backend_data *bed;
975
0
  elf_property_list *list = elf_properties (ibfd);
976
977
0
  bed = get_elf_backend_data (obfd);
978
0
  align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
979
980
  /* Get the output .note.gnu.property section size.  */
981
0
  return elf_get_gnu_property_section_size (list, align_size);
982
0
}
983
984
/* Convert GNU properties.  */
985
986
bool
987
_bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec,
988
         bfd *obfd, bfd_byte **ptr,
989
         bfd_size_type *ptr_size)
990
0
{
991
0
  unsigned int size;
992
0
  bfd_byte *contents;
993
0
  unsigned int align_shift;
994
0
  elf_backend_data *bed;
995
0
  elf_property_list *list = elf_properties (ibfd);
996
997
0
  bed = get_elf_backend_data (obfd);
998
0
  align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2;
999
1000
  /* Get the output .note.gnu.property section size.  */
1001
0
  size = bfd_section_size (isec->output_section);
1002
1003
  /* Update the output .note.gnu.property section alignment.  */
1004
0
  bfd_set_section_alignment (isec->output_section, align_shift);
1005
1006
0
  if (size > bfd_section_size (isec))
1007
0
    {
1008
0
      contents = (bfd_byte *) bfd_malloc (size);
1009
0
      if (contents == NULL)
1010
0
  return false;
1011
0
      free (*ptr);
1012
0
      *ptr = contents;
1013
0
    }
1014
0
  else
1015
0
    contents = *ptr;
1016
1017
0
  *ptr_size = size;
1018
1019
  /* Generate the output .note.gnu.property section.  */
1020
0
  elf_write_gnu_properties (NULL, ibfd, contents, list, size,
1021
0
          1 << align_shift);
1022
1023
  return true;
1024
0
}