Coverage Report

Created: 2026-03-10 08:46

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
448
{
37
448
  if (prev != NULL)
38
448
    *prev = NULL;
39
40
  /* The properties are supposed to be sorted in the list.  */
41
495
  for (elf_property_list *n = l; n != NULL; n = n->next)
42
128
    {
43
128
      if (type == n->property.pr_type)
44
50
  return n;
45
78
      else if (type < n->property.pr_type)
46
31
  break;
47
47
      else if (prev != NULL)
48
47
  *prev = n;
49
128
    }
50
398
  return NULL;
51
448
}
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
398
{
59
398
  if (l == NULL) // First node.
60
337
    return what;
61
62
61
  if (prev == NULL) // Prepend.
63
28
    {
64
28
      what->next = l;
65
28
      return what;
66
28
    }
67
68
33
  what->next = prev->next;
69
33
  prev->next = what;
70
33
  return l;
71
61
}
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
448
{
99
448
  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
100
0
    {
101
      /* Never should happen.  */
102
0
      abort ();
103
0
    }
104
105
448
  elf_property_list *prev;
106
448
  elf_property_list *p =
107
448
    _bfd_elf_find_property (elf_properties (abfd), type, &prev);
108
448
  if (p != NULL)  /* Reuse the existing entry.  */
109
50
    {
110
50
      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
50
      return &p->property;
116
50
    }
117
118
398
  p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p));
119
398
  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
398
  memset (p, 0, sizeof (*p));
127
398
  p->property.pr_type = type;
128
398
  p->property.pr_datasz = datasz;
129
130
398
  elf_properties (abfd) =
131
398
    _bfd_elf_insert_property (elf_properties (abfd), p, prev);
132
133
398
  return &p->property;
