Coverage Report

Created: 2025-06-24 06:45

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