1 /* ELF program property support.
2 Copyright (C) 2017 Free Software Foundation, Inc.
4 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
21 /* GNU program property draft is at:
23 https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf
31 /* Get a property, allocate a new one if needed. */
34 _bfd_elf_get_property (bfd
*abfd
, unsigned int type
, unsigned int datasz
)
36 elf_property_list
*p
, **lastp
;
38 if (bfd_get_flavour (abfd
) != bfd_target_elf_flavour
)
40 /* Never should happen. */
44 /* Keep the property list in order of type. */
45 lastp
= &elf_properties (abfd
);
46 for (p
= *lastp
; p
; p
= p
->next
)
48 /* Reuse the existing entry. */
49 if (type
== p
->property
.pr_type
)
51 if (datasz
> p
->property
.pr_datasz
)
53 /* This can happen when mixing 32-bit and 64-bit objects. */
54 p
->property
.pr_datasz
= datasz
;
58 else if (type
< p
->property
.pr_type
)
62 p
= (elf_property_list
*) bfd_alloc (abfd
, sizeof (*p
));
65 _bfd_error_handler (_("%B: out of memory in _bfd_elf_get_property"),
69 memset (p
, 0, sizeof (*p
));
70 p
->property
.pr_type
= type
;
71 p
->property
.pr_datasz
= datasz
;
77 /* Parse GNU properties. */
80 _bfd_elf_parse_gnu_properties (bfd
*abfd
, Elf_Internal_Note
*note
)
82 const struct elf_backend_data
*bed
= get_elf_backend_data (abfd
);
83 unsigned int align_size
= bed
->s
->elfclass
== ELFCLASS64
? 8 : 4;
84 bfd_byte
*ptr
= (bfd_byte
*) note
->descdata
;
85 bfd_byte
*ptr_end
= ptr
+ note
->descsz
;
87 if (note
->descsz
< 8 || (note
->descsz
% align_size
) != 0)
91 (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx\n"),
92 abfd
, note
->type
, note
->descsz
);
98 unsigned int type
= bfd_h_get_32 (abfd
, ptr
);
99 unsigned int datasz
= bfd_h_get_32 (abfd
, ptr
+ 4);
104 if ((ptr
+ datasz
) > ptr_end
)
107 (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x\n"),
108 abfd
, note
->type
, type
, datasz
);
109 /* Clear all properties. */
110 elf_properties (abfd
) = NULL
;
114 if (type
>= GNU_PROPERTY_LOPROC
)
116 if (type
< GNU_PROPERTY_LOUSER
&& bed
->parse_gnu_properties
)
118 enum elf_property_kind kind
119 = bed
->parse_gnu_properties (abfd
, type
, ptr
, datasz
);
120 if (kind
== property_corrupt
)
122 /* Clear all properties. */
123 elf_properties (abfd
) = NULL
;
126 else if (kind
!= property_ignored
)
134 case GNU_PROPERTY_STACK_SIZE
:
135 if (datasz
!= align_size
)
138 (_("warning: %B: corrupt stack size: 0x%x\n"),
140 /* Clear all properties. */
141 elf_properties (abfd
) = NULL
;
144 prop
= _bfd_elf_get_property (abfd
, type
, datasz
);
146 prop
->u
.number
= bfd_h_get_64 (abfd
, ptr
);
148 prop
->u
.number
= bfd_h_get_32 (abfd
, ptr
);
149 prop
->pr_kind
= property_number
;
152 case GNU_PROPERTY_NO_COPY_ON_PROTECTED
:
156 (_("warning: %B: corrupt no copy on protected size: 0x%x\n"),
158 /* Clear all properties. */
159 elf_properties (abfd
) = NULL
;
162 prop
= _bfd_elf_get_property (abfd
, type
, datasz
);
163 prop
->pr_kind
= property_number
;
172 (_("warning: %B: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x\n"),
173 abfd
, note
->type
, type
);
176 ptr
+= (datasz
+ (align_size
- 1)) & ~ (align_size
- 1);
180 if (ptr
> (ptr_end
- 8))
187 /* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE
188 if APROP is updated. Otherwise, return TRUE if BPROP should be merged
192 elf_merge_gnu_properties (bfd
*abfd
, elf_property
*aprop
,
195 const struct elf_backend_data
*bed
= get_elf_backend_data (abfd
);
196 unsigned int pr_type
= aprop
!= NULL
? aprop
->pr_type
: bprop
->pr_type
;
198 if (bed
->merge_gnu_properties
!= NULL
199 && pr_type
>= GNU_PROPERTY_LOPROC
200 && pr_type
< GNU_PROPERTY_LOUSER
)
201 return bed
->merge_gnu_properties (abfd
, aprop
, bprop
);
205 case GNU_PROPERTY_STACK_SIZE
:
206 if (aprop
!= NULL
&& bprop
!= NULL
)
208 if (bprop
->u
.number
> aprop
->u
.number
)
210 aprop
->u
.number
= bprop
->u
.number
;
217 case GNU_PROPERTY_NO_COPY_ON_PROTECTED
:
218 /* Return TRUE if APROP is NULL to indicate that BPROP should
220 return aprop
== NULL
;
223 /* Never should happen. */
230 /* Return the property of TYPE on *LISTP and remove it from *LISTP.
231 Return NULL if not found. */
233 static elf_property
*
234 elf_find_and_remove_property (elf_property_list
**listp
,
237 elf_property_list
*list
;
239 for (list
= *listp
; list
; list
= list
->next
)
241 if (type
== list
->property
.pr_type
)
243 /* Remove this property. */
245 return &list
->property
;
247 else if (type
< list
->property
.pr_type
)
255 /* Merge GNU property list *LISTP with ABFD. */
258 elf_merge_gnu_property_list (bfd
*abfd
, elf_property_list
**listp
)
260 elf_property_list
*p
, **lastp
;
263 /* Merge each GNU property in ABFD with the one on *LISTP. */
264 lastp
= &elf_properties (abfd
);
265 for (p
= *lastp
; p
; p
= p
->next
)
267 pr
= elf_find_and_remove_property (listp
, p
->property
.pr_type
);
268 /* Pass NULL to elf_merge_gnu_properties for the property which
270 elf_merge_gnu_properties (abfd
, &p
->property
, pr
);
271 if (p
->property
.pr_kind
== property_remove
)
273 /* Remove this property. */
280 /* Merge the remaining properties on *LISTP with ABFD. */
281 for (p
= *listp
; p
!= NULL
; p
= p
->next
)
282 if (elf_merge_gnu_properties (abfd
, NULL
, &p
->property
))
284 pr
= _bfd_elf_get_property (abfd
, p
->property
.pr_type
,
285 p
->property
.pr_datasz
);
286 /* It must be a new property. */
287 if (pr
->pr_kind
!= property_unknown
)
289 /* Add a new property. */
294 /* Set up GNU properties. */
297 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info
*info
)
299 bfd
*abfd
, *first_pbfd
= NULL
;
300 elf_property_list
*list
;
302 bfd_boolean has_properties
= FALSE
;
303 const struct elf_backend_data
*bed
304 = get_elf_backend_data (info
->output_bfd
);
305 unsigned int elfclass
= bed
->s
->elfclass
;
306 int elf_machine_code
= bed
->elf_machine_code
;
308 /* Find the first relocatable ELF input with GNU properties. */
309 for (abfd
= info
->input_bfds
; abfd
!= NULL
; abfd
= abfd
->link
.next
)
310 if (bfd_get_flavour (abfd
) == bfd_target_elf_flavour
311 && bfd_count_sections (abfd
) != 0
312 && elf_properties (abfd
) != NULL
)
314 has_properties
= TRUE
;
316 /* Ignore GNU properties from ELF objects with different machine
318 if ((elf_machine_code
319 == get_elf_backend_data (abfd
)->elf_machine_code
)
321 == get_elf_backend_data (abfd
)->s
->elfclass
))
323 /* Keep .note.gnu.property section in FIRST_PBFD. */
329 /* Do nothing if there is no .note.gnu.property section. */
333 /* Merge .note.gnu.property sections. */
334 for (abfd
= info
->input_bfds
; abfd
!= NULL
; abfd
= abfd
->link
.next
)
335 if (abfd
!= first_pbfd
&& bfd_count_sections (abfd
) != 0)
337 elf_property_list
*null_ptr
= NULL
;
338 elf_property_list
**listp
= &null_ptr
;
340 /* Merge .note.gnu.property section in relocatable ELF input. */
341 if (bfd_get_flavour (abfd
) == bfd_target_elf_flavour
)
343 list
= elf_properties (abfd
);
345 /* Ignore GNU properties from ELF objects with different
349 == get_elf_backend_data (abfd
)->elf_machine_code
))
350 listp
= &elf_properties (abfd
);
355 /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL
356 when all properties are from ELF objects with different
357 machine code or class. */
358 if (first_pbfd
!= NULL
)
359 elf_merge_gnu_property_list (first_pbfd
, listp
);
363 /* Discard .note.gnu.property section in the rest inputs. */
364 sec
= bfd_get_section_by_name (abfd
,
365 NOTE_GNU_PROPERTY_SECTION_NAME
);
366 sec
->output_section
= bfd_abs_section_ptr
;
370 /* Rewrite .note.gnu.property section so that GNU properties are
371 always sorted by type even if input GNU properties aren't sorted. */
372 if (first_pbfd
!= NULL
)
377 Elf_External_Note
*e_note
;
378 unsigned int align_size
= bed
->s
->elfclass
== ELFCLASS64
? 8 : 4;
380 sec
= bfd_get_section_by_name (first_pbfd
,
381 NOTE_GNU_PROPERTY_SECTION_NAME
);
383 /* Update stack size in .note.gnu.property with -z stack-size=N
385 if (info
->stacksize
> 0)
388 bfd_vma stacksize
= info
->stacksize
;
390 p
= _bfd_elf_get_property (first_pbfd
, GNU_PROPERTY_STACK_SIZE
,
392 if (p
->pr_kind
== property_unknown
)
394 /* Create GNU_PROPERTY_STACK_SIZE. */
395 p
->u
.number
= stacksize
;
396 p
->pr_kind
= property_number
;
398 else if (stacksize
> p
->u
.number
)
399 p
->u
.number
= stacksize
;
401 else if (elf_properties (first_pbfd
) == NULL
)
403 /* Discard .note.gnu.property section if all properties have
405 sec
->output_section
= bfd_abs_section_ptr
;
409 /* Compute the section size. */
410 descsz
= offsetof (Elf_External_Note
, name
[sizeof "GNU"]);
411 descsz
= (descsz
+ 3) & -(unsigned int) 4;
413 for (list
= elf_properties (first_pbfd
);
417 /* There are 4 byte type + 4 byte datasz for each property. */
418 size
+= 4 + 4 + list
->property
.pr_datasz
;
419 /* Align each property. */
420 size
= (size
+ (align_size
- 1)) & ~(align_size
- 1);
423 /* Update .note.gnu.property section now. */
425 contents
= (bfd_byte
*) bfd_zalloc (first_pbfd
, size
);
427 e_note
= (Elf_External_Note
*) contents
;
428 bfd_h_put_32 (first_pbfd
, sizeof "GNU", &e_note
->namesz
);
429 bfd_h_put_32 (first_pbfd
, size
- descsz
, &e_note
->descsz
);
430 bfd_h_put_32 (first_pbfd
, NT_GNU_PROPERTY_TYPE_0
, &e_note
->type
);
431 memcpy (e_note
->name
, "GNU", sizeof "GNU");
434 for (list
= elf_properties (first_pbfd
);
438 /* There are 4 byte type + 4 byte datasz for each property. */
439 bfd_h_put_32 (first_pbfd
, list
->property
.pr_type
,
441 bfd_h_put_32 (first_pbfd
, list
->property
.pr_datasz
,
442 contents
+ size
+ 4);
445 /* Write out property value. */
446 switch (list
->property
.pr_kind
)
448 case property_number
:
449 switch (list
->property
.pr_datasz
)
452 /* Never should happen. */
459 bfd_h_put_32 (first_pbfd
, list
->property
.u
.number
,
464 bfd_h_put_64 (first_pbfd
, list
->property
.u
.number
,
471 /* Never should happen. */
474 size
+= list
->property
.pr_datasz
;
476 /* Align each property. */
477 size
= (size
+ (align_size
- 1)) & ~ (align_size
- 1);
480 /* Cache the section contents for elf_link_input_bfd. */
481 elf_section_data (sec
)->this_hdr
.contents
= contents
;