134
398
}
135
136
/* Parse GNU properties.  */
137
138
bool
139
_bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note)
140
558
{
141
558
  elf_backend_data *bed = get_elf_backend_data (abfd);
142
558
  unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
143
558
  bfd_byte *ptr = (bfd_byte *) note->descdata;
144
558
  bfd_byte *ptr_end = ptr + note->descsz;
145
146
558
  if (note->descsz < 8 || (note->descsz % align_size) != 0)
147
62
    {
148
62
    bad_size:
149
62
      _bfd_error_handler
150
62
  (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"),
151
62
   abfd, note->type, note->descsz);
152
62
      return false;
153
62
    }
154
155
1.74k
  while (ptr != ptr_end)
156
1.59k
    {
157
1.59k
      unsigned int type;
158
1.59k
      unsigned int datasz;
159
1.59k
      elf_property *prop;
160
161
1.59k
      if ((size_t) (ptr_end - ptr) < 8)
162
0
  goto bad_size;
163
164
1.59k
      type = bfd_h_get_32 (abfd, ptr);
165
1.59k
      datasz = bfd_h_get_32 (abfd, ptr + 4);
166
1.59k
      ptr += 8;
167
168
1.59k
      if (datasz > (size_t) (ptr_end - ptr))
169
156
  {
170
156
    _bfd_error_handler
171
156
      (_("warning: %pB: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x"),
172
156
       abfd, note->type, type, datasz);
173
    /* Clear all properties.  */
174
156
    elf_properties (abfd) = NULL;
175
156
    return false;
176
156
  }
177
178
1.44k
      if (type >= GNU_PROPERTY_LOPROC)
179
532
  {
180
532
    if (bed->elf_machine_code == EM_NONE)
181
168
      {
182
        /* Ignore processor-specific properties with generic ELF
183
     target vector.  They should be handled by the matching
184
     ELF target vector.  */
185
168
        goto next;
186
168
      }
187
364
    else if (type < GNU_PROPERTY_LOUSER
188
229
       && bed->parse_gnu_properties)
189
177
      {
190
177
        enum elf_property_kind kind
191
177
    = bed->parse_gnu_properties (abfd, type, ptr, datasz);
192
177
        if (kind == property_corrupt)
193
33
    {
194
      /* Clear all properties.  */
195
33
      elf_properties (abfd) = NULL;
196
33
      return false;
197
33
    }
198
144
        else if (kind != property_ignored)
199
32
    goto next;
200
177
      }
201
532
  }
202
910
      else
203
910
  {
204
910
    switch (type)
205
910
      {
206
135
      case GNU_PROPERTY_STACK_SIZE:
207
135
        if (datasz != align_size)
208
60
    {
209
60
      _bfd_error_handler
210
60
        (_("warning: %pB: corrupt stack size: 0x%x"),
211
60
         abfd, datasz);
212
      /* Clear all properties.  */
213
60
      elf_properties (abfd) = NULL;
214
60
      return false;
215
60
    }
216
75
        prop = _bfd_elf_get_property (abfd, type, datasz);
217
75
        if (datasz == 8)
218
75
    prop->u.number = bfd_h_get_64 (abfd, ptr);
219
0
        else
220
0
    prop->u.number = bfd_h_get_32 (abfd, ptr);
221
75
        prop->pr_kind = property_number;
222
75
        goto next;
223
224
123
      case GNU_PROPERTY_NO_COPY_ON_PROTECTED:
225
123
        if (datasz != 0)
226
44
    {
227
44
      _bfd_error_handler
228
44
        (_("warning: %pB: corrupt no copy on protected size: 0x%x"),
229
44
         abfd, datasz);
230
      /* Clear all properties.  */
231
44
      elf_properties (abfd) = NULL;
232
44
      return false;
233
44
    }
234
79
        prop = _bfd_elf_get_property (abfd, type, datasz);
235
79
        elf_has_no_copy_on_protected (abfd) = true;
236
79
        prop->pr_kind = property_number;
237
79
        goto next;
238
239
85
      case GNU_PROPERTY_MEMORY_SEAL:
240
85
        if (datasz != 0)
241
23
    {
242
23
      _bfd_error_handler
243
23
        (_("warning: %pB: corrupt memory sealing size: 0x%x"),
244
23
         abfd, datasz);
245
      /* Clear all properties.  */
246
23
      elf_properties (abfd) = NULL;
247
23
      return false;
248
23
    }
249
62
        prop = _bfd_elf_get_property (abfd, type, datasz);
250
62
        prop->pr_kind = property_number;
251
62
        goto next;
252
253
567
      default:
254
567
        if ((type >= GNU_PROPERTY_UINT32_AND_LO
255
110
       && type <= GNU_PROPERTY_UINT32_AND_HI)
256
507
      || (type >= GNU_PROPERTY_UINT32_OR_LO
257
50
          && type <= GNU_PROPERTY_UINT32_OR_HI))
258
99
    {
259
99
      if (datasz != 4)
260
37
        {
261
37
          _bfd_error_handler
262
37
      (_("error: %pB: <corrupt property (0x%x) size: 0x%x>"),
263
37
       abfd, type, datasz);
264
          /* Clear all properties.  */
265
37
          elf_properties (abfd) = NULL;
266
37
          return false;
267
37
        }
268
62
      prop = _bfd_elf_get_property (abfd, type, datasz);
269
62
      prop->u.number |= bfd_h_get_32 (abfd, ptr);
270
62
      prop->pr_kind = property_number;
271
62
      if (type == GNU_PROPERTY_1_NEEDED
272
25
          && ((prop->u.number
273
25
         & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
274
25
        != 0))
275
15
        {
276
15
          elf_has_indirect_extern_access (abfd) = true;
277
          /* GNU_PROPERTY_NO_COPY_ON_PROTECTED is implied.  */
278
15
          elf_has_no_copy_on_protected (abfd) = true;
279
15
        }
280
62
      goto next;
281
99
    }
282
468
        break;
283
910
      }
284
910
  }
285
286
767
      _bfd_error_handler
287
767
  (_("warning: %pB: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"),
288
767
   abfd, note->type, type);
289
290
1.24k
    next:
291
1.24k
      ptr += (datasz + (align_size - 1)) & ~ (align_size - 1);
292
1.24k
    }
293
294
143
  return true;
295
496
}
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
      size = (size + (align_size - 1)) & ~ (align_size - 1);
674
0
    }
675
0
}
676
677
static asection *
678
_bfd_elf_link_create_gnu_property_sec (struct bfd_link_info *info, bfd *elf_bfd,
679
               unsigned int elfclass)
680
0
{
681
0
  asection *sec;
682
683
0
  sec = bfd_make_section_with_flags (elf_bfd,
684
0
             NOTE_GNU_PROPERTY_SECTION_NAME,
685
0
             (SEC_ALLOC
686
0
              | SEC_LOAD
687
0
              | SEC_IN_MEMORY
688
0
              | SEC_READONLY
689
0
              | SEC_HAS_CONTENTS
690
0
              | SEC_DATA));
691
0
  if (sec == NULL
692
0
      || !bfd_set_section_alignment (sec, elfclass == ELFCLASS64 ? 3 : 2))
693
0
    info->callbacks->fatal (_("%P: failed to create %s\n"),
694
0
          NOTE_GNU_PROPERTY_SECTION_NAME);
695
696
0
  elf_section_type (sec) = SHT_NOTE;
697
0
  return sec;
698
0
}
699
700
/* Prune empty generic properties.  */
701
702
static void
703
elf_prune_empty_properties (elf_property_list **pp)
704
0
{
705
0
  elf_property_list *p;
706
707
0
  while ((p = *pp) != NULL)
708
0
    if ((p->property.pr_type < GNU_PROPERTY_LOPROC
709
0
   || p->property.pr_type >= GNU_PROPERTY_LOUSER)
710
0
  && p->property.pr_datasz != 0
711
0
  && p->property.pr_kind == property_number
712
0
  && p->property.u.number == 0)
713
0
      *pp = p->next;
714
0
    else
715
0
      pp = &p->next;
716
0
}
717
718
/* Set up GNU properties.  Return the first relocatable ELF input with
719
   GNU properties if found.  Otherwise, return NULL.  */
720
721
bfd *
722
_bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info)
723
0
{
724
0
  bfd *abfd, *first_pbfd = NULL, *elf_bfd = NULL;
725
0
  elf_property_list *list;
726
0
  asection *sec;
727
0
  bool has_properties = false;
728
0
  elf_backend_data *bed = get_elf_backend_data (info->output_bfd);
729
0
  unsigned int elfclass = bed->s->elfclass;
730
0
  int elf_machine_code = bed->elf_machine_code;
731
0
  elf_property *p;
732
733
  /* Find the first relocatable ELF input with GNU properties.  */
734
0
  for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
735
0
    if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
736
0
  && (abfd->flags & DYNAMIC) == 0
737
0
  && (elf_machine_code
738
0
      == get_elf_backend_data (abfd)->elf_machine_code)
739
0
  && (elfclass == get_elf_backend_data (abfd)->s->elfclass))
740
0
      {
741
  /* Ignore GNU properties from ELF objects with different machine
742
     code or class.  Also skip objects without a GNU_PROPERTY note
743
     section.  */
744
0
  elf_bfd = abfd;
745
746
0
  if (elf_properties (abfd) != NULL)
747
0
    {
748
0
      has_properties = true;
749
750
0
      if (bfd_get_section_by_name (abfd,
751
0
           NOTE_GNU_PROPERTY_SECTION_NAME)
752
0
    != NULL)
753
0
        {
754
    /* Keep .note.gnu.property section in FIRST_PBFD.  */
755
0
    first_pbfd = abfd;
756
0
    break;
757
0
        }
758
0
    }
759
0
      }
760
761
0
  if (info->indirect_extern_access > 0 && elf_bfd != NULL)
762
0
    {
763
      /* Support -z indirect-extern-access.  */
764
0
      if (first_pbfd == NULL)
765
0
  {
766
0
    sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass);
767
0
    first_pbfd = elf_bfd;
768
0
    has_properties = true;
769
0
  }
770
771
0
      p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_1_NEEDED, 4);
772
0
      if (p->pr_kind == property_unknown)
773
0
  {
774
    /* Create GNU_PROPERTY_1_NEEDED.  */
775
0
    p->u.number
776
0
      = GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
777
0
    p->pr_kind = property_number;
778
0
  }
779
0
      else
780
0
  p->u.number
781
0
    |= GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
782
0
    }
783
784
0
  if (elf_bfd != NULL)
785
0
    {
786
0
      if (info->memory_seal)
787
0
  {
788
    /* Support -z no-memory-seal.  */
789
0
    if (first_pbfd == NULL)
790
0
      {
791
0
        sec = _bfd_elf_link_create_gnu_property_sec (info, elf_bfd, elfclass);
792
0
        first_pbfd = elf_bfd;
793
0
        has_properties = true;
794
0
      }
795
796
0
    p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_MEMORY_SEAL, 0);
797
0
    if (p->pr_kind == property_unknown)
798
0
      {
799
        /* Create GNU_PROPERTY_NO_MEMORY_SEAL.  */
800
0
        p->u.number = GNU_PROPERTY_MEMORY_SEAL;
801
0
        p->pr_kind = property_number;
802
0
      }
803
0
  }
804
0
      else
805
0
  elf_find_and_remove_property (&elf_properties (elf_bfd),
806
0
              GNU_PROPERTY_MEMORY_SEAL, true);
807
0
    }
808
809
  /* Do nothing if there is no .note.gnu.property section.  */
810
0
  if (!has_properties)
811
0
    return NULL;
812
813
  /* Merge .note.gnu.property sections.  */
814
0
  info->callbacks->minfo (_("\n"));
815
0
  info->callbacks->minfo (_("Merging program properties\n"));
816
0
  info->callbacks->minfo (_("\n"));
817
818
0
  for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next)
819
0
    if (abfd != first_pbfd
820
0
  && (abfd->flags & (DYNAMIC | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0)
821
0
      {
822
0
  elf_property_list *null_ptr = NULL;
823
0
  elf_property_list **listp = &null_ptr;
824
825
  /* Merge .note.gnu.property section in relocatable ELF input.  */
826
0
  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
827
0
    {
828
0
      list = elf_properties (abfd);
829
830
      /* Ignore GNU properties from ELF objects with different
831
         machine code.  */
832
0
      if (list != NULL
833
0
    && (elf_machine_code
834
0
        == get_elf_backend_data (abfd)->elf_machine_code))
835
0
        listp = &elf_properties (abfd);
836
0
    }
837
0
  else
838
0
    list = NULL;
839
840
  /* Merge properties with FIRST_PBFD.  FIRST_PBFD can be NULL
841
     when all properties are from ELF objects with different
842
     machine code or class.  */
843
0
  if (first_pbfd != NULL)
844
0
    elf_merge_gnu_property_list (info, first_pbfd, abfd, listp);
845
846
0
  if (list != NULL)
847
0
    {
848
      /* Discard the .note.gnu.property section in this bfd.  */
849
0
      sec = bfd_get_section_by_name (abfd,
850
0
             NOTE_GNU_PROPERTY_SECTION_NAME);
851
0
      if (sec != NULL)
852
0
        sec->output_section = bfd_abs_section_ptr;
853
0
    }
854
0
      }
855
856
  /* Rewrite .note.gnu.property section so that GNU properties are
857
     always sorted by type even if input GNU properties aren't sorted.  */
858
0
  if (first_pbfd != NULL)
859
0
    {
860
0
      bfd_size_type size;
861
0
      bfd_byte *contents;
862
0
      unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4;
863
864
0
      sec = bfd_get_section_by_name (first_pbfd,
865
0
             NOTE_GNU_PROPERTY_SECTION_NAME);
866
0
      BFD_ASSERT (sec != NULL);
867
868
      /* Update stack size in .note.gnu.property with -z stack-size=N
869
   if N > 0.  */
870
0
      if (info->stacksize > 0)
871
0
  {
872
0
    bfd_vma stacksize = info->stacksize;
873
874
0
    p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE,
875
0
             align_size);
876
0
    if (p->pr_kind == property_unknown)
877
0
      {
878
        /* Create GNU_PROPERTY_STACK_SIZE.  */
879
0
        p->u.number = stacksize;
880
0
        p->pr_kind = property_number;
881
0
      }
882
0
    else if (stacksize > p->u.number)
883
0
      p->u.number = stacksize;
884
0
  }
885
0
      else if (elf_properties (first_pbfd) == NULL)
886
0
  {
887
    /* Discard .note.gnu.property section if all properties have
888
       been removed.  */
889
0
    sec->output_section = bfd_abs_section_ptr;
890
0
    return NULL;
891
0
  }
892
893
      /* Fix up GNU properties.  */
894
0
      if (bed->fixup_gnu_properties)
895
0
  bed->fixup_gnu_properties (info, &elf_properties (first_pbfd));
896
897
0
      if (info->indirect_extern_access <= 0)
898
0
  {
899
    /* Get GNU_PROPERTY_1_NEEDED properties.  */
900
0
    p = elf_find_and_remove_property (&elf_properties (first_pbfd),
901
0
              GNU_PROPERTY_1_NEEDED, false);
902
0
    if (p != NULL)
903
0
      {
904
0
        if (info->indirect_extern_access < 0)
905
0
    {
906
      /* Set indirect_extern_access to 1 to indicate that
907
         it is turned on by input properties.  */
908
0
      if ((p->u.number
909
0
           & GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS)
910
0
          != 0)
911
0
        info->indirect_extern_access = 1;
912
0
    }
913
0
        else
914
    /* Turn off indirect external access.  */
915
0
    p->u.number
916
0
      &= ~GNU_PROPERTY_1_NEEDED_INDIRECT_EXTERN_ACCESS;
917
0
      }
918
0
  }
919
920
0
      elf_prune_empty_properties (&elf_properties (first_pbfd));
921
922
0
      if (elf_properties (first_pbfd) == NULL)
923
0
  {
924
    /* Discard .note.gnu.property section if all properties have
925
       been removed.  */
926
0
    sec->output_section = bfd_abs_section_ptr;
927
0
    return NULL;
928
0
  }
929
930
      /* Compute the section size.  */
931
0
      list = elf_properties (first_pbfd);
932
0
      size = elf_get_gnu_property_section_size (list, align_size);
933
934
      /* Update .note.gnu.property section now.  */
935
0
      sec->size = size;
936
0
      contents = (bfd_byte *) bfd_zalloc (first_pbfd, size);
937
938
0
      elf_write_gnu_properties (info, first_pbfd, contents, list, size,
939
0
        align_size);
940
941
      /* Cache the section contents for elf_link_input_bfd.  */
942
0
      sec->alloced = 1;
943
0
      elf_section_data (sec)->this_hdr.contents = contents;
944
945
      /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data
946
   symbol is defined in the shared object.  */
947
0
      if (elf_has_no_copy_on_protected (first_pbfd))
948
0
  info->extern_protected_data = false;
949
950
0
      if (info->indirect_extern_access > 0)
951
0
  {
952
    /* For indirect external access, don't generate copy
953
       relocations.  NB: Set to nocopyreloc to 2 to indicate
954
       that it is implied by indirect_extern_access.  */
955
0
    info->nocopyreloc = 2;
956
0
    info->extern_protected_data = false;
957
0
  }
958
0
    }
959
960
0
  return first_pbfd;
961
0
}
962
963
/* Convert GNU property size.  */
964
965
bfd_size_type
966
_bfd_elf_convert_gnu_property_size (bfd *ibfd, bfd *obfd)
967
0
{
968
0
  unsigned int align_size;
969
0
  elf_backend_data *bed;
970
0
  elf_property_list *list = elf_properties (ibfd);
971
972
0
  bed = get_elf_backend_data (obfd);
973
0
  align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4;
974
975
  /* Get the output .note.gnu.property section size.  */
976
0
  return elf_get_gnu_property_section_size (list, align_size);
977
0
}
978
979
/* Convert GNU properties.  */
980
981
bool
982
_bfd_elf_convert_gnu_properties (bfd *ibfd, asection *isec,
983
         bfd *obfd, bfd_byte **ptr,
984
         bfd_size_type *ptr_size)
985
0
{
986
0
  unsigned int size;
987
0
  bfd_byte *contents;
988
0
  unsigned int align_shift;
989
0
  elf_backend_data *bed;
990
0
  elf_property_list *list = elf_properties (ibfd);
991
992
0
  bed = get_elf_backend_data (obfd);
993
0
  align_shift = bed->s->elfclass == ELFCLASS64 ? 3 : 2;
994
995
  /* Get the output .note.gnu.property section size.  */
996
0
  size = bfd_section_size (isec->output_section);
997
998
  /* Update the output .note.gnu.property section alignment.  */
999
0
  bfd_set_section_alignment (isec->output_section, align_shift);
1000
1001
0
  if (size > bfd_section_size (isec))
1002
0
    {
1003
0
      contents = (bfd_byte *) bfd_malloc (size);
1004
0
      if (contents == NULL)
1005
0
  return false;
1006
0
      free (*ptr);
1007
0
      *ptr = contents;
1008
0
    }
1009
0
  else
1010
0
    contents = *ptr;
1011
1012
0
  *ptr_size = size;
1013
1014
  /* Generate the output .note.gnu.property section.  */
1015
0
  elf_write_gnu_properties (NULL, ibfd, contents, list, size,
1016
0
          1 << align_shift);
1017
1018
  return true;
1019
0
}