/src/binutils-gdb/bfd/elf-attrs.c
Line | Count | Source |
1 | | /* ELF attributes support (based on ARM EABI attributes). |
2 | | Copyright (C) 2005-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 | | /* Design note regarding the merge of Object Attributes v2 during linkage |
22 | | |
23 | | Entry point: _bfd_elf_link_setup_object_attributes |
24 | | |
25 | | The linker is an "advanced" consumer of OAv2. After parsing, it deduplicates |
26 | | them, merges them, detects any compatibility issues, and finally translates |
27 | | them to GNU properties. |
28 | | |
29 | | ** Overall design |
30 | | |
31 | | The OAv2 processing pipeline follows a map-reduce pattern. Obviously, the |
32 | | actual processing in GNU ld is not multi-threaded, and the operations are not |
33 | | necessarily executed directly one after another. |
34 | | |
35 | | * Phase 1, map: successive per-file operations applied on the list of |
36 | | compatible input objects. |
37 | | 1. Parsing of the OAv2 section's data (also used by objcopy). |
38 | | 2. Translation of relevant GNU properties to OAv2. This is required for the |
39 | | backward-compatibility with input objects only marked using GNU |
40 | | properties. |
41 | | 3. Sorting of the subsections and object attributes. Further operations |
42 | | rely on the ordering to perform some optimization in the processing of |
43 | | the data. |
44 | | 4. Deduplication of subsections and object attributes, and detection of any |
45 | | conflict between duplicated subsections or tags. |
46 | | 5. Translation of relevant OAv2 to GNU properties for a forward |
47 | | -compatibility with the GNU properties merge. |
48 | | 6. Marking of unknown subsections to skip them during the merge (in |
49 | | phase 2), and to prune them before the output object's serialization |
50 | | (in phase 3). |
51 | | |
52 | | * Phase 2, reduce: OAv2 in input objects are merged together. |
53 | | 1. Gathering of "frozen" values (=coming from the command-line arguments) |
54 | | into a virtual read-only list of subsections and attributes. |
55 | | 2. Merging of OAv2 from an input file and the frozen input. |
56 | | 3. Merging of the results of step 2 together. Since the OAv2 merge is |
57 | | commutative and associative, it can be implemented as a reduce. |
58 | | However, GNU ld implements it as an accumulate because it does not |
59 | | support multithreading. |
60 | | Notes: the two merge phases also perform a marking of unsupported / invalid |
61 | | subsections and attributes. This marking can be used for debugging, and |
62 | | also more practically to drop unsupported optional subsections from the |
63 | | output. |
64 | | |
65 | | * Phase 3, finalization of the output. |
66 | | 1. Pruning of the unknown / unsupported / invalid subsections and |
67 | | attributes. |
68 | | 2. Serialization of OAv2 data (also used by objcopy). |
69 | | Notes: |
70 | | - There is no translation of the merged OAv2 to GNU properties at this |
71 | | stage, as the GNU properties merge process has already all the needed |
72 | | information (translated in step 5 of stage 1) to produce the GNU |
73 | | properties. |
74 | | - The GNU properties are currently required as the runtime linker does |
75 | | not understand OAv2 yet. |
76 | | - Phase 3 should also include a compatibility check between the final |
77 | | merge result of the current link unit and input shared objects. I opted |
78 | | for postponing this compatibility check, and GNU properties merge will |
79 | | take care of it as it already does. |
80 | | |
81 | | The Object Ottributes merge process must handle both optional and required |
82 | | subsections. It also treats the first merge of the frozen set specially, as |
83 | | the OAv2 list in the input BFD serves as the accumulator for subsequent |
84 | | merges. |
85 | | |
86 | | ** Optional subsections |
87 | | |
88 | | Optional subsections are processed as if merging two ordered sets — by |
89 | | iterating linearly through both, checking whether an element of a given |
90 | | ordinality is present in the opposite set, and adding it to the accumulator. |
91 | | The added diffuculty with subsections and attributes lies in the fact that |
92 | | missing elements have default values, and these must be merged with existing |
93 | | ones to produce the final value to be stored. |
94 | | |
95 | | ** Required subsections |
96 | | |
97 | | Required subsections are processed slightly differently from the optional |
98 | | subsections, as they cannot be pruned since they are mandatory, hence an |
99 | | error will be raised by the linker if it is not recognized. |
100 | | |
101 | | For now, the subsection for PAuth ABI is the only one use case, and no merge |
102 | | is applied on the values. The values simply need to match. |
103 | | This implementation choice might be challenged in the future if required |
104 | | subsections can have the same diversity as optional subsections. If the case |
105 | | arises, the refactoring to handle this new behavior should consist in adding |
106 | | a new merge policy MERGE-EQUAL, or something similar. Some "if required" |
107 | | should be added in the optional subsections merge logic to error on any |
108 | | missing elements, or mismatch, and messages should also be rephrased to point |
109 | | out that the error is for a required subsection. |
110 | | |
111 | | ** Important note regarding support for testing |
112 | | |
113 | | In order to test this generic logic, AArch64's use cases are not offering |
114 | | enough coverage, so a "GNU testing namespace" which corresponds to the name |
115 | | of the subsection was introduced. It follows the following pattern: |
116 | | gnu_testing_<XXXXXX>_MERGE_<POLICY> |
117 | | with: |
118 | | - <XXXXXX>: an arbitrary name for your testing subsection. |
119 | | - <POLICY>: the name of the merging policy to apply on the values in the |
120 | | subsection. The currently supported merge policy are: |
121 | | * _MERGE_AND: bitwise AND applied on numerical values. |
122 | | * _MERGE_OR: bitwise OR applied on numerical values. |
123 | | * _MERGE_ADD: concatenates strings together with a '+' in-between. |
124 | | Note: "_MERGE_ADD" does not make really sense, and will very likely never |
125 | | be used for a real merge. Its only purpose is to test the correct |
126 | | handling of merges with strings. |
127 | | Any subsection name matching neither names supported by the backend, nor |
128 | | following the pattern corresponding GNU testing namespace will be considered |
129 | | unknown and its status set to obj_attr_subsection_v2_unknown. This will have |
130 | | for consequence the pruning of this subsection. |
131 | | |
132 | | Additionally, the first two tags in gnu_testing namespace, GNUTestTag_0 and |
133 | | GNUTestTag_1, are known, and so have a name and can be initialized to the |
134 | | default value ('0' or NULL) depending on the encoding specified on the |
135 | | subsection. Any tags above 1 will be considered unknown, so will be default |
136 | | -initialized in the same way but its status will be set to obj_attr_v2_unknown. |
137 | | This behavior of the testing tags allows to test the pruning of unknown |
138 | | attributes. */ |
139 | | |
140 | | #include "sysdep.h" |
141 | | #include "bfd.h" |
142 | | #include "doubly-linked-list.h" |
143 | | #include "libiberty.h" |
144 | | #include "libbfd.h" |
145 | | #include "elf-bfd.h" |
146 | | |
147 | | /* Decode the encoded version number corresponding to the Object Attribute |
148 | | version. Return the version on success, UNSUPPORTED on failure. */ |
149 | | obj_attr_version_t |
150 | | _bfd_obj_attrs_version_dec (uint8_t encoded_version) |
151 | 2.39k | { |
152 | 2.39k | if (encoded_version == 'A') |
153 | 2.18k | return OBJ_ATTR_V1; |
154 | 204 | return OBJ_ATTR_VERSION_UNSUPPORTED; |
155 | 2.39k | } |
156 | | |
157 | | /* Encode the Object Attribute version into a byte. */ |
158 | | uint8_t |
159 | | _bfd_obj_attrs_version_enc (obj_attr_version_t version) |
160 | 0 | { |
161 | 0 | if (version == OBJ_ATTR_V1) |
162 | 0 | return 'A'; |
163 | 0 | abort (); |
164 | 0 | } |
165 | | |
166 | | /* Return the number of bytes needed by I in uleb128 format. */ |
167 | | static uint32_t |
168 | | uleb128_size (uint32_t i) |
169 | 0 | { |
170 | 0 | uint32_t size = 1; |
171 | 0 | while (i >= 0x80) |
172 | 0 | { |
173 | 0 | i >>= 7; |
174 | 0 | size++; |
175 | 0 | } |
176 | 0 | return size; |
177 | 0 | } |
178 | | |
179 | | /* Return TRUE if the attribute has the default value (0/""). */ |
180 | | static bool |
181 | | is_default_attr (obj_attribute *attr) |
182 | 0 | { |
183 | 0 | if (ATTR_TYPE_HAS_ERROR (attr->type)) |
184 | 0 | return true; |
185 | 0 | if (ATTR_TYPE_HAS_INT_VAL (attr->type) && attr->i != 0) |
186 | 0 | return false; |
187 | 0 | if (ATTR_TYPE_HAS_STR_VAL (attr->type) && attr->s && *attr->s) |
188 | 0 | return false; |
189 | 0 | if (ATTR_TYPE_HAS_NO_DEFAULT (attr->type)) |
190 | 0 | return false; |
191 | | |
192 | 0 | return true; |
193 | 0 | } |
194 | | |
195 | | /* Return the vendor name for a given object attributes section. */ |
196 | | static const char * |
197 | | obj_attr_v1_vendor_name (bfd *abfd, int vendor) |
198 | 0 | { |
199 | 0 | return (vendor == OBJ_ATTR_PROC |
200 | 0 | ? get_elf_backend_data (abfd)->obj_attrs_vendor |
201 | 0 | : "gnu"); |
202 | 0 | } |
203 | | |
204 | | /* Return the size of a single attribute. */ |
205 | | static bfd_vma |
206 | | obj_attr_v1_size (unsigned int tag, obj_attribute *attr) |
207 | 0 | { |
208 | 0 | bfd_vma size; |
209 | |
|
210 | 0 | if (is_default_attr (attr)) |
211 | 0 | return 0; |
212 | | |
213 | 0 | size = uleb128_size (tag); |
214 | 0 | if (ATTR_TYPE_HAS_INT_VAL (attr->type)) |
215 | 0 | size += uleb128_size (attr->i); |
216 | 0 | if (ATTR_TYPE_HAS_STR_VAL (attr->type)) |
217 | 0 | size += strlen ((char *)attr->s) + 1; |
218 | 0 | return size; |
219 | 0 | } |
220 | | |
221 | | /* Return the size of the object attributes section for VENDOR |
222 | | (OBJ_ATTR_PROC or OBJ_ATTR_GNU), or 0 if there are no attributes |
223 | | for that vendor to record and the vendor is OBJ_ATTR_GNU. */ |
224 | | static bfd_vma |
225 | | vendor_obj_attrs_v1_size (bfd *abfd, int vendor) |
226 | 0 | { |
227 | 0 | bfd_vma size; |
228 | 0 | obj_attribute *attr; |
229 | 0 | obj_attribute_list *list; |
230 | 0 | int i; |
231 | 0 | const char *vendor_name = obj_attr_v1_vendor_name (abfd, vendor); |
232 | |
|
233 | 0 | if (!vendor_name) |
234 | 0 | return 0; |
235 | | |
236 | 0 | attr = elf_known_obj_attributes (abfd)[vendor]; |
237 | 0 | size = 0; |
238 | 0 | for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) |
239 | 0 | size += obj_attr_v1_size (i, &attr[i]); |
240 | |
|
241 | 0 | for (list = elf_other_obj_attributes (abfd)[vendor]; |
242 | 0 | list; |
243 | 0 | list = list->next) |
244 | 0 | size += obj_attr_v1_size (list->tag, &list->attr); |
245 | | |
246 | | /* <size> <vendor_name> NUL 0x1 <size> */ |
247 | 0 | return (size |
248 | 0 | ? size + 10 + strlen (vendor_name) |
249 | 0 | : 0); |
250 | 0 | } |
251 | | |
252 | | static bfd_vma |
253 | | oav1_section_size (bfd *abfd) |
254 | 0 | { |
255 | 0 | bfd_vma size = 0; |
256 | 0 | size = vendor_obj_attrs_v1_size (abfd, OBJ_ATTR_PROC); |
257 | 0 | size += vendor_obj_attrs_v1_size (abfd, OBJ_ATTR_GNU); |
258 | 0 | if (size > 0) |
259 | 0 | size += sizeof (uint8_t); /* <format-version: uint8> */ |
260 | 0 | return size; |
261 | 0 | } |
262 | | |
263 | | /* Return the size of a single attribute. */ |
264 | | static bfd_vma |
265 | | oav2_attr_size (const obj_attr_v2_t *attr, obj_attr_encoding_v2_t type) |
266 | 0 | { |
267 | 0 | bfd_vma size = uleb128_size (attr->tag); |
268 | 0 | switch (type) |
269 | 0 | { |
270 | 0 | case OA_ENC_ULEB128: |
271 | 0 | size += uleb128_size (attr->val.uint); |
272 | 0 | break; |
273 | 0 | case OA_ENC_NTBS: |
274 | 0 | size += strlen (attr->val.string) + 1; /* +1 for '\0'. */ |
275 | 0 | break; |
276 | 0 | default: |
277 | 0 | abort (); |
278 | 0 | } |
279 | 0 | return size; |
280 | 0 | } |
281 | | |
282 | | /* Return the size of a subsection. */ |
283 | | static bfd_vma |
284 | | oav2_subsection_size (const obj_attr_subsection_v2_t *subsec) |
285 | 0 | { |
286 | 0 | bfd_vma size = sizeof (uint32_t); /* <subsection-length: uint32> */ |
287 | 0 | size += strlen (subsec->name) + 1; /* <subsection-name: NTBS> so +1 for '\0'. */ |
288 | 0 | size += 2 * sizeof (uint8_t); /* <optional: uint8> <encoding: uint8> */ |
289 | | /* <attribute>* */ |
290 | 0 | for (const obj_attr_v2_t *attr = subsec->first; |
291 | 0 | attr != NULL; |
292 | 0 | attr = attr->next) |
293 | 0 | size += oav2_attr_size (attr, subsec->encoding); |
294 | 0 | return size; |
295 | 0 | } |
296 | | |
297 | | /* Return the size of a object attributes section. */ |
298 | | static bfd_vma |
299 | | oav2_section_size (bfd *abfd) |
300 | 0 | { |
301 | 0 | const obj_attr_subsection_v2_t *subsec |
302 | 0 | = elf_obj_attr_subsections (abfd).first; |
303 | 0 | if (subsec == NULL) |
304 | 0 | return 0; |
305 | | |
306 | 0 | bfd_vma size = sizeof (uint8_t); /* <format-version: uint8> */ |
307 | 0 | for (; subsec != NULL; subsec = subsec->next) |
308 | 0 | size += oav2_subsection_size (subsec); |
309 | 0 | return size; |
310 | 0 | } |
311 | | |
312 | | /* Return the size of the object attributes section. */ |
313 | | bfd_vma |
314 | | bfd_elf_obj_attr_size (bfd *abfd) |
315 | 0 | { |
316 | 0 | obj_attr_version_t version = elf_obj_attr_version (abfd); |
317 | 0 | switch (version) |
318 | 0 | { |
319 | 0 | case OBJ_ATTR_V1: |
320 | 0 | return oav1_section_size (abfd); |
321 | 0 | case OBJ_ATTR_V2: |
322 | 0 | return oav2_section_size (abfd); |
323 | 0 | case OBJ_ATTR_VERSION_NONE: |
324 | 0 | return 0; |
325 | 0 | default: |
326 | 0 | abort (); |
327 | 0 | } |
328 | 0 | } |
329 | | |
330 | | /* Write VAL in uleb128 format to P, returning a pointer to the |
331 | | following byte. */ |
332 | | static bfd_byte * |
333 | | write_uleb128 (bfd_byte *p, uint32_t val) |
334 | 0 | { |
335 | 0 | bfd_byte c; |
336 | 0 | do |
337 | 0 | { |
338 | 0 | c = val & 0x7f; |
339 | 0 | val >>= 7; |
340 | 0 | if (val) |
341 | 0 | c |= 0x80; |
342 | 0 | *(p++) = c; |
343 | 0 | } |
344 | 0 | while (val); |
345 | 0 | return p; |
346 | 0 | } |
347 | | |
348 | | /* Write attribute ATTR to butter P, and return a pointer to the following |
349 | | byte. */ |
350 | | static bfd_byte * |
351 | | write_obj_attr_v1 (bfd_byte *p, unsigned int tag, obj_attribute *attr) |
352 | 0 | { |
353 | | /* Suppress default entries. */ |
354 | 0 | if (is_default_attr (attr)) |
355 | 0 | return p; |
356 | | |
357 | 0 | p = write_uleb128 (p, tag); |
358 | 0 | if (ATTR_TYPE_HAS_INT_VAL (attr->type)) |
359 | 0 | p = write_uleb128 (p, attr->i); |
360 | 0 | if (ATTR_TYPE_HAS_STR_VAL (attr->type)) |
361 | 0 | { |
362 | 0 | int len; |
363 | |
|
364 | 0 | len = strlen (attr->s) + 1; |
365 | 0 | memcpy (p, attr->s, len); |
366 | 0 | p += len; |
367 | 0 | } |
368 | |
|
369 | 0 | return p; |
370 | 0 | } |
371 | | |
372 | | /* Write the contents of the object attributes section (length SIZE) |
373 | | for VENDOR to CONTENTS. */ |
374 | | static void |
375 | | write_vendor_obj_attrs_v1 (bfd *abfd, bfd_byte *contents, bfd_vma size, |
376 | | int vendor) |
377 | 0 | { |
378 | 0 | bfd_byte *p; |
379 | 0 | obj_attribute *attr; |
380 | 0 | obj_attribute_list *list; |
381 | 0 | int i; |
382 | 0 | const char *vendor_name = obj_attr_v1_vendor_name (abfd, vendor); |
383 | 0 | size_t vendor_length = strlen (vendor_name) + 1; |
384 | |
|
385 | 0 | p = contents; |
386 | 0 | bfd_put_32 (abfd, size, p); |
387 | 0 | p += 4; |
388 | 0 | memcpy (p, vendor_name, vendor_length); |
389 | 0 | p += vendor_length; |
390 | 0 | *(p++) = Tag_File; |
391 | 0 | bfd_put_32 (abfd, size - 4 - vendor_length, p); |
392 | 0 | p += 4; |
393 | |
|
394 | 0 | attr = elf_known_obj_attributes (abfd)[vendor]; |
395 | 0 | for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) |
396 | 0 | { |
397 | 0 | unsigned int tag = i; |
398 | 0 | if (get_elf_backend_data (abfd)->obj_attrs_order) |
399 | 0 | tag = get_elf_backend_data (abfd)->obj_attrs_order (i); |
400 | 0 | p = write_obj_attr_v1 (p, tag, &attr[tag]); |
401 | 0 | } |
402 | |
|
403 | 0 | for (list = elf_other_obj_attributes (abfd)[vendor]; |
404 | 0 | list; |
405 | 0 | list = list->next) |
406 | 0 | p = write_obj_attr_v1 (p, list->tag, &list->attr); |
407 | 0 | } |
408 | | |
409 | | static void |
410 | | oav1_write_section (bfd *abfd, bfd_byte *buffer, bfd_vma size) |
411 | 0 | { |
412 | | /* This function should only be called for object attributes version 1. */ |
413 | 0 | BFD_ASSERT (elf_obj_attr_version (abfd) == OBJ_ATTR_V1); |
414 | |
|
415 | 0 | bfd_byte *p = buffer; |
416 | |
|
417 | 0 | const struct elf_backend_data *be = get_elf_backend_data (abfd); |
418 | | /* <format-version: uint8> */ |
419 | 0 | *(p++) = be->obj_attrs_version_enc (elf_obj_attr_version (abfd)); |
420 | |
|
421 | 0 | for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) |
422 | 0 | { |
423 | 0 | bfd_vma vendor_size = vendor_obj_attrs_v1_size (abfd, vendor); |
424 | 0 | if (vendor_size > 0) |
425 | 0 | write_vendor_obj_attrs_v1 (abfd, p, vendor_size, vendor); |
426 | 0 | p += vendor_size; |
427 | 0 | } |
428 | | |
429 | | /* We didn't overrun the buffer. */ |
430 | 0 | BFD_ASSERT (p <= buffer + size); |
431 | 0 | } |
432 | | |
433 | | static bfd_byte * |
434 | | oav2_write_attr (bfd_byte *p, |
435 | | const obj_attr_v2_t *attr, |
436 | | obj_attr_encoding_v2_t type) |
437 | 0 | { |
438 | 0 | p = write_uleb128 (p, attr->tag); |
439 | 0 | switch (type) |
440 | 0 | { |
441 | 0 | case OA_ENC_ULEB128: |
442 | 0 | p = write_uleb128 (p, attr->val.uint); |
443 | 0 | break; |
444 | 0 | case OA_ENC_NTBS: |
445 | | /* +1 for '\0'. */ |
446 | 0 | p = (bfd_byte *) stpcpy ((char *) p, attr->val.string) + 1; |
447 | 0 | break; |
448 | 0 | default: |
449 | 0 | abort (); |
450 | 0 | } |
451 | 0 | return p; |
452 | 0 | } |
453 | | |
454 | | static bfd_byte * |
455 | | oav2_write_subsection (bfd *abfd, |
456 | | const obj_attr_subsection_v2_t *subsec, |
457 | | bfd_byte *p) |
458 | 0 | { |
459 | | /* <subsection-length: uint32> */ |
460 | 0 | bfd_vma subsec_size = oav2_subsection_size (subsec); |
461 | 0 | bfd_put_32 (abfd, subsec_size, p); |
462 | 0 | p += sizeof (uint32_t); |
463 | | |
464 | | /* <vendor-name: NTBS> */ |
465 | 0 | size_t vendor_name_size = strlen (subsec->name) + 1; /* +1 for '\0'. */ |
466 | 0 | memcpy (p, subsec->name, vendor_name_size); |
467 | 0 | p += vendor_name_size; |
468 | | |
469 | | /* -- <vendor-data: bytes> -- */ |
470 | | /* <optional: uint8> */ |
471 | 0 | bfd_put_8 (abfd, subsec->optional, p); |
472 | 0 | ++p; |
473 | | /* <encoding: uint8> */ |
474 | 0 | bfd_put_8 (abfd, obj_attr_encoding_v2_to_u8 (subsec->encoding), p); |
475 | 0 | ++p; |
476 | | /* <attribute>* */ |
477 | 0 | for (const obj_attr_v2_t *attr = subsec->first; |
478 | 0 | attr != NULL; |
479 | 0 | attr = attr->next) |
480 | 0 | p = oav2_write_attr (p, attr, subsec->encoding); |
481 | 0 | return p; |
482 | 0 | } |
483 | | |
484 | | static bfd_vma |
485 | | oav2_write_section (bfd *abfd, bfd_byte *buffer, bfd_vma size) |
486 | 0 | { |
487 | | /* This function should only be called for object attributes version 2. */ |
488 | 0 | BFD_ASSERT (elf_obj_attr_version (abfd) == OBJ_ATTR_V2); |
489 | |
|
490 | 0 | bfd_vma section_size = oav2_section_size (abfd); |
491 | 0 | if (section_size == 0) |
492 | 0 | return 0; |
493 | | |
494 | 0 | bfd_byte *p = buffer; |
495 | |
|
496 | 0 | const struct elf_backend_data *be = get_elf_backend_data (abfd); |
497 | | /* <format-version: uint8> */ |
498 | 0 | *(p++) = be->obj_attrs_version_enc (elf_obj_attr_version (abfd)); |
499 | | |
500 | | /* [ <subsection-length: uint32> <vendor-name: NTBS> <vendor-data: bytes> ]* */ |
501 | 0 | for (const obj_attr_subsection_v2_t *subsec |
502 | 0 | = elf_obj_attr_subsections (abfd).first; |
503 | 0 | subsec != NULL; |
504 | 0 | subsec = subsec->next) |
505 | 0 | p = oav2_write_subsection (abfd, subsec, p); |
506 | | |
507 | | /* We didn't overrun the buffer. */ |
508 | 0 | BFD_ASSERT (p <= buffer + size); |
509 | | /* We wrote as many data as it was computed by |
510 | | vendor_section_obj_attr_using_subsections_size(). */ |
511 | 0 | BFD_ASSERT (section_size == (bfd_vma) (p - buffer)); |
512 | |
|
513 | 0 | return section_size; |
514 | 0 | } |
515 | | |
516 | | static void |
517 | | oav2_sort_subsections (obj_attr_subsection_list_t *plist) |
518 | 0 | { |
519 | 0 | for (obj_attr_subsection_v2_t *subsec = plist->first; |
520 | 0 | subsec != NULL; |
521 | 0 | subsec = subsec->next) |
522 | 0 | LINKED_LIST_MERGE_SORT (obj_attr_v2_t) (subsec, _bfd_elf_obj_attr_v2_cmp); |
523 | |
|
524 | 0 | LINKED_LIST_MERGE_SORT (obj_attr_subsection_v2_t) |
525 | 0 | (plist, _bfd_elf_obj_attr_subsection_v2_cmp); |
526 | 0 | } |
527 | | |
528 | | /* Write the contents of the object attributes section to CONTENTS. */ |
529 | | void |
530 | | bfd_elf_set_obj_attr_contents (bfd *abfd, bfd_byte *buffer, bfd_vma size) |
531 | 0 | { |
532 | 0 | if (! abfd->is_linker_output |
533 | 0 | && elf_obj_attr_version (abfd) == OBJ_ATTR_V2) |
534 | | /* Before dumping the data, sort subsections in alphabetical order, and |
535 | | attributes according to their tag in numerical order. This is useful |
536 | | for diagnostic tools so that they dump the same output even if the |
537 | | subsections or their attributes were not declared in the same order in |
538 | | different files. |
539 | | This sorting is only performed in the case of the assembler. In the |
540 | | case of the linker, the subsections and attributes are already sorted |
541 | | by the merge process. */ |
542 | 0 | oav2_sort_subsections (&elf_obj_attr_subsections (abfd)); |
543 | |
|
544 | 0 | obj_attr_version_t version = elf_obj_attr_version (abfd); |
545 | 0 | switch (version) |
546 | 0 | { |
547 | 0 | case OBJ_ATTR_V1: |
548 | 0 | oav1_write_section (abfd, buffer, size); |
549 | 0 | break; |
550 | 0 | case OBJ_ATTR_V2: |
551 | 0 | oav2_write_section (abfd, buffer, size); |
552 | 0 | break; |
553 | 0 | default: |
554 | 0 | abort (); |
555 | 0 | } |
556 | 0 | } |
557 | | |
558 | | /* The first two tags in gnu-testing namespace are known (from the perspective |
559 | | of GNU ld), and so have a name and can be initialized to the default value |
560 | | ('0' or NULL) depending on the encoding specified on the subsection. Any |
561 | | tags above 1 will be considered unknown, so will be default initialized in |
562 | | the same way but its status will be set to obj_attr_subsection_v2_unknown. |
563 | | If the tag is unknown, ld can drop it if it is inside an optional subsection, |
564 | | whereas ld will raise an error in a required subsection. |
565 | | Note: the array below has to be sorted by the tag's integer value. */ |
566 | | static const obj_attr_info_t known_attrs_gnu_testing[] = |
567 | | { |
568 | | { .tag = {"GNUTestTag_0", 0} }, |
569 | | { .tag = {"GNUTestTag_1", 1} }, |
570 | | }; |
571 | | |
572 | | /* List of known GNU subsections. |
573 | | Note: this array has to be sorted using the same criteria as in |
574 | | _bfd_elf_obj_attr_subsection_v2_cmp(). */ |
575 | | static const known_subsection_v2_t obj_attr_v2_known_gnu_subsections[] = |
576 | | { |
577 | | { |
578 | | /* Note: the currently set values for the subsection name, its optionality, |
579 | | and encoding are irrelevant for a testing subsection. These values are |
580 | | unused. This entry is only a placeholder for list of known GNU testing |
581 | | tags. */ |
582 | | .subsec_name = NULL, |
583 | | .known_attrs = known_attrs_gnu_testing, |
584 | | .optional = true, |
585 | | .encoding = OA_ENC_ULEB128, |
586 | | .len = ARRAY_SIZE (known_attrs_gnu_testing), |
587 | | }, |
588 | | /* Note for the future: GNU subsections can be added here below. */ |
589 | | }; |
590 | | |
591 | | /* Return True if the given subsection name is part of the reserved testing |
592 | | namespace, i.e. SUBSEC_NAME begins with "gnu-testing". */ |
593 | | static bool |
594 | | gnu_testing_namespace (const char *subsec_name) |
595 | 19 | { |
596 | 19 | return strncmp ("gnu_testing_", subsec_name, 12) == 0; |
597 | 19 | } |
598 | | |
599 | | /* Identify the scope of a subsection from its name. |
600 | | Note: the code below needs to be kept in sync with the code of |
601 | | elf_parse_attrs_subsection_v2() in binutils/readelf.c. */ |
602 | | obj_attr_subsection_scope_v2_t |
603 | | bfd_elf_obj_attr_subsection_v2_scope (const bfd *abfd, const char *subsec_name) |
604 | 287 | { |
605 | 287 | const char *vendor_name = get_elf_backend_data (abfd)->obj_attrs_vendor; |
606 | 287 | obj_attr_subsection_scope_v2_t scope = OA_SUBSEC_PRIVATE; |
607 | 287 | size_t vendor_name_len = strlen (vendor_name); |
608 | 287 | if ((strncmp (subsec_name, vendor_name, vendor_name_len) == 0 |
609 | 9 | && subsec_name[vendor_name_len] == '_') |
610 | 287 | || (strncmp (subsec_name, "gnu_", 4) == 0 |
611 | 19 | && !gnu_testing_namespace (subsec_name))) |
612 | 19 | scope = OA_SUBSEC_PUBLIC; |
613 | 287 | return scope; |
614 | 287 | } |
615 | | |
616 | | /* Search for a subsection matching NAME in the list of subsections known from |
617 | | bfd (generic or backend-specific). Return the subsection information if it |
618 | | is found, or NULL otherwise. */ |
619 | | const known_subsection_v2_t * |
620 | | bfd_obj_attr_v2_identify_subsection (const struct elf_backend_data *bed, |
621 | | const char *name) |
622 | 0 | { |
623 | | /* Check known backend subsections. */ |
624 | 0 | const known_subsection_v2_t *known_subsections |
625 | 0 | = bed->obj_attr_v2_known_subsections; |
626 | 0 | const size_t known_subsections_size = bed->obj_attr_v2_known_subsections_size; |
627 | |
|
628 | 0 | for (unsigned i = 0; i < known_subsections_size; ++i) |
629 | 0 | { |
630 | 0 | int cmp = strcmp (known_subsections[i].subsec_name, name); |
631 | 0 | if (cmp == 0) |
632 | 0 | return &known_subsections[i]; |
633 | 0 | else if (cmp > 0) |
634 | 0 | break; |
635 | 0 | } |
636 | | |
637 | | /* Check known GNU subsections. */ |
638 | | /* Note for the future: search known GNU subsections here. Don't forget to |
639 | | skip the first entry (placeholder for GNU testing subsection). */ |
640 | | |
641 | | /* Check whether this subsection is a GNU testing subsection. */ |
642 | 0 | if (gnu_testing_namespace (name)) |
643 | 0 | return &obj_attr_v2_known_gnu_subsections[0]; |
644 | | |
645 | 0 | return NULL; |
646 | 0 | } |
647 | | |
648 | | /* Search for the attribute information associated to TAG in the list of known |
649 | | tags registered in the known subsection SUBSEC. Return the tag information |
650 | | if it is found, NULL otherwise. */ |
651 | | static const obj_attr_info_t * |
652 | | identify_tag (const known_subsection_v2_t *subsec, obj_attr_tag_t tag) |
653 | 0 | { |
654 | 0 | for (unsigned i = 0; i < subsec->len; ++i) |
655 | 0 | { |
656 | 0 | const obj_attr_info_t *known_attr = &subsec->known_attrs[i]; |
657 | 0 | if (known_attr->tag.value == tag) |
658 | 0 | return known_attr; |
659 | 0 | else if (known_attr->tag.value > tag) |
660 | 0 | break; |
661 | 0 | } |
662 | 0 | return NULL; |
663 | 0 | } |
664 | | |
665 | | /* Return the attribute information associated to the pair SUBSEC, TAG if it |
666 | | exists, NULL otherwise. */ |
667 | | const obj_attr_info_t * |
668 | | _bfd_obj_attr_v2_find_known_by_tag (const struct elf_backend_data *bed, |
669 | | const char *subsec_name, |
670 | | obj_attr_tag_t tag) |
671 | 0 | { |
672 | 0 | const known_subsection_v2_t *subsec_info |
673 | 0 | = bfd_obj_attr_v2_identify_subsection (bed, subsec_name); |
674 | 0 | if (subsec_info != NULL) |
675 | 0 | return identify_tag (subsec_info, tag); |
676 | 0 | return NULL; |
677 | 0 | } |
678 | | |
679 | | /* To-string function for the pair <SUBSEC, TAG>. |
680 | | Returns the attribute information associated to TAG if it is found, |
681 | | or "Tag_unknown_<N>" otherwise. */ |
682 | | const char * |
683 | | _bfd_obj_attr_v2_tag_to_string (const struct elf_backend_data *bed, |
684 | | const char *subsec_name, |
685 | | obj_attr_tag_t tag) |
686 | 0 | { |
687 | 0 | const obj_attr_info_t *attr_info |
688 | 0 | = _bfd_obj_attr_v2_find_known_by_tag (bed, subsec_name, tag); |
689 | 0 | if (attr_info != NULL) |
690 | 0 | return xstrdup (attr_info->tag.name); |
691 | 0 | return xasprintf ("Tag_unknown_%"PRIu64, tag); |
692 | 0 | } |
693 | | |
694 | | /* To-string function for the subsection parameter "comprehension". */ |
695 | | const char * |
696 | | bfd_oav2_comprehension_to_string (bool comprehension) |
697 | 0 | { |
698 | 0 | return comprehension ? "optional" : "required"; |
699 | 0 | } |
700 | | |
701 | | /* To-string function for the subsection parameter "encoding". */ |
702 | | const char * |
703 | | bfd_oav2_encoding_to_string (obj_attr_encoding_v2_t encoding) |
704 | 0 | { |
705 | 0 | return (encoding == OA_ENC_ULEB128) ? "ULEB128" : "NTBS"; |
706 | 0 | } |
707 | | |
708 | | /* Return True if the given BFD is an ELF object with the target backend |
709 | | machine code, non-dynamic (i.e. not a shared library), non-executable, not a |
710 | | plugin or created by the linker. False otherwise. */ |
711 | | static bool |
712 | | oav2_relevant_elf_object (const struct bfd_link_info *info, |
713 | | const bfd *const abfd) |
714 | 0 | { |
715 | 0 | const struct elf_backend_data *output_bed |
716 | 0 | = get_elf_backend_data (info->output_bfd); |
717 | 0 | unsigned int elfclass = output_bed->s->elfclass; |
718 | 0 | int elf_machine_code = output_bed->elf_machine_code; |
719 | 0 | return ((abfd->flags & (DYNAMIC | EXEC_P | BFD_PLUGIN | BFD_LINKER_CREATED)) == 0 |
720 | 0 | && bfd_get_flavour (abfd) == bfd_target_elf_flavour |
721 | 0 | && elf_machine_code == get_elf_backend_data (abfd)->elf_machine_code |
722 | 0 | && elfclass == get_elf_backend_data (abfd)->s->elfclass); |
723 | 0 | } |
724 | | |
725 | | /* Structure storing the result of a search in the list of input BFDs. */ |
726 | | typedef struct |
727 | | { |
728 | | /* A pointer to a BFD. This BFD can either point to a file having |
729 | | object attributes, or a candidate file which does not have any. */ |
730 | | bfd *pbfd; |
731 | | |
732 | | /* A boolean indicating whether the file actually contains object |
733 | | attributes. */ |
734 | | bool has_object_attributes; |
735 | | |
736 | | /* A pointer to the section containing the object attributes, if any |
737 | | were found. */ |
738 | | asection *sec; |
739 | | } bfd_search_result_t; |
740 | | |
741 | | /* Checks whether a BFD contains object attributes, and if so search for the |
742 | | relevant section storing them. The name and type of the section have to |
743 | | match with what the backend expects, i.e. elf_backend_obj_attrs_section and |
744 | | elf_backend_obj_attrs_section_type, otherwise the object attributes section |
745 | | won't be recognized as such, and will be skipped. |
746 | | Return True if an object attribute section is found, False otherwise. */ |
747 | | static bool |
748 | | input_bfd_has_object_attributes (const struct bfd_link_info *info, |
749 | | bfd *abfd, |
750 | | bfd_search_result_t *res) |
751 | 0 | { |
752 | | /* The file may contain object attributes. Save this candidate. */ |
753 | 0 | res->pbfd = abfd; |
754 | |
|
755 | 0 | if (elf_obj_attr_subsections (abfd).size == 0) |
756 | 0 | return false; |
757 | | |
758 | 0 | res->has_object_attributes = true; |
759 | |
|
760 | 0 | uint32_t sec_type = get_elf_backend_data (abfd)->obj_attrs_section_type; |
761 | 0 | const char *sec_name = get_elf_backend_data (abfd)->obj_attrs_section; |
762 | 0 | res->sec = bfd_get_section_by_name (abfd, sec_name); |
763 | 0 | if (res->sec != NULL) |
764 | 0 | { |
765 | 0 | if (elf_section_type (res->sec) != sec_type) |
766 | 0 | { |
767 | 0 | info->callbacks->minfo |
768 | 0 | (_("%X%pB: warning: ignoring section '%s' with unexpected type %#x\n"), |
769 | 0 | abfd, sec_name, elf_section_type (res->sec)); |
770 | 0 | res->sec = NULL; |
771 | 0 | } |
772 | 0 | } |
773 | 0 | return (res->sec != NULL); |
774 | 0 | } |
775 | | |
776 | | /* Search for the first input object file containing object attributes. |
777 | | If no such object is found, the result structure's PBFD points to the |
778 | | last object file that could have contained object attributes. The |
779 | | result structure's HAS_OBJECT_ATTRIBUTES allows to distinguish the |
780 | | cases when PBFD contains or does not contain object attributes. If no |
781 | | candidate file is found, PBFD will stay NULL. */ |
782 | | static bfd_search_result_t |
783 | | bfd_linear_find_first_with_obj_attrs (const struct bfd_link_info *info) |
784 | 0 | { |
785 | 0 | bfd_search_result_t res = { .has_object_attributes = false }; |
786 | 0 | for (bfd *abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) |
787 | 0 | { |
788 | 0 | if (oav2_relevant_elf_object (info, abfd) |
789 | 0 | && abfd->section_count != 0 |
790 | 0 | && input_bfd_has_object_attributes (info, abfd, &res)) |
791 | 0 | break; |
792 | 0 | } |
793 | 0 | return res; |
794 | 0 | } |
795 | | |
796 | | /* Create a object attributes section for the given bfd input. */ |
797 | | static asection * |
798 | | create_object_attributes_section (struct bfd_link_info *info, |
799 | | bfd *abfd) |
800 | 0 | { |
801 | 0 | asection *sec; |
802 | 0 | const char *sec_name = get_elf_backend_data (abfd)->obj_attrs_section; |
803 | 0 | sec = bfd_make_section_with_flags (abfd, |
804 | 0 | sec_name, |
805 | 0 | (SEC_READONLY |
806 | 0 | | SEC_HAS_CONTENTS |
807 | 0 | | SEC_DATA)); |
808 | 0 | if (sec == NULL) |
809 | 0 | info->callbacks->fatal (_("%P: failed to create %s section\n"), sec_name); |
810 | | |
811 | 0 | if (!bfd_set_section_alignment (sec, 2)) |
812 | 0 | info->callbacks->fatal (_("%pA: failed to align section\n"), sec); |
813 | | |
814 | 0 | elf_section_type (sec) = get_elf_backend_data (abfd)->obj_attrs_section_type; |
815 | |
|
816 | 0 | bfd_set_section_size (sec, bfd_elf_obj_attr_size (abfd)); |
817 | |
|
818 | 0 | return sec; |
819 | 0 | } |
820 | | |
821 | | /* Translate GNU properties that have object attributes v2 equivalents. */ |
822 | | static void |
823 | | oav2_translate_gnu_props_to_obj_attrs (const bfd *abfd) |
824 | 0 | { |
825 | 0 | const struct elf_backend_data *be = get_elf_backend_data (abfd); |
826 | 0 | if (be->translate_gnu_props_to_obj_attrs == NULL) |
827 | 0 | return; |
828 | | |
829 | 0 | for (const elf_property_list *p = elf_properties (abfd); |
830 | 0 | p != NULL; |
831 | 0 | p = p->next) |
832 | 0 | be->translate_gnu_props_to_obj_attrs (abfd, p); |
833 | 0 | } |
834 | | |
835 | | /* Translate object attributes v2 that have GNU properties equivalents. */ |
836 | | static void |
837 | | oav2_translate_obj_attrs_to_gnu_props (bfd *abfd) |
838 | 0 | { |
839 | 0 | const struct elf_backend_data *be = get_elf_backend_data (abfd); |
840 | 0 | if (be->translate_obj_attrs_to_gnu_props == NULL) |
841 | 0 | return; |
842 | | |
843 | 0 | for (const obj_attr_subsection_v2_t *subsec |
844 | 0 | = elf_obj_attr_subsections (abfd).first; |
845 | 0 | subsec != NULL; |
846 | 0 | subsec = subsec->next) |
847 | 0 | be->translate_obj_attrs_to_gnu_props (abfd, subsec); |
848 | 0 | } |
849 | | |
850 | | /* Compact duplicated tag declarations in a subsection. |
851 | | Return True on success, False if any issue is found during the compaction, |
852 | | i.e. conflicting values for the same tag. */ |
853 | | static bool |
854 | | oav2_compact_tags (const bfd *abfd, obj_attr_subsection_v2_t *subsec) |
855 | 0 | { |
856 | 0 | bool success = true; |
857 | |
|
858 | 0 | for (obj_attr_v2_t *a = subsec->first; |
859 | 0 | a != NULL && a->next != NULL;) |
860 | 0 | { |
861 | 0 | if (a->tag != a->next->tag) |
862 | 0 | { |
863 | 0 | a = a->next; |
864 | 0 | continue; |
865 | 0 | } |
866 | | |
867 | | /* For NTBS encoding, ensure that the string value of the attributes is |
868 | | not NULL. |
869 | | Note: a string attribute can only be NULL if it was created during the |
870 | | merge process. Since tag compaction occurs before merging begins, this |
871 | | assertion guarantees that the function is never called in a context |
872 | | where the assumption does not hold. */ |
873 | 0 | BFD_ASSERT |
874 | 0 | (subsec->encoding == OA_ENC_ULEB128 || |
875 | 0 | (a->val.string != NULL && a->next->val.string != NULL)); |
876 | | |
877 | | /* Values of a tag are the same, we remove the duplicate. */ |
878 | 0 | if ((subsec->encoding == OA_ENC_ULEB128 |
879 | 0 | && a->val.uint == a->next->val.uint) |
880 | 0 | || (subsec->encoding == OA_ENC_NTBS |
881 | 0 | && strcmp (a->val.string, a->next->val.string) == 0)) |
882 | 0 | { |
883 | 0 | obj_attr_v2_t *dup_attr = a->next; |
884 | 0 | LINKED_LIST_REMOVE (obj_attr_v2_t) (subsec, dup_attr); |
885 | 0 | _bfd_elf_obj_attr_v2_free (dup_attr, subsec->encoding); |
886 | 0 | continue; |
887 | 0 | } |
888 | | |
889 | | /* The values of a tag are different, there are various options: |
890 | | - the tag values can be merged. This requires a knowledge of a tag |
891 | | merge policy, sometimes generic, sometimes only known from the |
892 | | target backend. Since no such complex case exists for now, it is |
893 | | not implemented. |
894 | | - values for a given tag have to be the same in the same subsection, |
895 | | or it raises an error. This will be the default handling for now. */ |
896 | 0 | success = false; |
897 | |
|
898 | 0 | const char *tag_s = _bfd_obj_attr_v2_tag_to_string |
899 | 0 | (get_elf_backend_data (abfd), subsec->name, a->tag); |
900 | |
|
901 | 0 | if (subsec->encoding == OA_ENC_ULEB128) |
902 | 0 | _bfd_error_handler |
903 | 0 | (_("%pB: error: found duplicated attributes '%s' with conflicting " |
904 | 0 | "values (%#x vs %#x) in subsection %s"), |
905 | 0 | abfd, tag_s, a->val.uint, a->next->val.uint, subsec->name); |
906 | 0 | else /* (subsec->encoding == OA_ENC_NTBS) */ |
907 | 0 | _bfd_error_handler |
908 | 0 | (_("%pB: error: found duplicated attributes '%s' with conflicting " |
909 | 0 | "values ('%s' vs '%s') in subsection %s"), |
910 | 0 | abfd, tag_s, a->val.string, a->next->val.string, subsec->name); |
911 | |
|
912 | 0 | free ((char *) tag_s); |
913 | | |
914 | | /* We skip the tag, and continue the compaction of tags to find further |
915 | | issues (if any). */ |
916 | 0 | a = a->next; |
917 | 0 | } |
918 | |
|
919 | 0 | return success; |
920 | 0 | } |
921 | | |
922 | | /* Merge two subsections together (object attributes v2 only). |
923 | | The result is stored into subsec1. subsec2 is destroyed. |
924 | | Return true if the merge was successful, false otherwise. |
925 | | Note: subsec1 and subsec2 are expected to be sorted before the call to this |
926 | | function. */ |
927 | | static bool |
928 | | oav2_subsection_destructive_merge (const bfd *abfd, |
929 | | obj_attr_subsection_v2_t *subsec1, |
930 | | obj_attr_subsection_v2_t *subsec2) |
931 | 0 | { |
932 | 0 | BFD_ASSERT (subsec1->encoding == subsec2->encoding |
933 | 0 | && subsec1->optional == subsec2->optional); |
934 | |
|
935 | 0 | bool success = true; |
936 | |
|
937 | 0 | success &= oav2_compact_tags (abfd, subsec1); |
938 | 0 | success &= oav2_compact_tags (abfd, subsec2); |
939 | |
|
940 | 0 | obj_attr_v2_t *a1 = subsec1->first; |
941 | 0 | obj_attr_v2_t *a2 = subsec2->first; |
942 | 0 | while (a1 != NULL && a2 != NULL) |
943 | 0 | { |
944 | 0 | if (a1->tag < a2->tag) |
945 | 0 | {} /* Nothing to do, a1 is already in subsec1. */ |
946 | 0 | else if (a1->tag > a2->tag) |
947 | 0 | { |
948 | | /* a2 is missing in subsec1, add it. */ |
949 | 0 | obj_attr_v2_t *previous |
950 | 0 | = LINKED_LIST_REMOVE (obj_attr_v2_t) (subsec2, a2); |
951 | 0 | LINKED_LIST_INSERT_BEFORE (obj_attr_v2_t) (subsec1, a2, a1); |
952 | 0 | a2 = previous; |
953 | 0 | } |
954 | 0 | else |
955 | 0 | { |
956 | 0 | const char *tag_s = NULL; |
957 | 0 | if (subsec1->encoding == OA_ENC_ULEB128 |
958 | 0 | && a1->val.uint != a2->val.uint) |
959 | 0 | { |
960 | 0 | success = false; |
961 | 0 | tag_s = _bfd_obj_attr_v2_tag_to_string |
962 | 0 | (get_elf_backend_data (abfd), subsec1->name, a1->tag); |
963 | 0 | _bfd_error_handler |
964 | 0 | (_("%pB: error: found 2 subsections with the same name '%s' " |
965 | 0 | "and found conflicting values (%#x vs %#x) for object " |
966 | 0 | "attribute '%s'"), |
967 | 0 | abfd, subsec1->name, a1->val.uint, a2->val.uint, tag_s); |
968 | 0 | } |
969 | 0 | else if (subsec1->encoding == OA_ENC_NTBS |
970 | 0 | && strcmp (a1->val.string, a2->val.string) != 0) |
971 | 0 | { |
972 | 0 | success = false; |
973 | 0 | tag_s = _bfd_obj_attr_v2_tag_to_string |
974 | 0 | (get_elf_backend_data (abfd), subsec1->name, a1->tag); |
975 | 0 | _bfd_error_handler |
976 | 0 | (_("%pB: error: found 2 subsections with the same name '%s' " |
977 | 0 | "and found conflicting values ('%s' vs '%s') for object " |
978 | 0 | "attribute '%s"), |
979 | 0 | abfd, subsec1->name, a1->val.string, a2->val.string, tag_s); |
980 | 0 | } |
981 | 0 | free ((char *) tag_s); |
982 | 0 | } |
983 | 0 | a1 = a1->next; |
984 | 0 | a2 = a2->next; |
985 | 0 | } |
986 | |
|
987 | 0 | for (; a2 != NULL; a2 = a2->next) |
988 | 0 | { |
989 | | /* a2 is missing in subsec1, add it. */ |
990 | 0 | obj_attr_v2_t *previous |
991 | 0 | = LINKED_LIST_REMOVE (obj_attr_v2_t) (subsec2, a2); |
992 | 0 | LINKED_LIST_INSERT_BEFORE (obj_attr_v2_t) (subsec1, a2, a1); |
993 | 0 | a2 = previous; |
994 | 0 | } |
995 | | |
996 | | /* If a1 != NULL, we don't care since it is already in subsec1. */ |
997 | | |
998 | | /* Destroy subsec2 before exiting. */ |
999 | 0 | _bfd_elf_obj_attr_subsection_v2_free (subsec2); |
1000 | |
|
1001 | 0 | return success; |
1002 | 0 | } |
1003 | | |
1004 | | /* Merge duplicated subsections and object attributes inside a same object |
1005 | | file. After a call to this function, the subsections and object attributes |
1006 | | are sorted. |
1007 | | Note: this function allows to handle in a best effort exotic objects produced |
1008 | | by a non-GNU assembler. Duplicated subsections could come from the same |
1009 | | section, or different ones. Indeed, the deserializer deserializes the |
1010 | | content of a section if its type matches the object attributes type specified |
1011 | | by the backend, regardless of the section name. The behavior for such cases |
1012 | | is not specified by the Object Attributes specification, and are a question |
1013 | | of implementation. Non-GNU linkers might have a different behavior with such |
1014 | | exotic objects. */ |
1015 | | static bool |
1016 | | oav2_file_scope_merge_subsections (const bfd *abfd) |
1017 | 0 | { |
1018 | 0 | obj_attr_subsection_list_t *subsecs = &elf_obj_attr_subsections (abfd); |
1019 | | |
1020 | | /* Sort all the subsections and object attributes as they might not have been |
1021 | | inserted in the right order. From now on, the subsections and attributes |
1022 | | will be assumed to be always sorted. Any additive mutation will need to |
1023 | | preserve the order. */ |
1024 | 0 | oav2_sort_subsections (subsecs); |
1025 | |
|
1026 | 0 | bool success = true; |
1027 | |
|
1028 | 0 | obj_attr_subsection_v2_t *subsec = subsecs->first; |
1029 | 0 | while (subsec != NULL && subsec->next != NULL) |
1030 | 0 | { |
1031 | 0 | obj_attr_subsection_v2_t *dup_subsec |
1032 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (subsec->next, |
1033 | 0 | subsec->name, |
1034 | 0 | false); |
1035 | 0 | if (dup_subsec != NULL) |
1036 | 0 | { |
1037 | 0 | LINKED_LIST_REMOVE (obj_attr_subsection_v2_t) (subsecs, dup_subsec); |
1038 | 0 | success &= oav2_subsection_destructive_merge (abfd, subsec, dup_subsec); |
1039 | 0 | } |
1040 | 0 | else |
1041 | 0 | subsec = subsec->next; |
1042 | 0 | } |
1043 | |
|
1044 | 0 | return success; |
1045 | 0 | } |
1046 | | |
1047 | | /* If an Object Attribute subsection inside ABFD cannot be identified neither |
1048 | | as a GNU subsection or a backend-specific one, set the status of this |
1049 | | subsection to UNKNOWN. The unknown subsection will be skipped during the |
1050 | | merge process, and will be pruned from the output. */ |
1051 | | static void |
1052 | | oav2_subsections_mark_unknown (const bfd *abfd) |
1053 | 0 | { |
1054 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
1055 | 0 | for (obj_attr_subsection_v2_t *subsec = elf_obj_attr_subsections (abfd).first; |
1056 | 0 | subsec != NULL; |
1057 | 0 | subsec = subsec->next) |
1058 | 0 | { |
1059 | 0 | if (bfd_obj_attr_v2_identify_subsection (bed, subsec->name) == NULL) |
1060 | 0 | subsec->status = obj_attr_subsection_v2_unknown; |
1061 | 0 | } |
1062 | 0 | } |
1063 | | |
1064 | | /* Assign the merge result to REF. |
1065 | | The only reason to exist for this helper is when the manipulated value is a |
1066 | | string. In this case, the value in REF must be freed before assigning. */ |
1067 | | static void |
1068 | | oav2_assign_value (obj_attr_encoding_v2_t encoding, |
1069 | | obj_attr_v2_t *a_ref, |
1070 | | union obj_attr_value_v2 res) |
1071 | 0 | { |
1072 | 0 | if (encoding == OA_ENC_NTBS) |
1073 | 0 | free ((void *) a_ref->val.string); |
1074 | 0 | a_ref->val = res; |
1075 | 0 | } |
1076 | | |
1077 | | /* Initialize the given ATTR with its default value coming from the known tag |
1078 | | registry. */ |
1079 | | static void |
1080 | | oav2_attr_overwrite_with_default (const struct bfd_link_info *info, |
1081 | | const obj_attr_subsection_v2_t *subsec, |
1082 | | obj_attr_v2_t *attr) |
1083 | 0 | { |
1084 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); |
1085 | |
|
1086 | 0 | union obj_attr_value_v2 default_value; |
1087 | 0 | memset (&default_value, 0, sizeof (default_value)); |
1088 | |
|
1089 | 0 | const obj_attr_info_t *attr_info |
1090 | 0 | = _bfd_obj_attr_v2_find_known_by_tag (bed, subsec->name, attr->tag); |
1091 | 0 | if (attr_info == NULL) |
1092 | 0 | { |
1093 | 0 | attr->status = obj_attr_v2_unknown; |
1094 | 0 | oav2_assign_value (subsec->encoding, attr, default_value); |
1095 | 0 | return; |
1096 | 0 | } |
1097 | | |
1098 | 0 | if (bed->obj_attr_v2_default_value != NULL |
1099 | 0 | && bed->obj_attr_v2_default_value (info, attr_info, subsec, attr)) |
1100 | 0 | return; |
1101 | | |
1102 | 0 | if (subsec->encoding == OA_ENC_NTBS) |
1103 | 0 | { |
1104 | 0 | if (attr_info->default_value.string != NULL) |
1105 | 0 | default_value.string = xstrdup (attr_info->default_value.string); |
1106 | 0 | } |
1107 | 0 | else |
1108 | 0 | default_value.uint = attr_info->default_value.uint; |
1109 | 0 | oav2_assign_value (subsec->encoding, attr, default_value); |
1110 | 0 | } |
1111 | | |
1112 | | /* Create a new attribute with the same key (=tag) as ATTR, and initialized with |
1113 | | its default value from the known tag registry. */ |
1114 | | static obj_attr_v2_t * |
1115 | | oav2_attr_default (const struct bfd_link_info *info, |
1116 | | const obj_attr_subsection_v2_t *subsec, |
1117 | | const obj_attr_v2_t *attr) |
1118 | 0 | { |
1119 | 0 | obj_attr_v2_t *new_attr = _bfd_elf_obj_attr_v2_copy (attr, subsec->encoding); |
1120 | 0 | oav2_attr_overwrite_with_default (info, subsec, new_attr); |
1121 | 0 | return new_attr; |
1122 | 0 | } |
1123 | | |
1124 | | /* The currently supported merge policy in the testing GNU namespace. |
1125 | | - bitwise AND: apply bitwise AND. |
1126 | | - bitwise OR: apply bitwise OR. |
1127 | | - String-ADD: concatenates strings together with a '+' in-between. |
1128 | | Note: Such policies should only be used for testing. */ |
1129 | | typedef enum { |
1130 | | SUBSECTION_TESTING_MERGE_UNSUPPORTED = 0, |
1131 | | SUBSECTION_TESTING_MERGE_AND_POLICY = 1, |
1132 | | SUBSECTION_TESTING_MERGE_OR_POLICY = 2, |
1133 | | SUBSECTION_TESTING_MERGE_ADD_POLICY = 3, |
1134 | | } gnu_testing_merge_policy; |
1135 | | |
1136 | | /* Determine which merge policy will be applied to SUBSEC. The GNU policy are |
1137 | | detected from the name of the subsection. It should follow the following |
1138 | | pattern: "gnu_testing_XXXXXX_MERGE_<POLICY>". |
1139 | | Return one of the known merge policy if recognised, UNSUPPORTED otherwise. */ |
1140 | | static gnu_testing_merge_policy |
1141 | | gnu_testing_merge_subsection (const char *subsec_name) |
1142 | 0 | { |
1143 | 0 | if (! gnu_testing_namespace (subsec_name)) |
1144 | 0 | return SUBSECTION_TESTING_MERGE_UNSUPPORTED; |
1145 | | |
1146 | 0 | size_t subsec_name_len = strlen (subsec_name); |
1147 | 0 | if (strcmp ("_MERGE_AND", subsec_name + subsec_name_len - 10) == 0) |
1148 | 0 | return SUBSECTION_TESTING_MERGE_AND_POLICY; |
1149 | 0 | else if (strcmp ("_MERGE_OR", subsec_name + subsec_name_len - 9) == 0) |
1150 | 0 | return SUBSECTION_TESTING_MERGE_OR_POLICY; |
1151 | 0 | else if (strcmp ("_MERGE_ADD", subsec_name + subsec_name_len - 10) == 0) |
1152 | 0 | return SUBSECTION_TESTING_MERGE_ADD_POLICY; |
1153 | 0 | else |
1154 | 0 | return SUBSECTION_TESTING_MERGE_UNSUPPORTED; |
1155 | 0 | } |
1156 | | |
1157 | | /* Merge policy Integer-AND: apply bitwise AND between REF and RHS. */ |
1158 | | obj_attr_v2_merge_result_t |
1159 | | _bfd_obj_attr_v2_merge_AND (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1160 | | const bfd *abfd ATTRIBUTE_UNUSED, |
1161 | | const obj_attr_subsection_v2_t *subsec, |
1162 | | const obj_attr_v2_t *ref, const obj_attr_v2_t *rhs, |
1163 | | const obj_attr_v2_t *frozen ATTRIBUTE_UNUSED) |
1164 | 0 | { |
1165 | 0 | BFD_ASSERT (subsec->encoding == OA_ENC_ULEB128); |
1166 | |
|
1167 | 0 | obj_attr_v2_merge_result_t res; |
1168 | |
|
1169 | 0 | res.val.uint = (ref->val.uint & rhs->val.uint); |
1170 | 0 | res.merge = (res.val.uint != ref->val.uint); |
1171 | 0 | res.reason = (!res.merge |
1172 | 0 | ? OAv2_MERGE_SAME_VALUE_AS_REF |
1173 | 0 | : OAv2_MERGE_OK); |
1174 | |
|
1175 | 0 | return res; |
1176 | 0 | } |
1177 | | |
1178 | | /* Merge policy Integer-OR: apply bitwise OR between REF and RHS. */ |
1179 | | static obj_attr_v2_merge_result_t |
1180 | | obj_attr_v2_merge_OR (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1181 | | const bfd *abfd ATTRIBUTE_UNUSED, |
1182 | | const obj_attr_subsection_v2_t *subsec, |
1183 | | const obj_attr_v2_t *ref, const obj_attr_v2_t *rhs, |
1184 | | const obj_attr_v2_t *frozen ATTRIBUTE_UNUSED) |
1185 | 0 | { |
1186 | 0 | BFD_ASSERT (subsec->encoding == OA_ENC_ULEB128); |
1187 | |
|
1188 | 0 | obj_attr_v2_merge_result_t res; |
1189 | |
|
1190 | 0 | res.val.uint = (ref->val.uint | rhs->val.uint); |
1191 | 0 | res.merge = (res.val.uint != ref->val.uint); |
1192 | 0 | res.reason = (!res.merge |
1193 | 0 | ? OAv2_MERGE_SAME_VALUE_AS_REF |
1194 | 0 | : OAv2_MERGE_OK); |
1195 | |
|
1196 | 0 | return res; |
1197 | 0 | } |
1198 | | |
1199 | | /* Merge policy String-ADD: concatenates strings from REF and RHS together |
1200 | | adding a '+' character in-between. */ |
1201 | | static obj_attr_v2_merge_result_t |
1202 | | obj_attr_v2_merge_ADD (const struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1203 | | const bfd *abfd ATTRIBUTE_UNUSED, |
1204 | | const obj_attr_subsection_v2_t *subsec, |
1205 | | const obj_attr_v2_t *ref, const obj_attr_v2_t *rhs, |
1206 | | const obj_attr_v2_t *frozen ATTRIBUTE_UNUSED) |
1207 | 0 | { |
1208 | 0 | BFD_ASSERT (subsec->encoding == OA_ENC_NTBS); |
1209 | |
|
1210 | 0 | obj_attr_v2_merge_result_t res = { |
1211 | 0 | .merge = false, |
1212 | 0 | .val.string = NULL, |
1213 | 0 | .reason = OAv2_MERGE_OK, |
1214 | 0 | }; |
1215 | | |
1216 | | /* Note: FROZEN is unused for this "concatenating" merge because it is |
1217 | | either passed as RHS when coming from oav2_subsections_merge_frozen(), |
1218 | | or passed as FROZEN when coming from oav2_subsections_merge() and was |
1219 | | already merged. */ |
1220 | | |
1221 | | /* REF and RHS have both a value. Concatenate RHS to REF. */ |
1222 | 0 | if (ref->val.string && rhs->val.string) |
1223 | 0 | { |
1224 | 0 | res.merge = true; |
1225 | 0 | size_t ref_s_size = strlen (ref->val.string); |
1226 | 0 | size_t rhs_s_size = strlen (rhs->val.string); |
1227 | 0 | char *buffer = xmalloc (ref_s_size + 1 + rhs_s_size + 1); |
1228 | 0 | res.val.string = buffer; |
1229 | 0 | memcpy (buffer, ref->val.string, ref_s_size); |
1230 | 0 | buffer += ref_s_size; |
1231 | 0 | *buffer = '+'; |
1232 | 0 | ++buffer; |
1233 | 0 | memcpy (buffer, rhs->val.string, rhs_s_size + 1); |
1234 | 0 | } |
1235 | | /* REF has a value, but RHS does not. Nothing to do. */ |
1236 | 0 | else if (ref->val.string) |
1237 | 0 | res.reason = OAv2_MERGE_SAME_VALUE_AS_REF; |
1238 | | /* No previous value in REF. RHS is the new value. */ |
1239 | 0 | else if (rhs->val.string) |
1240 | 0 | { |
1241 | | /* This case could be optimized to avoid the dynamic allocation by moving |
1242 | | the value from RHS to RES, but then, we need to distinguish the case |
1243 | | when RHS and FROZEN are the same, and in this case, the value should |
1244 | | not be moved but copied. The little benefit is not worth the added |
1245 | | complexity. */ |
1246 | 0 | res.merge = true; |
1247 | 0 | res.val.string = xstrdup (rhs->val.string); |
1248 | 0 | } |
1249 | 0 | return res; |
1250 | 0 | } |
1251 | | |
1252 | | /* Return the merge result between attributes LHS, RHS and FROZEN. |
1253 | | Note: FROZEN_IS_RHS indicates that FROZEN is in RHS's position. This happens |
1254 | | when this function is called from oav2_subsections_merge_frozen(). When this |
1255 | | boolean is true, arguments are swapped to get the correct diagnostic messages |
1256 | | in case of issues. */ |
1257 | | static obj_attr_v2_merge_result_t |
1258 | | oav2_attr_merge (const struct bfd_link_info *info, |
1259 | | const bfd *abfd, |
1260 | | const obj_attr_subsection_v2_t *subsec, |
1261 | | const obj_attr_v2_t *lhs, const obj_attr_v2_t *rhs, |
1262 | | const obj_attr_v2_t *frozen, bool frozen_is_rhs) |
1263 | 0 | { |
1264 | 0 | obj_attr_v2_merge_result_t res = { |
1265 | 0 | .merge = false, |
1266 | 0 | .val.uint = 0, |
1267 | 0 | .reason = OAv2_MERGE_OK, |
1268 | 0 | }; |
1269 | |
|
1270 | 0 | gnu_testing_merge_policy policy; |
1271 | |
|
1272 | 0 | if (get_elf_backend_data (abfd)->obj_attr_v2_tag_merge != NULL) |
1273 | 0 | { |
1274 | | /* If FROZEN is RHS (i.e. called from oav2_subsections_merge_frozen()), it |
1275 | | means that the merged value of LHS (the REF) and FROZEN is going to |
1276 | | be merged by the caller into LHS. However, since diagnostic messages |
1277 | | always point to RHS, we need to swap LHS and RHS, so that ABFD is not |
1278 | | associated wrongly to FROZEN. */ |
1279 | 0 | if (frozen_is_rhs) |
1280 | 0 | { |
1281 | 0 | const obj_attr_v2_t *tmp = lhs; |
1282 | 0 | lhs = rhs; |
1283 | 0 | rhs = tmp; |
1284 | 0 | } |
1285 | 0 | res = get_elf_backend_data (abfd)->obj_attr_v2_tag_merge (info, abfd, |
1286 | 0 | subsec, lhs, rhs, frozen); |
1287 | 0 | if (res.merge || res.reason == OAv2_MERGE_SAME_VALUE_AS_REF) |
1288 | 0 | return res; |
1289 | 0 | } |
1290 | | |
1291 | | /* Note for the future: the merge of generic object attributes should be |
1292 | | added here, between the architecture-specific merge, and the reserved GNU |
1293 | | testing namespace. */ |
1294 | | |
1295 | | /* GNU testing merge policies are looked up last. */ |
1296 | 0 | if ((res.reason == OAv2_MERGE_UNSUPPORTED || res.reason == OAv2_MERGE_OK) |
1297 | 0 | && (policy = gnu_testing_merge_subsection (subsec->name)) |
1298 | 0 | != SUBSECTION_TESTING_MERGE_UNSUPPORTED) |
1299 | 0 | { |
1300 | | /* Only the first two attributes can be merged, others won't and will |
1301 | | be discarded. */ |
1302 | 0 | if (lhs->tag <= 1) |
1303 | 0 | { |
1304 | 0 | if (policy == SUBSECTION_TESTING_MERGE_AND_POLICY) |
1305 | 0 | res = _bfd_obj_attr_v2_merge_AND (info, abfd, subsec, lhs, rhs, frozen); |
1306 | 0 | else if (policy == SUBSECTION_TESTING_MERGE_OR_POLICY) |
1307 | 0 | res = obj_attr_v2_merge_OR (info, abfd, subsec, lhs, rhs, frozen); |
1308 | 0 | else if (policy == SUBSECTION_TESTING_MERGE_ADD_POLICY) |
1309 | 0 | res = obj_attr_v2_merge_ADD (info, abfd, subsec, lhs, rhs, frozen); |
1310 | |
|
1311 | 0 | return res; |
1312 | 0 | } |
1313 | 0 | } |
1314 | | |
1315 | | /* Nothing matched, thus the merge of this tag is unsupported. */ |
1316 | 0 | res.reason = OAv2_MERGE_UNSUPPORTED; |
1317 | 0 | return res; |
1318 | 0 | } |
1319 | | |
1320 | | /* Append a new default-initialized attribute with the same key as AREF to the |
1321 | | given subsection. */ |
1322 | | static void |
1323 | | oav2_subsection_append_attr_default (const struct bfd_link_info *info, |
1324 | | obj_attr_subsection_v2_t *s_abfd_missing, |
1325 | | const obj_attr_v2_t *a_ref) |
1326 | 0 | { |
1327 | 0 | obj_attr_v2_t *new_attr = oav2_attr_default (info, s_abfd_missing, a_ref); |
1328 | 0 | LINKED_LIST_APPEND (obj_attr_v2_t) (s_abfd_missing, new_attr); |
1329 | 0 | } |
1330 | | |
1331 | | /* Return a new default-initialized subsection with the same parameters as |
1332 | | SUBSEC. */ |
1333 | | static obj_attr_subsection_v2_t * |
1334 | | oav2_subsection_default_new (const struct bfd_link_info *info, |
1335 | | const obj_attr_subsection_v2_t *subsec) |
1336 | 0 | { |
1337 | 0 | obj_attr_subsection_v2_t *new_subsec = bfd_elf_obj_attr_subsection_v2_init |
1338 | 0 | (xstrdup (subsec->name), subsec->scope, subsec->optional, subsec->encoding); |
1339 | |
|
1340 | 0 | for (const obj_attr_v2_t *attr = subsec->first; |
1341 | 0 | attr != NULL; |
1342 | 0 | attr = attr->next) |
1343 | 0 | oav2_subsection_append_attr_default (info, new_subsec, attr); |
1344 | |
|
1345 | 0 | return new_subsec; |
1346 | 0 | } |
1347 | | |
1348 | | /* Report missing required attribute with key TAG in subsection SREF. */ |
1349 | | static void |
1350 | | report_missing_required_obj_attr (const struct bfd_link_info *info, |
1351 | | const bfd *abfd, |
1352 | | const obj_attr_subsection_v2_t *s_ref, |
1353 | | const obj_attr_tag_t tag) |
1354 | 0 | { |
1355 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
1356 | 0 | const char *tag_s = _bfd_obj_attr_v2_tag_to_string (bed, s_ref->name, tag); |
1357 | 0 | info->callbacks->einfo ( |
1358 | 0 | _("%X%pB: error: missing required object attribute '%s' in subsection '%s'\n"), |
1359 | 0 | abfd, tag_s, s_ref->name); |
1360 | 0 | free ((char *) tag_s); |
1361 | 0 | } |
1362 | | |
1363 | | /* Report required attribute A_ABFD mismatching with A_REF. */ |
1364 | | static void |
1365 | | report_mismatching_required_obj_attr (const struct bfd_link_info *info, |
1366 | | const bfd *ref_bfd, |
1367 | | const bfd *abfd, |
1368 | | const obj_attr_subsection_v2_t *s_ref, |
1369 | | const obj_attr_v2_t *a_ref, |
1370 | | const obj_attr_v2_t *a_abfd) |
1371 | 0 | { |
1372 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (abfd); |
1373 | 0 | const char *tag_s |
1374 | 0 | = _bfd_obj_attr_v2_tag_to_string (bed, s_ref->name, a_ref->tag); |
1375 | 0 | if (s_ref->encoding == OA_ENC_ULEB128) |
1376 | 0 | { |
1377 | 0 | info->callbacks->einfo ( |
1378 | 0 | _("%X%pB: error: mismatching value for required object attribute '%s' " |
1379 | 0 | "in subsection '%s': %#x\n"), |
1380 | 0 | abfd, tag_s, s_ref->name, a_abfd->val.uint); |
1381 | 0 | info->callbacks->info ( |
1382 | 0 | _("%pB: info: conflicting value '%#x' lives here\n"), |
1383 | 0 | ref_bfd, a_ref->val.uint); |
1384 | 0 | } |
1385 | 0 | else |
1386 | 0 | { |
1387 | 0 | info->callbacks->einfo ( |
1388 | 0 | _("%X%pB: error: mismatching value for required object attribute '%s' " |
1389 | 0 | "in subsection '%s': \"%s\"\n"), |
1390 | 0 | abfd, tag_s, s_ref->name, a_abfd->val.string); |
1391 | 0 | info->callbacks->info ( |
1392 | 0 | _("%pB: info: conflicting value \"%s\" lives here\n"), |
1393 | 0 | ref_bfd, a_ref->val.string); |
1394 | 0 | } |
1395 | 0 | free ((char *) tag_s); |
1396 | 0 | } |
1397 | | |
1398 | | /* Attempt a perfect match between subsections S_REF and S_ABFD, and reports |
1399 | | errors for any mismatch. Return S_REF if the subsections match, NULL |
1400 | | otherwise.*/ |
1401 | | static obj_attr_subsection_v2_t * |
1402 | | oav2_subsection_perfect_match (const struct bfd_link_info *info, |
1403 | | const bfd *ref_bfd, const bfd *abfd, |
1404 | | obj_attr_subsection_v2_t *s_ref, |
1405 | | const obj_attr_subsection_v2_t *s_abfd) |
1406 | 0 | { |
1407 | 0 | bool success = true; |
1408 | 0 | const obj_attr_v2_t *a_ref = s_ref->first; |
1409 | 0 | const obj_attr_v2_t *a_abfd = s_abfd->first; |
1410 | 0 | while (a_ref != NULL && a_abfd != NULL) |
1411 | 0 | { |
1412 | 0 | if (a_ref->tag < a_abfd->tag) |
1413 | 0 | { |
1414 | 0 | success = false; |
1415 | 0 | report_missing_required_obj_attr (info, abfd, s_ref, a_ref->tag); |
1416 | 0 | a_ref = a_ref->next; |
1417 | 0 | } |
1418 | 0 | else if (a_ref->tag > a_abfd->tag) |
1419 | 0 | { |
1420 | 0 | success = false; |
1421 | 0 | report_missing_required_obj_attr (info, ref_bfd, s_ref, a_abfd->tag); |
1422 | 0 | a_abfd = a_abfd->next; |
1423 | 0 | } |
1424 | 0 | else |
1425 | 0 | { |
1426 | 0 | if (s_ref->encoding == OA_ENC_ULEB128) |
1427 | 0 | { |
1428 | 0 | if (a_ref->val.uint != a_abfd->val.uint) |
1429 | 0 | { |
1430 | 0 | success = false; |
1431 | 0 | report_mismatching_required_obj_attr (info, ref_bfd, abfd, |
1432 | 0 | s_ref, a_ref, a_abfd); |
1433 | 0 | } |
1434 | 0 | } |
1435 | 0 | else if (s_ref->encoding == OA_ENC_NTBS) |
1436 | 0 | { |
1437 | 0 | if (strcmp (a_ref->val.string, a_abfd->val.string) != 0) |
1438 | 0 | { |
1439 | 0 | success = false; |
1440 | 0 | report_mismatching_required_obj_attr (info, ref_bfd, abfd, |
1441 | 0 | s_ref, a_ref, a_abfd); |
1442 | 0 | } |
1443 | 0 | } |
1444 | 0 | a_ref = a_ref->next; |
1445 | 0 | a_abfd = a_abfd->next; |
1446 | 0 | } |
1447 | 0 | } |
1448 | |
|
1449 | 0 | for (; a_abfd != NULL; a_abfd = a_abfd->next) |
1450 | 0 | { |
1451 | 0 | success = false; |
1452 | 0 | report_missing_required_obj_attr (info, ref_bfd, s_ref, a_abfd->tag); |
1453 | 0 | } |
1454 | |
|
1455 | 0 | for (; a_ref != NULL; a_ref = a_ref->next) |
1456 | 0 | { |
1457 | 0 | success = false; |
1458 | 0 | report_missing_required_obj_attr (info, abfd, s_ref, a_ref->tag); |
1459 | 0 | } |
1460 | |
|
1461 | 0 | return success ? s_ref : NULL; |
1462 | 0 | } |
1463 | | |
1464 | | /* Search for the attribute with TAG into a list of attributes. The attributes |
1465 | | list is assumed to be sorted. Return the pointer to the attribute with TAG |
1466 | | if found, NULL otherwise. */ |
1467 | | static obj_attr_v2_t * |
1468 | | oav2_search_by_tag (obj_attr_v2_t *attr_first, obj_attr_tag_t tag) |
1469 | 0 | { |
1470 | 0 | for (obj_attr_v2_t *attr = attr_first; attr != NULL; attr = attr->next) |
1471 | 0 | { |
1472 | 0 | if (attr->tag == tag) |
1473 | 0 | return attr; |
1474 | 0 | else if (attr->tag > tag) |
1475 | 0 | break; |
1476 | 0 | } |
1477 | 0 | return NULL; |
1478 | 0 | } |
1479 | | |
1480 | | /* Merge optional subsection S_ABFD into S_REF. S_FROZEN is used to report any |
1481 | | issue with the selected configuration, and to force the merge value to a |
1482 | | specific value if needed. */ |
1483 | | static |
1484 | | obj_attr_subsection_v2_t * |
1485 | | handle_optional_subsection_merge (const struct bfd_link_info *info, |
1486 | | const bfd *ref_bfd, const bfd *abfd, |
1487 | | obj_attr_subsection_v2_t *s_ref, |
1488 | | const obj_attr_subsection_v2_t *s_abfd, |
1489 | | const obj_attr_subsection_v2_t *s_frozen) |
1490 | 0 | { |
1491 | 0 | (void) info; |
1492 | | /* REF_BFD and ABFD are the same only when the call originated from |
1493 | | oav2_subsections_merge_frozen(), when FROZEN is merged into ABFD |
1494 | | (the future REF_BFD). See detailed explanation in oav2_attr_merge(). */ |
1495 | 0 | bool frozen_is_abfd = (ref_bfd == abfd); |
1496 | 0 | obj_attr_v2_t *a_ref = s_ref->first; |
1497 | 0 | const obj_attr_v2_t *a_abfd = s_abfd->first; |
1498 | 0 | obj_attr_v2_t *a_frozen_first = (s_frozen != NULL) ? s_frozen->first : NULL; |
1499 | 0 | while (a_ref != NULL && a_abfd != NULL) |
1500 | 0 | { |
1501 | 0 | uint32_t searched_frozen_tag |
1502 | 0 | = (a_ref->tag < a_abfd->tag |
1503 | 0 | ? a_ref->tag |
1504 | 0 | : a_abfd->tag); |
1505 | 0 | obj_attr_v2_t *a_frozen |
1506 | 0 | = oav2_search_by_tag (a_frozen_first, searched_frozen_tag); |
1507 | 0 | if (a_frozen != NULL) |
1508 | 0 | a_frozen_first = a_frozen; |
1509 | |
|
1510 | 0 | if (a_ref->tag < a_abfd->tag) |
1511 | 0 | { |
1512 | 0 | obj_attr_v2_t *a_default = oav2_attr_default (info, s_abfd, a_ref); |
1513 | 0 | obj_attr_v2_merge_result_t res |
1514 | 0 | = oav2_attr_merge (info, abfd, s_ref, a_ref, a_default, a_frozen, |
1515 | 0 | frozen_is_abfd); |
1516 | 0 | _bfd_elf_obj_attr_v2_free (a_default, s_ref->encoding); |
1517 | 0 | if (res.merge) |
1518 | 0 | oav2_assign_value (s_ref->encoding, a_ref, res.val); |
1519 | 0 | else if (res.reason == OAv2_MERGE_UNSUPPORTED) |
1520 | 0 | a_ref->status = obj_attr_v2_unknown; |
1521 | 0 | a_ref = a_ref->next; |
1522 | 0 | } |
1523 | 0 | else if (a_ref->tag > a_abfd->tag) |
1524 | 0 | { |
1525 | 0 | obj_attr_v2_t *a_default = oav2_attr_default (info, s_ref, a_abfd); |
1526 | 0 | obj_attr_v2_merge_result_t res |
1527 | 0 | = oav2_attr_merge (info, abfd, s_ref, a_default, a_abfd, a_frozen, |
1528 | 0 | frozen_is_abfd); |
1529 | 0 | if (res.merge || res.reason == OAv2_MERGE_SAME_VALUE_AS_REF) |
1530 | 0 | { |
1531 | 0 | oav2_assign_value (s_ref->encoding, a_default, res.val); |
1532 | 0 | LINKED_LIST_INSERT_BEFORE (obj_attr_v2_t) |
1533 | 0 | (s_ref, a_default, a_ref); |
1534 | 0 | } |
1535 | 0 | else |
1536 | 0 | _bfd_elf_obj_attr_v2_free (a_default, s_ref->encoding); |
1537 | 0 | a_abfd = a_abfd->next; |
1538 | 0 | } |
1539 | 0 | else |
1540 | 0 | { |
1541 | 0 | obj_attr_v2_merge_result_t res |
1542 | 0 | = oav2_attr_merge (info, abfd, s_ref, a_ref, a_abfd, a_frozen, |
1543 | 0 | frozen_is_abfd); |
1544 | 0 | if (res.merge) |
1545 | 0 | oav2_assign_value (s_ref->encoding, a_ref, res.val); |
1546 | 0 | else if (res.reason == OAv2_MERGE_UNSUPPORTED) |
1547 | 0 | a_ref->status = obj_attr_v2_unknown; |
1548 | 0 | a_ref = a_ref->next; |
1549 | 0 | a_abfd = a_abfd->next; |
1550 | 0 | } |
1551 | 0 | } |
1552 | |
|
1553 | 0 | for (; a_abfd != NULL; a_abfd = a_abfd->next) |
1554 | 0 | { |
1555 | 0 | obj_attr_v2_t *a_default = oav2_attr_default (info, s_ref, a_abfd); |
1556 | 0 | obj_attr_v2_merge_result_t res |
1557 | 0 | = oav2_attr_merge (info, abfd, s_ref, a_default, a_abfd, NULL, false); |
1558 | 0 | if (res.merge || res.reason == OAv2_MERGE_SAME_VALUE_AS_REF) |
1559 | 0 | { |
1560 | 0 | oav2_assign_value (s_ref->encoding, a_default, res.val); |
1561 | 0 | LINKED_LIST_APPEND (obj_attr_v2_t) (s_ref, a_default); |
1562 | 0 | } |
1563 | 0 | else |
1564 | 0 | _bfd_elf_obj_attr_v2_free (a_default, s_ref->encoding); |
1565 | 0 | } |
1566 | |
|
1567 | 0 | for (; a_ref != NULL; a_ref = a_ref->next) |
1568 | 0 | { |
1569 | 0 | obj_attr_v2_t *a_frozen = oav2_search_by_tag (a_frozen_first, a_ref->tag); |
1570 | 0 | if (a_frozen != NULL) |
1571 | 0 | a_frozen_first = a_frozen; |
1572 | |
|
1573 | 0 | obj_attr_v2_t *a_default = oav2_attr_default (info, s_abfd, a_ref); |
1574 | 0 | obj_attr_v2_merge_result_t res |
1575 | 0 | = oav2_attr_merge (info, abfd, s_ref, a_ref, a_default, a_frozen, |
1576 | 0 | frozen_is_abfd); |
1577 | 0 | _bfd_elf_obj_attr_v2_free (a_default, s_ref->encoding); |
1578 | 0 | if (res.merge) |
1579 | 0 | oav2_assign_value (s_ref->encoding, a_ref, res.val); |
1580 | 0 | else if (res.reason == OAv2_MERGE_UNSUPPORTED) |
1581 | 0 | a_ref->status = obj_attr_v2_unknown; |
1582 | 0 | } |
1583 | |
|
1584 | 0 | return s_ref; |
1585 | 0 | } |
1586 | | |
1587 | | /* Merge case 1: S_ABFD and S_REF exists, so merge S_ABFD into S_REF. */ |
1588 | | static obj_attr_subsection_v2_t * |
1589 | | handle_subsection_merge (const struct bfd_link_info *info, |
1590 | | const bfd *ref_bfd, const bfd *abfd, |
1591 | | obj_attr_subsection_v2_t *s_ref, |
1592 | | const obj_attr_subsection_v2_t *s_abfd, |
1593 | | const obj_attr_subsection_v2_t *s_frozen) |
1594 | 0 | { |
1595 | 0 | if (! s_ref->optional) |
1596 | 0 | return oav2_subsection_perfect_match (info, ref_bfd, abfd, s_ref, s_abfd); |
1597 | 0 | return handle_optional_subsection_merge |
1598 | 0 | (info, ref_bfd, abfd, s_ref, s_abfd, s_frozen); |
1599 | 0 | } |
1600 | | |
1601 | | /* Merge case 2: S_ABFD does not exist, but S_REF does. |
1602 | | 1. Create a new default-initialized S_ABFD. |
1603 | | 2. Merge S_ABFD into S_REF. */ |
1604 | | static bool |
1605 | | handle_subsection_missing (const struct bfd_link_info *info, |
1606 | | const bfd *ref_bfd, const bfd *abfd, |
1607 | | obj_attr_subsection_v2_t *s_ref, |
1608 | | const obj_attr_subsection_v2_t *s_frozen) |
1609 | 0 | { |
1610 | 0 | if (! s_ref->optional) |
1611 | 0 | { |
1612 | 0 | info->callbacks->einfo |
1613 | 0 | (_("%X%pB: error: missing required object attributes subsection %s\n"), |
1614 | 0 | abfd, s_ref->name); |
1615 | 0 | return false; |
1616 | 0 | } |
1617 | | |
1618 | | /* Compute default values of the missing attributes in ABFD, but present in |
1619 | | REF, and merge ABFD's generated subsection with the one of REF. */ |
1620 | 0 | obj_attr_subsection_v2_t *s_abfd = oav2_subsection_default_new (info, s_ref); |
1621 | 0 | const obj_attr_subsection_v2_t *merged |
1622 | 0 | = handle_subsection_merge (info, ref_bfd, abfd, s_ref, s_abfd, s_frozen); |
1623 | 0 | _bfd_elf_obj_attr_subsection_v2_free (s_abfd); |
1624 | 0 | return merged != NULL; |
1625 | 0 | } |
1626 | | |
1627 | | /* Merge case 3: S_ABFD does not have a S_REF equivalent. |
1628 | | 1. Create a new default-initialized S_REF subsection. |
1629 | | 2. Merge S_ABFD into S_REF. |
1630 | | 3. Insert S_REF into REF before S_REF_NEXT. */ |
1631 | | static bool |
1632 | | handle_subsection_additional (const struct bfd_link_info *info, |
1633 | | const bfd *ref_bfd, const bfd *abfd, |
1634 | | obj_attr_subsection_v2_t *s_ref_next, |
1635 | | const obj_attr_subsection_v2_t *s_abfd, |
1636 | | const obj_attr_subsection_v2_t *s_frozen) |
1637 | 0 | { |
1638 | 0 | if (! s_abfd->optional) |
1639 | 0 | { |
1640 | 0 | info->callbacks->einfo |
1641 | 0 | (_("%X%pB: error: missing required object attributes subsection %s\n"), |
1642 | 0 | ref_bfd, s_abfd->name); |
1643 | 0 | return false; |
1644 | 0 | } |
1645 | | |
1646 | | /* Compute default values of the missing attributes in REF, but present in |
1647 | | ABFD, and merge REF's generated subsection with the one of ABFD. */ |
1648 | 0 | obj_attr_subsection_v2_t *s_ref = oav2_subsection_default_new (info, s_abfd); |
1649 | 0 | obj_attr_subsection_v2_t *s_merged |
1650 | 0 | = handle_subsection_merge (info, ref_bfd, abfd, s_ref, s_abfd, s_frozen); |
1651 | 0 | if (s_merged != NULL) |
1652 | 0 | { |
1653 | 0 | LINKED_LIST_INSERT_BEFORE (obj_attr_subsection_v2_t) |
1654 | 0 | (&elf_obj_attr_subsections (ref_bfd), s_merged, s_ref_next); |
1655 | 0 | } |
1656 | 0 | else |
1657 | | /* An issue occurred during the merge. s_ref won't be saved so it needs to |
1658 | | be freed. */ |
1659 | 0 | _bfd_elf_obj_attr_subsection_v2_free (s_ref); |
1660 | 0 | return (s_merged != NULL); |
1661 | 0 | } |
1662 | | |
1663 | | /* Check whether a subsection is known, and if so, whether the current |
1664 | | properties of the subsection match the expected ones. |
1665 | | Return True if the subsection is known, AND all the properties of the |
1666 | | subsection match the expected. False otherwise. */ |
1667 | | static bool |
1668 | | oav2_subsection_match_known (const struct bfd_link_info *info, |
1669 | | const bfd *abfd, |
1670 | | const obj_attr_subsection_v2_t *subsec) |
1671 | 0 | { |
1672 | 0 | const known_subsection_v2_t *subsec_info |
1673 | 0 | = bfd_obj_attr_v2_identify_subsection (get_elf_backend_data (abfd), |
1674 | 0 | subsec->name); |
1675 | |
|
1676 | 0 | if (subsec_info == NULL) |
1677 | 0 | return false; |
1678 | | |
1679 | 0 | bool match = true; |
1680 | 0 | if (subsec_info->encoding != subsec->encoding) |
1681 | 0 | { |
1682 | 0 | info->callbacks->einfo |
1683 | 0 | (_("%X%pB: error: <%s> property of subsection '%s' was " |
1684 | 0 | "incorrectly set. Got '%s', expected '%s'\n"), |
1685 | 0 | abfd, "encoding", subsec->name, |
1686 | 0 | bfd_oav2_encoding_to_string (subsec->encoding), |
1687 | 0 | bfd_oav2_encoding_to_string (subsec_info->encoding)); |
1688 | 0 | match = false; |
1689 | 0 | } |
1690 | 0 | if (subsec_info->optional != subsec->optional) |
1691 | 0 | { |
1692 | 0 | info->callbacks->einfo |
1693 | 0 | (_("%X%pB: error: <%s> property of subsection '%s' was " |
1694 | 0 | "incorrectly set. Got '%s', expected '%s'\n"), |
1695 | 0 | abfd, "comprehension", subsec->name, |
1696 | 0 | bfd_oav2_comprehension_to_string (subsec->optional), |
1697 | 0 | bfd_oav2_comprehension_to_string (subsec_info->optional)); |
1698 | 0 | match = false; |
1699 | 0 | } |
1700 | 0 | return match; |
1701 | 0 | } |
1702 | | |
1703 | | /* Check whether the properties of the subsections S1 and S2 match. |
1704 | | Return True if the properties match, False otherwise. */ |
1705 | | static bool |
1706 | | oav2_subsection_generic_params_match (const struct bfd_link_info *info, |
1707 | | const bfd *f1, const bfd *f2, |
1708 | | const obj_attr_subsection_v2_t *s1, |
1709 | | const obj_attr_subsection_v2_t *s2) |
1710 | 0 | { |
1711 | 0 | bool match = (s1->encoding == s2->encoding && s1->optional == s2->optional); |
1712 | 0 | if (! match) |
1713 | 0 | { |
1714 | 0 | if (f1 != NULL) |
1715 | 0 | { |
1716 | 0 | info->callbacks->einfo ( |
1717 | 0 | _("%X%pB: error: mismatching properties of subsection '%s'\n"), |
1718 | 0 | f2, s1->name); |
1719 | 0 | info->callbacks->info ( |
1720 | 0 | _("%pB: info: conflicting properties (%s, %s) live here\n"), f1, |
1721 | 0 | bfd_oav2_comprehension_to_string (s1->optional), |
1722 | 0 | bfd_oav2_encoding_to_string (s1->encoding)); |
1723 | 0 | info->callbacks->info ( |
1724 | 0 | _("info: (%s, %s) VS (%s, %s)\n"), |
1725 | 0 | bfd_oav2_comprehension_to_string (s2->optional), |
1726 | 0 | bfd_oav2_encoding_to_string (s2->encoding), |
1727 | 0 | bfd_oav2_comprehension_to_string (s1->optional), |
1728 | 0 | bfd_oav2_encoding_to_string (s1->encoding)); |
1729 | 0 | } |
1730 | 0 | else |
1731 | 0 | { |
1732 | 0 | info->callbacks->einfo ( |
1733 | 0 | _("%X%pB: error: corrupted properties in subsection '%s'\n"), |
1734 | 0 | f2, s1->name); |
1735 | 0 | info->callbacks->info ( |
1736 | 0 | _("info: (%s, %s) VS (%s, %s)\n"), |
1737 | 0 | bfd_oav2_comprehension_to_string (s2->optional), |
1738 | 0 | bfd_oav2_encoding_to_string (s2->encoding), |
1739 | 0 | bfd_oav2_comprehension_to_string (s1->optional), |
1740 | 0 | bfd_oav2_encoding_to_string (s1->encoding)); |
1741 | 0 | } |
1742 | 0 | } |
1743 | 0 | return match; |
1744 | 0 | } |
1745 | | |
1746 | | /* Check for mismatch between the parameters of subsections S1 and S2. |
1747 | | Return True if the parameters mismatch, False otherwise. |
1748 | | Note: F1 can be null when comparing FROZEN and the first object file used to |
1749 | | store the merge result. If an error is reported, it means that one of the |
1750 | | definition of S1 or S2 is corrupted. Most likely S2 because it is a user |
1751 | | input, or S1 if it is a programmation error of FROZEN. In the second case, |
1752 | | please raise a bug to binutils bug tracker. */ |
1753 | | static bool |
1754 | | oav2_subsection_mismatching_params (const struct bfd_link_info *info, |
1755 | | const bfd *f1, const bfd *f2, |
1756 | | const obj_attr_subsection_v2_t *s1, |
1757 | | const obj_attr_subsection_v2_t *s2) |
1758 | 0 | { |
1759 | 0 | if (gnu_testing_namespace (s2->name)) |
1760 | 0 | return ! oav2_subsection_generic_params_match (info, f1, f2, s1, s2); |
1761 | | |
1762 | | /* Check whether the subsection is known, and if so, match against the |
1763 | | expected properties. |
1764 | | Note: this piece of code must be guarded against gnu-testing subsections, |
1765 | | as oav2_subsection_match_known() looks up at the known subsections. |
1766 | | Since the "fictive" entry for gnu-testing known subsection has random |
1767 | | values for its encoding and optionality, it won't be able to detect |
1768 | | mismatching parameters correctly. */ |
1769 | 0 | return ! oav2_subsection_match_known (info, f2, s2); |
1770 | 0 | } |
1771 | | |
1772 | | /* Merge object attributes from FROZEN into the object file ABFD. |
1773 | | Note: this function is called only once before starting the merge process |
1774 | | between the object files. ABFD corresponds to the future REF_BFD, and is |
1775 | | used to store the result of the merge. ABFD is also an input file, so any |
1776 | | mismatch against FROZEN should be raised before the values of ABFD be |
1777 | | modified. */ |
1778 | | static bool |
1779 | | oav2_subsections_merge_frozen (const struct bfd_link_info *info, |
1780 | | const bfd *abfd, |
1781 | | const obj_attr_subsection_list_t *frozen_cfg) |
1782 | 0 | { |
1783 | 0 | const obj_attr_subsection_v2_t *s_frozen = frozen_cfg->first; |
1784 | 0 | if (s_frozen == NULL) |
1785 | 0 | return true; |
1786 | | |
1787 | 0 | bool success = true; |
1788 | | |
1789 | | /* Note: all the handle_subsection_* functions call oav2_attr_merge() down the |
1790 | | stack. Passing ABFD as REF_BFD allows to detect that this function is |
1791 | | the caller. Then a special behavior in oav2_attr_merge() is triggered for |
1792 | | this specific use case, so that we can obtain the right diagnostics. */ |
1793 | |
|
1794 | 0 | obj_attr_subsection_v2_t *s_abfd = elf_obj_attr_subsections (abfd).first; |
1795 | 0 | while (s_frozen != NULL && s_abfd != NULL) |
1796 | 0 | { |
1797 | 0 | int cmp = strcmp (s_abfd->name, s_frozen->name); |
1798 | 0 | if (cmp < 0) /* ABFD has a subsection that FROZEN doesn't have. */ |
1799 | 0 | { |
1800 | | /* No need to try to merge anything here. */ |
1801 | 0 | s_abfd = s_abfd->next; |
1802 | 0 | } |
1803 | 0 | else if (cmp > 0) /* FROZEN has a subsection that ABFD doesn't have. */ |
1804 | 0 | { |
1805 | 0 | success &= handle_subsection_additional (info, abfd, abfd, |
1806 | 0 | s_abfd, s_frozen, s_frozen); |
1807 | 0 | s_frozen = s_frozen->next; |
1808 | 0 | } |
1809 | 0 | else /* Both ABFD and frozen have the subsection. */ |
1810 | 0 | { |
1811 | 0 | bool mismatch = oav2_subsection_mismatching_params (info, NULL, abfd, |
1812 | 0 | s_frozen, s_abfd); |
1813 | 0 | success &= ! mismatch; |
1814 | 0 | if (mismatch) |
1815 | | /* FROZEN cannot be corrupted as it is generated from the command |
1816 | | line arguments. If it is corrupted, it is a bug. */ |
1817 | 0 | s_abfd->status = obj_attr_subsection_v2_corrupted; |
1818 | 0 | else |
1819 | 0 | success &= (handle_subsection_merge (info, abfd, abfd, |
1820 | 0 | s_abfd, s_frozen, s_frozen) != NULL); |
1821 | |
|
1822 | 0 | s_abfd = s_abfd->next; |
1823 | 0 | s_frozen = s_frozen->next; |
1824 | 0 | } |
1825 | 0 | } |
1826 | | |
1827 | | /* No need to go through the remaining sections of ABFD, only mismatches |
1828 | | against FROZEN are interesting. */ |
1829 | |
|
1830 | 0 | for (; s_frozen != NULL; s_frozen = s_frozen->next) |
1831 | 0 | success &= handle_subsection_additional (info, abfd, abfd, |
1832 | 0 | elf_obj_attr_subsections (abfd).last, s_frozen, s_frozen); |
1833 | |
|
1834 | 0 | return success; |
1835 | 0 | } |
1836 | | |
1837 | | /* Merge object attributes from object file ABFD and FROZEN_CFG into REF_BFD. */ |
1838 | | static bool |
1839 | | oav2_subsections_merge (const struct bfd_link_info *info, |
1840 | | const bfd *ref_bfd, bfd *abfd, |
1841 | | const obj_attr_subsection_list_t *frozen_cfg) |
1842 | 0 | { |
1843 | 0 | bool success = true; |
1844 | 0 | obj_attr_subsection_list_t *abfd_subsecs = &elf_obj_attr_subsections (abfd); |
1845 | 0 | obj_attr_subsection_list_t *ref_subsecs = &elf_obj_attr_subsections (ref_bfd); |
1846 | |
|
1847 | 0 | obj_attr_subsection_v2_t *s_frozen_first = frozen_cfg->first; |
1848 | 0 | obj_attr_subsection_v2_t *s_abfd = abfd_subsecs->first; |
1849 | 0 | obj_attr_subsection_v2_t *s_ref = ref_subsecs->first; |
1850 | |
|
1851 | 0 | while (s_abfd != NULL && s_ref != NULL) |
1852 | 0 | { |
1853 | 0 | int cmp = strcmp (s_ref->name, s_abfd->name); |
1854 | |
|
1855 | 0 | if (cmp < 0) /* REF has a subsection that ABFD doesn't have. */ |
1856 | 0 | { |
1857 | 0 | if (s_ref->status != obj_attr_subsection_v2_ok) |
1858 | 0 | { |
1859 | 0 | s_ref = s_ref->next; |
1860 | 0 | continue; |
1861 | 0 | } |
1862 | | |
1863 | 0 | obj_attr_subsection_v2_t *s_frozen |
1864 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (s_frozen_first, |
1865 | 0 | s_ref->name, |
1866 | 0 | true); |
1867 | | |
1868 | | /* Mismatching between REF and FROZEN already done in |
1869 | | oav2_subsections_merge_frozen. */ |
1870 | 0 | success &= handle_subsection_missing (info, ref_bfd, abfd, s_ref, |
1871 | 0 | s_frozen); |
1872 | |
|
1873 | 0 | if (s_frozen != NULL) |
1874 | 0 | s_frozen_first = s_frozen->next; |
1875 | 0 | s_ref = s_ref->next; |
1876 | 0 | } |
1877 | 0 | else if (cmp > 0) /* ABFD has a subsection that REF doesn't have. */ |
1878 | 0 | { |
1879 | 0 | if (s_abfd->status != obj_attr_subsection_v2_ok) |
1880 | 0 | { |
1881 | 0 | s_abfd = s_abfd->next; |
1882 | 0 | continue; |
1883 | 0 | } |
1884 | | |
1885 | 0 | obj_attr_subsection_v2_t *s_frozen |
1886 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (s_frozen_first, |
1887 | 0 | s_abfd->name, |
1888 | 0 | true); |
1889 | 0 | if (s_frozen != NULL) |
1890 | 0 | { |
1891 | | /* Check any mismatch against ABFD and FROZEN. */ |
1892 | 0 | bool mismatch = oav2_subsection_mismatching_params (info, NULL, |
1893 | 0 | abfd, s_frozen, s_abfd); |
1894 | 0 | success &= ! mismatch; |
1895 | 0 | if (mismatch) |
1896 | 0 | s_abfd->status = obj_attr_subsection_v2_corrupted; |
1897 | 0 | else |
1898 | 0 | success &= handle_subsection_additional (info, ref_bfd, abfd, |
1899 | 0 | s_ref, s_abfd, s_frozen); |
1900 | 0 | } |
1901 | 0 | else |
1902 | 0 | success &= handle_subsection_additional (info, ref_bfd, abfd, s_ref, |
1903 | 0 | s_abfd, NULL); |
1904 | |
|
1905 | 0 | if (s_frozen != NULL) |
1906 | 0 | s_frozen_first = s_frozen->next; |
1907 | 0 | s_abfd = s_abfd->next; |
1908 | 0 | } |
1909 | 0 | else /* Both REF and ABFD have the subsection. */ |
1910 | 0 | { |
1911 | 0 | if (s_ref->status != obj_attr_subsection_v2_ok) |
1912 | 0 | { |
1913 | 0 | s_ref = s_ref->next; |
1914 | 0 | s_abfd = s_abfd->next; |
1915 | 0 | continue; |
1916 | 0 | } |
1917 | | |
1918 | 0 | obj_attr_subsection_v2_t *s_frozen |
1919 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (s_frozen_first, |
1920 | 0 | s_ref->name, |
1921 | 0 | true); |
1922 | |
|
1923 | 0 | bool mismatch = oav2_subsection_mismatching_params |
1924 | 0 | (info, ref_bfd, abfd, s_ref, s_abfd); |
1925 | 0 | success &= ! mismatch; |
1926 | 0 | if (mismatch) |
1927 | 0 | s_abfd->status = obj_attr_subsection_v2_corrupted; |
1928 | 0 | else |
1929 | 0 | success &= (handle_subsection_merge (info, ref_bfd, abfd, s_ref, |
1930 | 0 | s_abfd, s_frozen) != NULL); |
1931 | |
|
1932 | 0 | if (s_frozen != NULL) |
1933 | 0 | s_frozen_first = s_frozen->next; |
1934 | 0 | s_ref = s_ref->next; |
1935 | 0 | s_abfd = s_abfd->next; |
1936 | 0 | } |
1937 | 0 | } |
1938 | |
|
1939 | 0 | for (; s_abfd != NULL; s_abfd = s_abfd->next) |
1940 | 0 | { |
1941 | 0 | if (s_abfd->status != obj_attr_subsection_v2_ok) |
1942 | 0 | continue; |
1943 | | |
1944 | 0 | obj_attr_subsection_v2_t *s_frozen |
1945 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (s_frozen_first, |
1946 | 0 | s_abfd->name, |
1947 | 0 | true); |
1948 | 0 | if (s_frozen != NULL) |
1949 | 0 | { |
1950 | 0 | bool mismatch = oav2_subsection_mismatching_params (info, NULL, abfd, |
1951 | 0 | s_frozen, s_abfd); |
1952 | 0 | success &= ! mismatch; |
1953 | 0 | if (mismatch) |
1954 | 0 | s_abfd->status = obj_attr_subsection_v2_corrupted; |
1955 | 0 | else |
1956 | 0 | success &= handle_subsection_additional (info, ref_bfd, abfd, |
1957 | 0 | ref_subsecs->last, s_abfd, |
1958 | 0 | s_frozen); |
1959 | 0 | } |
1960 | 0 | else |
1961 | 0 | success &= handle_subsection_additional (info, ref_bfd, abfd, |
1962 | 0 | ref_subsecs->last, s_abfd, |
1963 | 0 | NULL); |
1964 | 0 | } |
1965 | |
|
1966 | 0 | for (; s_ref != NULL; s_ref = s_ref->next) |
1967 | 0 | { |
1968 | 0 | if (s_ref->status != obj_attr_subsection_v2_ok) |
1969 | 0 | continue; |
1970 | | |
1971 | 0 | obj_attr_subsection_v2_t *s_frozen |
1972 | 0 | = bfd_obj_attr_subsection_v2_find_by_name (s_frozen_first, |
1973 | 0 | s_ref->name, |
1974 | 0 | true); |
1975 | | /* No need to check for matching parameters here as frozen has already |
1976 | | been checked against ref. */ |
1977 | 0 | success &= handle_subsection_missing (info, ref_bfd, abfd, s_ref, s_frozen); |
1978 | 0 | } |
1979 | |
|
1980 | 0 | return success; |
1981 | 0 | } |
1982 | | |
1983 | | /* Wrapper for the high-level logic of merging a single file. |
1984 | | It handles both of the following cases: |
1985 | | - ABFD (future REF_BFD) merged against FROZEN. |
1986 | | - ABFD (input) and FROZEN_CFG merged into REF_BFD. |
1987 | | If has_obj_attrs_after_translation is non-NULL, the caller is responsible for |
1988 | | the distinction between the cases where attributes are already present, or |
1989 | | where attributes were added as a result of a translation of GNU properties. |
1990 | | The first step translates existing GNU properties to object attributes. Next, |
1991 | | any duplicates entries in the input are merged, and the resulting object |
1992 | | attributes are written back into GNU properties so that the GNU properties |
1993 | | merge process can correctly diagnose potential issues. Before merging, |
1994 | | unknown subsections and attributes are marked so they can be skipped during |
1995 | | processing. |
1996 | | Return True on success, False on failure. */ |
1997 | | static bool |
1998 | | oav2_merge_one (const struct bfd_link_info *info, |
1999 | | bfd *ref_bfd, bfd *abfd, |
2000 | | const obj_attr_subsection_list_t *frozen_cfg, |
2001 | | bool *has_obj_attrs_after_translation) |
2002 | 0 | { |
2003 | | /* ABFD is an input file that may contain GNU properties, object |
2004 | | attributes, or both. Before merging object attributes, we must first |
2005 | | translate any GNU properties into their equivalent object attributes |
2006 | | (if such equivalents exist) since they may not already be present. */ |
2007 | 0 | oav2_translate_gnu_props_to_obj_attrs (abfd); |
2008 | 0 | if (has_obj_attrs_after_translation |
2009 | 0 | && elf_obj_attr_subsections (abfd).size > 0) |
2010 | 0 | *has_obj_attrs_after_translation = true; |
2011 | | |
2012 | | /* Merge duplicates subsections and attributes. */ |
2013 | 0 | if (! oav2_file_scope_merge_subsections (abfd)) |
2014 | 0 | return false; |
2015 | | |
2016 | | /* ABFD is an input file that may contain GNU properties, object |
2017 | | attributes, or both. Before merging GNU properties, we must first |
2018 | | translate any object attributes into their equivalent GNU properties |
2019 | | (if such equivalents exist) since they may not already be present. */ |
2020 | 0 | oav2_translate_obj_attrs_to_gnu_props (abfd); |
2021 | | |
2022 | | /* Note: object attributes are always merged before GNU properties. |
2023 | | Ideally, there would be a single internal representation, with an |
2024 | | abstraction level flexible enough to capture both GNU properties and |
2025 | | object attributes without loss. In such a design, merge order would |
2026 | | be irrelevant, and translation would occur only at the I/O boundaries |
2027 | | during deserialization of GNU properties and object attributes. */ |
2028 | | |
2029 | | /* Mark unknown subsections and attributes to skip them during |
2030 | | the merge. */ |
2031 | 0 | oav2_subsections_mark_unknown (abfd); |
2032 | |
|
2033 | 0 | if (ref_bfd == NULL) |
2034 | | /* When REF_BFD is null, it means that ABFD is the future REF_BFD, and |
2035 | | will be accumulating the merge result. |
2036 | | It means that we will lose information from ABFD beyond this stage, |
2037 | | so we need to emit warnings / errors (if any) when merging ABFD |
2038 | | against FROZEN. */ |
2039 | 0 | return oav2_subsections_merge_frozen (info, abfd, frozen_cfg); |
2040 | | |
2041 | | /* Common merge case. */ |
2042 | 0 | return oav2_subsections_merge (info, ref_bfd, abfd, frozen_cfg); |
2043 | 0 | } |
2044 | | |
2045 | | /* Merge all the object attributes in INPUT_BFDS (REF_BFD excluded) into |
2046 | | REF_BFD. Return True on success, False otherwise. */ |
2047 | | static bool |
2048 | | oav2_merge_all (const struct bfd_link_info *info, |
2049 | | bfd *ref_bfd, bfd *input_bfds, |
2050 | | obj_attr_subsection_list_t *frozen_cfg) |
2051 | 0 | { |
2052 | 0 | bool success = true; |
2053 | 0 | for (bfd *abfd = input_bfds; abfd != NULL; abfd = abfd->link.next) |
2054 | 0 | { |
2055 | 0 | if (abfd != ref_bfd && oav2_relevant_elf_object (info, abfd)) |
2056 | 0 | success &= oav2_merge_one (info, ref_bfd, abfd, frozen_cfg, NULL); |
2057 | 0 | } |
2058 | 0 | return success; |
2059 | 0 | } |
2060 | | |
2061 | | /* Prune the given attribute, and return the next one in the list. */ |
2062 | | static obj_attr_v2_t * |
2063 | | oav2_attr_delete (obj_attr_subsection_v2_t *subsec, |
2064 | | obj_attr_v2_t *attr) |
2065 | 0 | { |
2066 | 0 | obj_attr_v2_t *next = attr->next; |
2067 | 0 | LINKED_LIST_REMOVE (obj_attr_v2_t) (subsec, attr); |
2068 | 0 | _bfd_elf_obj_attr_v2_free (attr, subsec->encoding); |
2069 | 0 | return next; |
2070 | 0 | } |
2071 | | |
2072 | | /* Prune the given subsection, and return the next one in the list. */ |
2073 | | static obj_attr_subsection_v2_t * |
2074 | | oav2_subsec_delete (obj_attr_subsection_list_t *plist, |
2075 | | obj_attr_subsection_v2_t *subsec) |
2076 | 224 | { |
2077 | 224 | obj_attr_subsection_v2_t *next = subsec->next; |
2078 | 224 | LINKED_LIST_REMOVE (obj_attr_subsection_v2_t) (plist, subsec); |
2079 | 224 | _bfd_elf_obj_attr_subsection_v2_free (subsec); |
2080 | 224 | return next; |
2081 | 224 | } |
2082 | | |
2083 | | /* Prune any attributes with a status different from obj_attr_v2_ok in the |
2084 | | given subsection. */ |
2085 | | static void |
2086 | | oav2_attrs_prune_nok (const struct bfd_link_info *info, |
2087 | | obj_attr_subsection_v2_t *subsec) |
2088 | 0 | { |
2089 | 0 | const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); |
2090 | 0 | for (obj_attr_v2_t *attr = subsec->first; |
2091 | 0 | attr != NULL;) |
2092 | 0 | { |
2093 | 0 | if (attr->status != obj_attr_v2_ok) |
2094 | 0 | { |
2095 | 0 | const char *tag_s |
2096 | 0 | = _bfd_obj_attr_v2_tag_to_string (bed, subsec->name, attr->tag); |
2097 | 0 | info->callbacks->minfo |
2098 | 0 | (_("Removed attribute '%s' from '%s'\n"), tag_s, subsec->name); |
2099 | 0 | free ((char *) tag_s); |
2100 | 0 | attr = oav2_attr_delete (subsec, attr); |
2101 | 0 | } |
2102 | 0 | else |
2103 | 0 | attr = attr->next; |
2104 | 0 | } |
2105 | 0 | } |
2106 | | |
2107 | | /* Prune any subsection with a status different from obj_attr_subsection_v2_ok |
2108 | | in the given list of subsections. */ |
2109 | | static void |
2110 | | oav2_subsecs_prune_nok (const struct bfd_link_info *info, |
2111 | | obj_attr_subsection_list_t *plist) |
2112 | 0 | { |
2113 | 0 | for (obj_attr_subsection_v2_t *subsec = plist->first; |
2114 | 0 | subsec != NULL;) |
2115 | 0 | { |
2116 | 0 | if (subsec->status == obj_attr_subsection_v2_ok) |
2117 | 0 | oav2_attrs_prune_nok (info, subsec); |
2118 | |
|
2119 | 0 | if (subsec->size == 0 || subsec->status != obj_attr_subsection_v2_ok) |
2120 | 0 | { |
2121 | 0 | info->callbacks->minfo (_("Removed subsection '%s'\n"), subsec->name); |
2122 | 0 | subsec = oav2_subsec_delete (plist, subsec); |
2123 | 0 | } |
2124 | 0 | else |
2125 | 0 | subsec = subsec->next; |
2126 | 0 | } |
2127 | 0 | } |
2128 | | |
2129 | | /* Prune any subsection or attribute with a status different from OK. */ |
2130 | | static bool |
2131 | | oav2_prune_nok_attrs (const struct bfd_link_info *info, bfd *abfd) |
2132 | 0 | { |
2133 | 0 | obj_attr_subsection_list_t *plist = &elf_obj_attr_subsections (abfd); |
2134 | 0 | oav2_subsecs_prune_nok (info, plist); |
2135 | 0 | return (plist->size != 0); |
2136 | 0 | } |
2137 | | |
2138 | | /* Set up object attributes coming from configuration, and merge them with the |
2139 | | ones from the input object files. Return a pointer to the input object file |
2140 | | containing the merge result on success, NULL otherwise. */ |
2141 | | bfd * |
2142 | | _bfd_elf_link_setup_object_attributes (struct bfd_link_info *info) |
2143 | 0 | { |
2144 | 0 | obj_attr_subsection_list_t *frozen_cfg |
2145 | 0 | = &elf_obj_attr_subsections (info->output_bfd); |
2146 | |
|
2147 | 0 | bfd_search_result_t res |
2148 | 0 | = bfd_linear_find_first_with_obj_attrs (info); |
2149 | | |
2150 | | /* If res.pbfd is NULL, it means that it didn't find any ELF object files. */ |
2151 | 0 | if (res.pbfd == NULL) |
2152 | 0 | return NULL; |
2153 | | |
2154 | | /* Sort the frozen subsections and attributes in case that they were not |
2155 | | inserted in the correct order. */ |
2156 | 0 | oav2_sort_subsections (frozen_cfg); |
2157 | | |
2158 | | /* Merge object attributes sections. */ |
2159 | 0 | info->callbacks->minfo ("\n"); |
2160 | 0 | info->callbacks->minfo (_("Merging object attributes\n")); |
2161 | 0 | info->callbacks->minfo ("\n"); |
2162 | |
|
2163 | 0 | bool success = oav2_merge_one (info, NULL, res.pbfd, frozen_cfg, |
2164 | 0 | &res.has_object_attributes); |
2165 | | |
2166 | | /* No frozen object attributes and no object file, so nothing to do. */ |
2167 | 0 | if (!res.has_object_attributes && frozen_cfg->size == 0) |
2168 | 0 | return NULL; |
2169 | | /* If frozen object attributes were set by some command-line options, we still |
2170 | | need to emit warnings / errors if incompatibilities exist. */ |
2171 | | |
2172 | | /* Set the object attribute version for the output object to the recommended |
2173 | | value by the backend. */ |
2174 | 0 | elf_obj_attr_version (info->output_bfd) |
2175 | 0 | = get_elf_backend_data (info->output_bfd)->default_obj_attr_version; |
2176 | |
|
2177 | 0 | if (res.sec == NULL) |
2178 | 0 | { |
2179 | | /* This input object has no object attribute section matching the name and |
2180 | | type specified by the backend, i.e. elf_backend_obj_attrs_section and |
2181 | | elf_backend_obj_attrs_section_type. |
2182 | | One of the two following cases is possible: |
2183 | | 1. No object attribute were found in this file, so the object attribute |
2184 | | version was never set by the deserializer. |
2185 | | 2. The deserializer might have found attributes in another section with |
2186 | | the correct type but the wrong name. The object attribute version |
2187 | | should have been set correctly in this case. |
2188 | | Whatever of those two cases, we set the object attribute version to the |
2189 | | backend's recommended value, and create a new section with the expected |
2190 | | name and type. */ |
2191 | 0 | elf_obj_attr_version (res.pbfd) |
2192 | 0 | = get_elf_backend_data (res.pbfd)->default_obj_attr_version; |
2193 | 0 | res.sec = create_object_attributes_section (info, res.pbfd); |
2194 | 0 | } |
2195 | | |
2196 | | /* Merge all the input object files againt res.pbfd and frozen_cfg, and |
2197 | | accumulate the merge result in res.pbfd. */ |
2198 | 0 | success &= oav2_merge_all (info, res.pbfd, info->input_bfds, frozen_cfg); |
2199 | 0 | if (! success) |
2200 | 0 | return NULL; |
2201 | | |
2202 | | /* Prune all subsections and attributes with a status different from OK. */ |
2203 | 0 | if (! oav2_prune_nok_attrs (info, res.pbfd)) |
2204 | 0 | return NULL; |
2205 | 0 | BFD_ASSERT (elf_obj_attr_subsections (res.pbfd).size > 0); |
2206 | | |
2207 | | /* Swap the old object attributes stored in output_bfd (i.e. the frozen |
2208 | | config) with the final merge result. */ |
2209 | 0 | LINKED_LIST_SWAP_LISTS (obj_attr_subsection_list_t) |
2210 | 0 | (&elf_obj_attr_subsections (info->output_bfd), |
2211 | 0 | &elf_obj_attr_subsections (res.pbfd)); |
2212 | | |
2213 | | /* Note: the object attributes section in the output object is copied from |
2214 | | the input object which was used for the merge (res.pbfd). No need to |
2215 | | create it here. However, so that the section is copied to the output |
2216 | | object, the size must be different from 0. For now, we will set this |
2217 | | size to 1. The real size will be set later. */ |
2218 | 0 | res.sec->size = 1; |
2219 | |
|
2220 | 0 | return res.pbfd; |
2221 | 0 | } |
2222 | | |
2223 | | /* Allocate/find an object attribute. */ |
2224 | | obj_attribute * |
2225 | | bfd_elf_new_obj_attr (bfd *abfd, obj_attr_vendor_t vendor, obj_attr_tag_t tag) |
2226 | 190k | { |
2227 | 190k | obj_attribute *attr; |
2228 | 190k | obj_attribute_list *list; |
2229 | 190k | obj_attribute_list *p; |
2230 | 190k | obj_attribute_list **lastp; |
2231 | | |
2232 | | |
2233 | 190k | if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) |
2234 | 157k | { |
2235 | | /* Known tags are preallocated. */ |
2236 | 157k | attr = &elf_known_obj_attributes (abfd)[vendor][tag]; |
2237 | 157k | } |
2238 | 33.1k | else |
2239 | 33.1k | { |
2240 | | /* Create a new tag. */ |
2241 | 33.1k | list = (obj_attribute_list *) |
2242 | 33.1k | bfd_alloc (abfd, sizeof (obj_attribute_list)); |
2243 | 33.1k | if (list == NULL) |
2244 | 0 | return NULL; |
2245 | 33.1k | memset (list, 0, sizeof (obj_attribute_list)); |
2246 | 33.1k | list->tag = tag; |
2247 | | /* Keep the tag list in order. */ |
2248 | 33.1k | lastp = &elf_other_obj_attributes (abfd)[vendor]; |
2249 | 956k | for (p = *lastp; p; p = p->next) |
2250 | 951k | { |
2251 | 951k | if (tag < p->tag) |
2252 | 28.1k | break; |
2253 | 923k | lastp = &p->next; |
2254 | 923k | } |
2255 | 33.1k | list->next = *lastp; |
2256 | 33.1k | *lastp = list; |
2257 | 33.1k | attr = &list->attr; |
2258 | 33.1k | } |
2259 | | |
2260 | 190k | return attr; |
2261 | 190k | } |
2262 | | |
2263 | | /* Return the value of an integer object attribute. */ |
2264 | | int |
2265 | | bfd_elf_get_obj_attr_int (bfd *abfd, |
2266 | | obj_attr_vendor_t vendor, |
2267 | | obj_attr_tag_t tag) |
2268 | 946 | { |
2269 | 946 | obj_attribute_list *p; |
2270 | | |
2271 | 946 | if (tag < NUM_KNOWN_OBJ_ATTRIBUTES) |
2272 | 946 | { |
2273 | | /* Known tags are preallocated. */ |
2274 | 946 | return elf_known_obj_attributes (abfd)[vendor][tag].i; |
2275 | 946 | } |
2276 | 0 | else |
2277 | 0 | { |
2278 | 0 | for (p = elf_other_obj_attributes (abfd)[vendor]; |
2279 | 0 | p; |
2280 | 0 | p = p->next) |
2281 | 0 | { |
2282 | 0 | if (tag == p->tag) |
2283 | 0 | return p->attr.i; |
2284 | 0 | if (tag < p->tag) |
2285 | 0 | break; |
2286 | 0 | } |
2287 | 0 | return 0; |
2288 | 0 | } |
2289 | 946 | } |
2290 | | |
2291 | | /* Add an integer object attribute. */ |
2292 | | obj_attribute * |
2293 | | bfd_elf_add_obj_attr_int (bfd *abfd, |
2294 | | obj_attr_vendor_t vendor, |
2295 | | obj_attr_tag_t tag, |
2296 | | unsigned int value) |
2297 | 155k | { |
2298 | 155k | obj_attribute *attr; |
2299 | | |
2300 | 155k | attr = bfd_elf_new_obj_attr (abfd, vendor, tag); |
2301 | 155k | if (attr != NULL) |
2302 | 155k | { |
2303 | 155k | attr->type = bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
2304 | 155k | attr->i = value; |
2305 | 155k | } |
2306 | 155k | return attr; |
2307 | 155k | } |
2308 | | |
2309 | | /* Duplicate an object attribute string value. */ |
2310 | | static char * |
2311 | | elf_attr_strdup (bfd *abfd, const char *s, const char *end) |
2312 | 35.0k | { |
2313 | 35.0k | char *p; |
2314 | 35.0k | size_t len; |
2315 | | |
2316 | 35.0k | if (end) |
2317 | 35.0k | len = strnlen (s, end - s); |
2318 | 0 | else |
2319 | 0 | len = strlen (s); |
2320 | | |
2321 | 35.0k | p = (char *) bfd_alloc (abfd, len + 1); |
2322 | 35.0k | if (p != NULL) |
2323 | 35.0k | { |
2324 | 35.0k | memcpy (p, s, len); |
2325 | 35.0k | p[len] = 0; |
2326 | 35.0k | } |
2327 | 35.0k | return p; |
2328 | 35.0k | } |
2329 | | |
2330 | | char * |
2331 | | _bfd_elf_attr_strdup (bfd *abfd, const char *s) |
2332 | 0 | { |
2333 | 0 | return elf_attr_strdup (abfd, s, NULL); |
2334 | 0 | } |
2335 | | |
2336 | | /* Add a string object attribute. */ |
2337 | | static obj_attribute * |
2338 | | elf_add_obj_attr_string (bfd *abfd, obj_attr_vendor_t vendor, obj_attr_tag_t tag, |
2339 | | const char *s, const char *end) |
2340 | 31.3k | { |
2341 | 31.3k | obj_attribute *attr; |
2342 | | |
2343 | 31.3k | attr = bfd_elf_new_obj_attr (abfd, vendor, tag); |
2344 | 31.3k | if (attr != NULL) |
2345 | 31.3k | { |
2346 | 31.3k | attr->type = bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
2347 | 31.3k | attr->s = elf_attr_strdup (abfd, s, end); |
2348 | 31.3k | if (attr->s == NULL) |
2349 | 0 | return NULL; |
2350 | 31.3k | } |
2351 | 31.3k | return attr; |
2352 | 31.3k | } |
2353 | | |
2354 | | obj_attribute * |
2355 | | bfd_elf_add_obj_attr_string (bfd *abfd, |
2356 | | obj_attr_vendor_t vendor, |
2357 | | obj_attr_tag_t tag, |
2358 | | const char *s) |
2359 | 0 | { |
2360 | 0 | return elf_add_obj_attr_string (abfd, vendor, tag, s, NULL); |
2361 | 0 | } |
2362 | | |
2363 | | /* Add a int+string object attribute. */ |
2364 | | static obj_attribute * |
2365 | | elf_add_obj_attr_int_string (bfd *abfd, |
2366 | | obj_attr_vendor_t vendor, |
2367 | | obj_attr_tag_t tag, |
2368 | | unsigned int i, |
2369 | | const char *s, |
2370 | | const char *end) |
2371 | 3.64k | { |
2372 | 3.64k | obj_attribute *attr; |
2373 | | |
2374 | 3.64k | attr = bfd_elf_new_obj_attr (abfd, vendor, tag); |
2375 | 3.64k | if (attr != NULL) |
2376 | 3.64k | { |
2377 | 3.64k | attr->type = bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
2378 | 3.64k | attr->i = i; |
2379 | 3.64k | attr->s = elf_attr_strdup (abfd, s, end); |
2380 | 3.64k | if (attr->s == NULL) |
2381 | 0 | return NULL; |
2382 | 3.64k | } |
2383 | 3.64k | return attr; |
2384 | 3.64k | } |
2385 | | |
2386 | | obj_attribute * |
2387 | | bfd_elf_add_obj_attr_int_string (bfd *abfd, |
2388 | | obj_attr_vendor_t vendor, |
2389 | | obj_attr_tag_t tag, |
2390 | | unsigned int i, |
2391 | | const char *s) |
2392 | 0 | { |
2393 | 0 | return elf_add_obj_attr_int_string (abfd, vendor, tag, i, s, NULL); |
2394 | 0 | } |
2395 | | |
2396 | | /* Copy object attributes v1 from IBFD to OBFD. */ |
2397 | | static void |
2398 | | oav1_copy_attributes (bfd *ibfd, bfd *obfd) |
2399 | 0 | { |
2400 | 0 | obj_attribute *in_attr; |
2401 | 0 | obj_attribute *out_attr; |
2402 | 0 | obj_attribute_list *list; |
2403 | 0 | int i; |
2404 | 0 | obj_attr_vendor_t vendor; |
2405 | |
|
2406 | 0 | for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) |
2407 | 0 | { |
2408 | 0 | in_attr |
2409 | 0 | = &elf_known_obj_attributes (ibfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; |
2410 | 0 | out_attr |
2411 | 0 | = &elf_known_obj_attributes (obfd)[vendor][LEAST_KNOWN_OBJ_ATTRIBUTE]; |
2412 | 0 | for (i = LEAST_KNOWN_OBJ_ATTRIBUTE; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++) |
2413 | 0 | { |
2414 | 0 | out_attr->type = in_attr->type; |
2415 | 0 | out_attr->i = in_attr->i; |
2416 | 0 | if (in_attr->s && *in_attr->s) |
2417 | 0 | { |
2418 | 0 | out_attr->s = _bfd_elf_attr_strdup (obfd, in_attr->s); |
2419 | 0 | if (out_attr->s == NULL) |
2420 | 0 | bfd_perror (_("error adding attribute")); |
2421 | 0 | } |
2422 | 0 | in_attr++; |
2423 | 0 | out_attr++; |
2424 | 0 | } |
2425 | |
|
2426 | 0 | for (list = elf_other_obj_attributes (ibfd)[vendor]; |
2427 | 0 | list; |
2428 | 0 | list = list->next) |
2429 | 0 | { |
2430 | 0 | bool ok = false; |
2431 | 0 | in_attr = &list->attr; |
2432 | 0 | switch (in_attr->type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) |
2433 | 0 | { |
2434 | 0 | case ATTR_TYPE_FLAG_INT_VAL: |
2435 | 0 | ok = bfd_elf_add_obj_attr_int (obfd, vendor, |
2436 | 0 | list->tag, in_attr->i); |
2437 | 0 | break; |
2438 | 0 | case ATTR_TYPE_FLAG_STR_VAL: |
2439 | 0 | ok = bfd_elf_add_obj_attr_string (obfd, vendor, list->tag, |
2440 | 0 | in_attr->s); |
2441 | 0 | break; |
2442 | 0 | case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: |
2443 | 0 | ok = bfd_elf_add_obj_attr_int_string (obfd, vendor, list->tag, |
2444 | 0 | in_attr->i, in_attr->s); |
2445 | 0 | break; |
2446 | 0 | default: |
2447 | 0 | abort (); |
2448 | 0 | } |
2449 | 0 | if (!ok) |
2450 | 0 | bfd_perror (_("error adding attribute")); |
2451 | 0 | } |
2452 | 0 | } |
2453 | 0 | } |
2454 | | |
2455 | | static obj_attr_subsection_v2_t * |
2456 | | oav2_obj_attr_subsection_v2_copy (const obj_attr_subsection_v2_t *); |
2457 | | |
2458 | | /* Copy object attributes v2 from IBFD to OBFD. */ |
2459 | | static void |
2460 | | oav2_copy_attributes (bfd *ibfd, bfd *obfd) |
2461 | 0 | { |
2462 | 0 | const obj_attr_subsection_list_t *in_attr_subsecs |
2463 | 0 | = &elf_obj_attr_subsections (ibfd); |
2464 | 0 | obj_attr_subsection_list_t *out_attr_subsecs |
2465 | 0 | = &elf_obj_attr_subsections (obfd); |
2466 | |
|
2467 | 0 | for (const obj_attr_subsection_v2_t *isubsec = in_attr_subsecs->first; |
2468 | 0 | isubsec != NULL; |
2469 | 0 | isubsec = isubsec->next) |
2470 | 0 | { |
2471 | 0 | obj_attr_subsection_v2_t *osubsec |
2472 | 0 | = oav2_obj_attr_subsection_v2_copy (isubsec); |
2473 | 0 | LINKED_LIST_APPEND (obj_attr_subsection_v2_t) (out_attr_subsecs, osubsec); |
2474 | 0 | } |
2475 | 0 | } |
2476 | | |
2477 | | /* Copy the object attributes from IBFD to OBFD. */ |
2478 | | void |
2479 | | _bfd_elf_copy_obj_attributes (bfd *ibfd, bfd *obfd) |
2480 | 315 | { |
2481 | 315 | if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
2482 | 315 | || bfd_get_flavour (obfd) != bfd_target_elf_flavour) |
2483 | 0 | return; |
2484 | | |
2485 | 315 | obj_attr_version_t version = elf_obj_attr_version (ibfd); |
2486 | 315 | elf_obj_attr_version (obfd) = version; |
2487 | | |
2488 | 315 | switch (version) |
2489 | 315 | { |
2490 | 315 | case OBJ_ATTR_VERSION_NONE: |
2491 | 315 | break; |
2492 | 0 | case OBJ_ATTR_V1: |
2493 | 0 | oav1_copy_attributes (ibfd, obfd); |
2494 | 0 | break; |
2495 | 0 | case OBJ_ATTR_V2: |
2496 | 0 | oav2_copy_attributes (ibfd, obfd); |
2497 | 0 | break; |
2498 | 0 | default: |
2499 | 0 | abort (); |
2500 | 315 | } |
2501 | 315 | } |
2502 | | |
2503 | | /* Determine whether a GNU object attribute tag takes an integer, a |
2504 | | string or both. */ |
2505 | | static int |
2506 | | gnu_obj_attrs_arg_type (obj_attr_tag_t tag) |
2507 | 373k | { |
2508 | | /* Except for Tag_compatibility, for GNU attributes we follow the |
2509 | | same rule ARM ones > 32 follow: odd-numbered tags take strings |
2510 | | and even-numbered tags take integers. In addition, tag & 2 is |
2511 | | nonzero for architecture-independent tags and zero for |
2512 | | architecture-dependent ones. */ |
2513 | 373k | if (tag == Tag_compatibility) |
2514 | 7.29k | return 3; |
2515 | 365k | else |
2516 | 365k | return (tag & 1) != 0 ? 2 : 1; |
2517 | 373k | } |
2518 | | |
2519 | | /* Determine what arguments an attribute tag takes. */ |
2520 | | int |
2521 | | bfd_elf_obj_attrs_arg_type (bfd *abfd, |
2522 | | obj_attr_vendor_t vendor, |
2523 | | obj_attr_tag_t tag) |
2524 | 381k | { |
2525 | | /* This function should only be called for object attributes version 1. */ |
2526 | 381k | BFD_ASSERT (elf_obj_attr_version (abfd) == OBJ_ATTR_V1); |
2527 | 381k | switch (vendor) |
2528 | 381k | { |
2529 | 8.34k | case OBJ_ATTR_PROC: |
2530 | 8.34k | return get_elf_backend_data (abfd)->obj_attrs_arg_type (tag); |
2531 | 0 | break; |
2532 | 373k | case OBJ_ATTR_GNU: |
2533 | 373k | return gnu_obj_attrs_arg_type (tag); |
2534 | 0 | break; |
2535 | 0 | default: |
2536 | 0 | abort (); |
2537 | 381k | } |
2538 | 381k | } |
2539 | | |
2540 | | static void |
2541 | | oav1_parse_section (bfd *abfd, bfd_byte *p, bfd_byte *p_end) |
2542 | 2.18k | { |
2543 | 2.18k | const char *std_sec = get_elf_backend_data (abfd)->obj_attrs_vendor; |
2544 | | |
2545 | 6.13k | while (p_end - p >= 4) |
2546 | 4.40k | { |
2547 | 4.40k | size_t len = p_end - p; |
2548 | 4.40k | size_t namelen; |
2549 | 4.40k | size_t section_len; |
2550 | 4.40k | int vendor; |
2551 | | |
2552 | 4.40k | section_len = bfd_get_32 (abfd, p); |
2553 | 4.40k | p += 4; |
2554 | 4.40k | if (section_len == 0) |
2555 | 200 | break; |
2556 | 4.20k | if (section_len > len) |
2557 | 1.97k | section_len = len; |
2558 | 4.20k | if (section_len <= 4) |
2559 | 98 | { |
2560 | 98 | _bfd_error_handler |
2561 | 98 | (_("%pB: error: attribute section length too small: %ld"), |
2562 | 98 | abfd, (long) section_len); |
2563 | 98 | break; |
2564 | 98 | } |
2565 | 4.10k | section_len -= 4; |
2566 | 4.10k | namelen = strnlen ((char *) p, section_len) + 1; |
2567 | 4.10k | if (namelen >= section_len) |
2568 | 162 | break; |
2569 | 3.94k | if (std_sec && strcmp ((char *) p, std_sec) == 0) |
2570 | 119 | vendor = OBJ_ATTR_PROC; |
2571 | 3.82k | else if (strcmp ((char *) p, "gnu") == 0) |
2572 | 1.13k | vendor = OBJ_ATTR_GNU; |
2573 | 2.69k | else |
2574 | 2.69k | { |
2575 | | /* Other vendor section. Ignore it. */ |
2576 | 2.69k | p += section_len; |
2577 | 2.69k | continue; |
2578 | 2.69k | } |
2579 | | |
2580 | 1.24k | p += namelen; |
2581 | 1.24k | section_len -= namelen; |
2582 | 3.04k | while (section_len > 0) |
2583 | 2.03k | { |
2584 | 2.03k | unsigned int tag; |
2585 | 2.03k | unsigned int val; |
2586 | 2.03k | size_t subsection_len; |
2587 | 2.03k | bfd_byte *end, *orig_p; |
2588 | | |
2589 | 2.03k | orig_p = p; |
2590 | 2.03k | tag = _bfd_safe_read_leb128 (abfd, &p, false, p_end); |
2591 | 2.03k | if (p_end - p >= 4) |
2592 | 1.96k | { |
2593 | 1.96k | subsection_len = bfd_get_32 (abfd, p); |
2594 | 1.96k | p += 4; |
2595 | 1.96k | } |
2596 | 70 | else |
2597 | 70 | { |
2598 | 70 | p = p_end; |
2599 | 70 | break; |
2600 | 70 | } |
2601 | 1.96k | if (subsection_len > section_len) |
2602 | 1.01k | subsection_len = section_len; |
2603 | 1.96k | section_len -= subsection_len; |
2604 | 1.96k | end = orig_p + subsection_len; |
2605 | 1.96k | if (end < p) |
2606 | 163 | break; |
2607 | 1.79k | switch (tag) |
2608 | 1.79k | { |
2609 | 1.16k | case Tag_File: |
2610 | 191k | while (p < end) |
2611 | 190k | { |
2612 | 190k | int type; |
2613 | 190k | bool ok = false; |
2614 | | |
2615 | 190k | tag = _bfd_safe_read_leb128 (abfd, &p, false, end); |
2616 | 190k | type = bfd_elf_obj_attrs_arg_type (abfd, vendor, tag); |
2617 | 190k | switch (type & (ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL)) |
2618 | 190k | { |
2619 | 3.64k | case ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL: |
2620 | 3.64k | val = _bfd_safe_read_leb128 (abfd, &p, false, end); |
2621 | 3.64k | ok = elf_add_obj_attr_int_string (abfd, vendor, tag, |
2622 | 3.64k | val, (char *) p, |
2623 | 3.64k | (char *) end); |
2624 | 3.64k | p += strnlen ((char *) p, end - p); |
2625 | 3.64k | if (p < end) |
2626 | 3.51k | p++; |
2627 | 3.64k | break; |
2628 | 31.3k | case ATTR_TYPE_FLAG_STR_VAL: |
2629 | 31.3k | ok = elf_add_obj_attr_string (abfd, vendor, tag, |
2630 | 31.3k | (char *) p, |
2631 | 31.3k | (char *) end); |
2632 | 31.3k | p += strnlen ((char *) p, end - p); |
2633 | 31.3k | if (p < end) |
2634 | 31.0k | p++; |
2635 | 31.3k | break; |
2636 | 155k | case ATTR_TYPE_FLAG_INT_VAL: |
2637 | 155k | val = _bfd_safe_read_leb128 (abfd, &p, false, end); |
2638 | 155k | ok = bfd_elf_add_obj_attr_int (abfd, vendor, tag, val); |
2639 | 155k | break; |
2640 | 0 | default: |
2641 | 0 | abort (); |
2642 | 190k | } |
2643 | 190k | if (!ok) |
2644 | 0 | bfd_perror (_("error adding attribute")); |
2645 | 190k | } |
2646 | 1.16k | break; |
2647 | 1.16k | case Tag_Section: |
2648 | 8 | case Tag_Symbol: |
2649 | | /* Don't have anywhere convenient to attach these. |
2650 | | Fall through for now. */ |
2651 | 637 | default: |
2652 | | /* Ignore things we don't know about. */ |
2653 | 637 | p = end; |
2654 | 637 | break; |
2655 | 1.79k | } |
2656 | 1.79k | } |
2657 | 1.24k | } |
2658 | 2.18k | } |
2659 | | |
2660 | | #define READ_ULEB128(abfd, var, cursor, end, total_read) \ |
2661 | 61.6k | do \ |
2662 | 61.6k | { \ |
2663 | 61.6k | bfd_byte *begin = (cursor); \ |
2664 | 61.6k | (var) = _bfd_safe_read_leb128 (abfd, &(cursor), false, end); \ |
2665 | 61.6k | (total_read) += (cursor) - begin; \ |
2666 | 61.6k | } \ |
2667 | 61.6k | while (0) |
2668 | | |
2669 | | static int |
2670 | | read_ntbs (bfd *abfd, |
2671 | | const bfd_byte *cursor, |
2672 | | const bfd_byte *end, |
2673 | | char **s) |
2674 | 15.6k | { |
2675 | 15.6k | *s = NULL; |
2676 | 15.6k | const size_t MAX_STR_LEN = end - cursor; /* Including \0. */ |
2677 | 15.6k | const size_t s_len = strnlen ((const char *) cursor, MAX_STR_LEN); |
2678 | 15.6k | if (s_len == MAX_STR_LEN) |
2679 | 63 | { |
2680 | 63 | bfd_set_error (bfd_error_malformed_archive); |
2681 | 63 | _bfd_error_handler (_("%pB: error: NTBS value seems corrupted " |
2682 | 63 | "(missing '\\0')"), |
2683 | 63 | abfd); |
2684 | 63 | return -1; |
2685 | 63 | } |
2686 | 15.6k | *s = xmemdup (cursor, s_len + 1, s_len + 1); |
2687 | 15.6k | return s_len + 1; |
2688 | 15.6k | } |
2689 | | |
2690 | | /* Parse an object attribute (v2 only). */ |
2691 | | static ssize_t |
2692 | | oav2_parse_attr (bfd *abfd, |
2693 | | bfd_byte *cursor, |
2694 | | const bfd_byte *end, |
2695 | | obj_attr_encoding_v2_t attr_type, |
2696 | | obj_attr_v2_t **attr) |
2697 | 38.5k | { |
2698 | 38.5k | *attr = NULL; |
2699 | 38.5k | ssize_t total_read = 0; |
2700 | | |
2701 | 38.5k | obj_attr_tag_t attr_tag; |
2702 | 38.5k | READ_ULEB128 (abfd, attr_tag, cursor, end, total_read); |
2703 | | |
2704 | 38.5k | union obj_attr_value_v2 attr_val; |
2705 | 38.5k | switch (attr_type) |
2706 | 38.5k | { |
2707 | 15.3k | case OA_ENC_NTBS: |
2708 | 15.3k | { |
2709 | 15.3k | int read = read_ntbs (abfd, cursor, end, (char **) &attr_val.string); |
2710 | 15.3k | if (read <= 0) |
2711 | 63 | return -1; |
2712 | 15.2k | total_read += read; |
2713 | 15.2k | } |
2714 | 0 | break; |
2715 | 23.1k | case OA_ENC_ULEB128: |
2716 | 23.1k | READ_ULEB128 (abfd, attr_val.uint, cursor, end, total_read); |
2717 | 23.1k | break; |
2718 | 0 | default: |
2719 | 0 | abort (); |
2720 | 38.5k | } |
2721 | | |
2722 | 38.4k | *attr = bfd_elf_obj_attr_v2_init (attr_tag, attr_val); |
2723 | 38.4k | return total_read; |
2724 | 38.5k | } |
2725 | | |
2726 | | /* Parse a subsection (object attributes v2 only). */ |
2727 | | static ssize_t |
2728 | | oav2_parse_subsection (bfd *abfd, |
2729 | | bfd_byte *cursor, |
2730 | | const uint64_t max_read, |
2731 | | obj_attr_subsection_v2_t **subsec) |
2732 | 517 | { |
2733 | 517 | *subsec = NULL; |
2734 | 517 | ssize_t total_read = 0; |
2735 | | |
2736 | 517 | char *subsection_name = NULL; |
2737 | 517 | const uint32_t F_SUBSECTION_LEN = sizeof(uint32_t); |
2738 | 517 | const uint32_t F_SUBSECTION_COMPREHENSION = sizeof(uint8_t); |
2739 | 517 | const uint32_t F_SUBSECTION_ENCODING = sizeof(uint8_t); |
2740 | | /* The minimum subsection length is 7: 4 bytes for the length itself, and 1 |
2741 | | byte for an empty NUL-terminated string, 1 byte for the comprehension, |
2742 | | 1 byte for the encoding, and no vendor-data. */ |
2743 | 517 | const uint32_t F_MIN_SUBSECTION_DATA_LEN |
2744 | 517 | = F_SUBSECTION_LEN + 1 /* for '\0' */ |
2745 | 517 | + F_SUBSECTION_COMPREHENSION + F_SUBSECTION_ENCODING; |
2746 | | |
2747 | | /* Similar to the issues reported in PR 17531, we need to check all the sizes |
2748 | | and offsets as we parse the section. */ |
2749 | 517 | if (max_read < F_MIN_SUBSECTION_DATA_LEN) |
2750 | 14 | { |
2751 | 14 | _bfd_error_handler (_("%pB: error: attributes subsection ends " |
2752 | 14 | "prematurely"), |
2753 | 14 | abfd); |
2754 | 14 | goto error; |
2755 | 14 | } |
2756 | | |
2757 | 503 | const unsigned int subsection_len = bfd_get_32 (abfd, cursor); |
2758 | 503 | const bfd_byte *const end = cursor + subsection_len; |
2759 | 503 | total_read += F_SUBSECTION_LEN; |
2760 | 503 | cursor += F_SUBSECTION_LEN; |
2761 | 503 | if (subsection_len > max_read) |
2762 | 118 | { |
2763 | 118 | _bfd_error_handler |
2764 | 118 | (_("%pB: error: bad subsection length (%u > max=%" PRIu64 ")"), |
2765 | 118 | abfd, subsection_len, max_read); |
2766 | 118 | goto error; |
2767 | 118 | } |
2768 | 385 | else if (subsection_len < F_MIN_SUBSECTION_DATA_LEN) |
2769 | 37 | { |
2770 | 37 | _bfd_error_handler (_("%pB: error: subsection length of %u is too small"), |
2771 | 37 | abfd, subsection_len); |
2772 | 37 | goto error; |
2773 | 37 | } |
2774 | | |
2775 | 348 | const size_t max_subsection_name_len |
2776 | 348 | = subsection_len - F_SUBSECTION_LEN |
2777 | 348 | - F_SUBSECTION_COMPREHENSION - F_SUBSECTION_ENCODING; |
2778 | 348 | const bfd_byte *subsection_name_end |
2779 | 348 | = memchr (cursor, '\0', max_subsection_name_len); |
2780 | 348 | if (subsection_name_end == NULL) |
2781 | 14 | { |
2782 | 14 | _bfd_error_handler (_("%pB: error: subsection name seems corrupted " |
2783 | 14 | "(missing '\\0')"), |
2784 | 14 | abfd); |
2785 | 14 | goto error; |
2786 | 14 | } |
2787 | 334 | else |
2788 | | /* Move the end pointer after '\0'. */ |
2789 | 334 | ++subsection_name_end; |
2790 | | |
2791 | | /* Note: if the length of the subsection name is 0 (i.e. the string is '\0'), |
2792 | | it is still considered a valid name, even if it is not particularly |
2793 | | useful. */ |
2794 | | |
2795 | | /* Note: at this stage, |
2796 | | 1. the length of the subsection name is validated, as the presence of '\0' |
2797 | | at the end of the string, so no risk of buffer overrun. |
2798 | | 2. the data for comprehension and encoding can also safely be read. */ |
2799 | 334 | { |
2800 | | /* Note: read_ntbs() assigns a dynamically allocated string to |
2801 | | subsection_name. Either the string has to be freed in case of errors, |
2802 | | or its ownership must be transferred. */ |
2803 | 334 | int read = read_ntbs (abfd, cursor, subsection_name_end, &subsection_name); |
2804 | 334 | if (read <= 0) |
2805 | 0 | goto error; |
2806 | 334 | total_read += read; |
2807 | 334 | cursor += read; |
2808 | 334 | } |
2809 | | |
2810 | 334 | uint8_t comprehension_raw = bfd_get_8 (abfd, cursor); |
2811 | 334 | ++cursor; |
2812 | 334 | ++total_read; |
2813 | | |
2814 | | /* Comprehension is supposed to be a boolean, so any value greater than 1 is |
2815 | | considered invalid. */ |
2816 | 334 | if (comprehension_raw > 1) |
2817 | 28 | { |
2818 | 28 | _bfd_error_handler (_("%pB: error: '%s' seems corrupted, got %u but only " |
2819 | 28 | "0 ('%s') or 1 ('%s') are valid values"), |
2820 | 28 | abfd, "comprehension", comprehension_raw, |
2821 | 28 | "required", "optional"); |
2822 | 28 | goto error; |
2823 | 28 | } |
2824 | | |
2825 | 306 | uint8_t value_encoding_raw = bfd_get_8 (abfd, cursor); |
2826 | 306 | ++cursor; |
2827 | 306 | ++total_read; |
2828 | | |
2829 | | /* Encoding cannot be greater than OA_ENC_MAX, otherwise it means that either |
2830 | | there is a new encoding that was introduced in the spec, and this |
2831 | | implementation in binutils is older, and not aware of it so does not |
2832 | | support it; or the stored value for encoding is garbage. */ |
2833 | 306 | enum obj_attr_encoding_v2 value_encoding |
2834 | 306 | = obj_attr_encoding_v2_from_u8 (value_encoding_raw); |
2835 | 306 | if (value_encoding > OA_ENC_MAX) |
2836 | 19 | { |
2837 | 19 | _bfd_error_handler (_("%pB: error: attribute type seems corrupted, got" |
2838 | 19 | " %u but only 0 (ULEB128) or 1 (NTBS) are " |
2839 | 19 | "valid types"), |
2840 | 19 | abfd, value_encoding); |
2841 | 19 | goto error; |
2842 | 19 | } |
2843 | | |
2844 | 287 | obj_attr_subsection_scope_v2_t scope |
2845 | 287 | = bfd_elf_obj_attr_subsection_v2_scope (abfd, subsection_name); |
2846 | | |
2847 | | /* Note: ownership of 'subsection_name' is transfered to the callee when |
2848 | | initializing the subsection. That is why we skip free() at the end. */ |
2849 | 287 | *subsec = bfd_elf_obj_attr_subsection_v2_init |
2850 | 287 | (subsection_name, scope, comprehension_raw, value_encoding); |
2851 | | |
2852 | | /* A subsection can be empty, so 'cursor' can be equal to 'end' here. */ |
2853 | 38.7k | while (cursor < end) |
2854 | 38.5k | { |
2855 | 38.5k | obj_attr_v2_t *attr; |
2856 | 38.5k | ssize_t read = oav2_parse_attr (abfd, cursor, end, value_encoding, &attr); |
2857 | 38.5k | if (read <= 0) |
2858 | 63 | { |
2859 | 63 | _bfd_elf_obj_attr_subsection_v2_free (*subsec); |
2860 | 63 | *subsec = NULL; |
2861 | 63 | return -1; |
2862 | 63 | } |
2863 | 38.4k | if (attr != NULL) |
2864 | 38.4k | LINKED_LIST_APPEND (obj_attr_v2_t) (*subsec, attr); |
2865 | 38.4k | total_read += read; |
2866 | 38.4k | cursor += read; |
2867 | 38.4k | } |
2868 | | |
2869 | 224 | BFD_ASSERT (cursor == end); |
2870 | 224 | return total_read; |
2871 | | |
2872 | 230 | error: |
2873 | 230 | bfd_set_error (bfd_error_malformed_archive); |
2874 | 230 | if (subsection_name) |
2875 | 47 | free (subsection_name); |
2876 | 230 | return -1; |
2877 | 287 | } |
2878 | | |
2879 | | /* Parse the list of subsections (object attributes v2 only). */ |
2880 | | static void |
2881 | | oav2_parse_section (bfd *abfd, |
2882 | | const Elf_Internal_Shdr *hdr, |
2883 | | bfd_byte *cursor) |
2884 | 302 | { |
2885 | 302 | obj_attr_subsection_list_t *subsecs = &elf_obj_attr_subsections (abfd); |
2886 | 302 | ssize_t read = 0; |
2887 | 302 | for (uint64_t remaining = hdr->sh_size - 1; /* Already read 'A'. */ |
2888 | 526 | remaining > 0; |
2889 | 302 | remaining -= read, cursor += read) |
2890 | 517 | { |
2891 | 517 | obj_attr_subsection_v2_t *subsec = NULL; |
2892 | 517 | read = oav2_parse_subsection (abfd, cursor, remaining, &subsec); |
2893 | 517 | if (read < 0) |
2894 | 293 | { |
2895 | 293 | _bfd_error_handler |
2896 | 293 | (_("%pB: error: could not parse subsection at offset %" PRIx64), |
2897 | 293 | abfd, hdr->sh_size - remaining); |
2898 | 293 | bfd_set_error (bfd_error_wrong_format); |
2899 | 293 | break; |
2900 | 293 | } |
2901 | 224 | else |
2902 | 224 | LINKED_LIST_APPEND (obj_attr_subsection_v2_t) (subsecs, subsec); |
2903 | 517 | } |
2904 | 302 | } |
2905 | | |
2906 | | /* Parse an object attributes section. |
2907 | | Note: The parsing setup is common between object attributes v1 and v2. */ |
2908 | | void |
2909 | | _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr) |
2910 | 4.78k | { |
2911 | 4.78k | elf_obj_attr_version (abfd) = OBJ_ATTR_VERSION_NONE; |
2912 | | |
2913 | | /* PR 17512: file: 2844a11d. */ |
2914 | 4.78k | if (hdr->sh_size == 0) |
2915 | 132 | return; |
2916 | | |
2917 | 4.65k | ufile_ptr filesize = bfd_get_file_size (abfd); |
2918 | 4.65k | if (filesize != 0 && hdr->sh_size > filesize) |
2919 | 1.24k | { |
2920 | 1.24k | _bfd_error_handler |
2921 | 1.24k | (_("%pB: error: attribute section '%pA' too big: %" PRIu64), |
2922 | 1.24k | abfd, hdr->bfd_section, (uint64_t) hdr->sh_size); |
2923 | 1.24k | bfd_set_error (bfd_error_invalid_operation); |
2924 | 1.24k | return; |
2925 | 1.24k | } |
2926 | | |
2927 | 3.41k | bfd_byte *data = (bfd_byte *) bfd_malloc (hdr->sh_size); |
2928 | 3.41k | if (!data) |
2929 | 0 | return; |
2930 | | |
2931 | 3.41k | if (!bfd_get_section_contents (abfd, hdr->bfd_section, data, 0, hdr->sh_size)) |
2932 | 694 | goto free_data; |
2933 | | |
2934 | 2.71k | unsigned char *cursor = data; |
2935 | | |
2936 | | /* The first character is the version of the attributes. */ |
2937 | 2.71k | obj_attr_version_t version |
2938 | 2.71k | = get_elf_backend_data (abfd)->obj_attrs_version_dec (*cursor); |
2939 | 2.71k | if (version == OBJ_ATTR_VERSION_UNSUPPORTED || version > OBJ_ATTR_VERSION_MAX) |
2940 | 230 | { |
2941 | 230 | _bfd_error_handler (_("%pB: error: unknown attributes version '%c'(%d)\n"), |
2942 | 230 | abfd, *cursor, *cursor); |
2943 | 230 | bfd_set_error (bfd_error_wrong_format); |
2944 | 230 | goto free_data; |
2945 | 230 | } |
2946 | | |
2947 | 2.48k | ++cursor; |
2948 | | |
2949 | 2.48k | elf_obj_attr_version (abfd) = version; |
2950 | 2.48k | switch (version) |
2951 | 2.48k | { |
2952 | 2.18k | case OBJ_ATTR_V1: |
2953 | 2.18k | oav1_parse_section (abfd, cursor, data + hdr->sh_size); |
2954 | 2.18k | break; |
2955 | 302 | case OBJ_ATTR_V2: |
2956 | 302 | oav2_parse_section (abfd, hdr, cursor); |
2957 | 302 | break; |
2958 | 0 | default: |
2959 | 0 | abort (); |
2960 | 2.48k | } |
2961 | | |
2962 | 3.41k | free_data: |
2963 | 3.41k | free (data); |
2964 | 3.41k | } |
2965 | | |
2966 | | /* Clean-up all the object attributes in a file. */ |
2967 | | void |
2968 | | _bfd_elf_cleanup_object_attributes (bfd *abfd) |
2969 | 51.1k | { |
2970 | 51.1k | obj_attr_subsection_list_t *plist = &elf_obj_attr_subsections (abfd); |
2971 | 51.1k | obj_attr_subsection_v2_t *subsec = plist->first; |
2972 | 51.4k | while (subsec != NULL) |
2973 | 224 | subsec = oav2_subsec_delete (plist, subsec); |
2974 | 51.1k | } |
2975 | | |
2976 | | /* Merge common object attributes from IBFD into OBFD. Raise an error |
2977 | | if there are conflicting attributes. Any processor-specific |
2978 | | attributes have already been merged. This must be called from the |
2979 | | bfd_elfNN_bfd_merge_private_bfd_data hook for each individual |
2980 | | target, along with any target-specific merging. Because there are |
2981 | | no common attributes other than Tag_compatibility at present, and |
2982 | | non-"gnu" Tag_compatibility is not expected in "gnu" sections, this |
2983 | | is not presently called for targets without their own |
2984 | | attributes. */ |
2985 | | |
2986 | | bool |
2987 | | _bfd_elf_merge_object_attributes (bfd *ibfd, struct bfd_link_info *info) |
2988 | 0 | { |
2989 | 0 | bfd *obfd = info->output_bfd; |
2990 | 0 | obj_attribute *in_attr; |
2991 | 0 | obj_attribute *out_attr; |
2992 | 0 | int vendor; |
2993 | | |
2994 | | /* Set the object attribute version for the output object to the recommended |
2995 | | value by the backend. */ |
2996 | 0 | elf_obj_attr_version (obfd) |
2997 | 0 | = get_elf_backend_data (obfd)->default_obj_attr_version; |
2998 | | |
2999 | | /* The only common attribute is currently Tag_compatibility, |
3000 | | accepted in both processor and "gnu" sections. */ |
3001 | 0 | for (vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; vendor++) |
3002 | 0 | { |
3003 | | /* Handle Tag_compatibility. The tags are only compatible if the flags |
3004 | | are identical and, if the flags are '1', the strings are identical. |
3005 | | If the flags are non-zero, then we can only use the string "gnu". */ |
3006 | 0 | in_attr = &elf_known_obj_attributes (ibfd)[vendor][Tag_compatibility]; |
3007 | 0 | out_attr = &elf_known_obj_attributes (obfd)[vendor][Tag_compatibility]; |
3008 | |
|
3009 | 0 | if (in_attr->i > 0 && strcmp (in_attr->s, "gnu") != 0) |
3010 | 0 | { |
3011 | 0 | _bfd_error_handler |
3012 | | /* xgettext:c-format */ |
3013 | 0 | (_("error: %pB: object has vendor-specific contents that " |
3014 | 0 | "must be processed by the '%s' toolchain"), |
3015 | 0 | ibfd, in_attr->s); |
3016 | 0 | return false; |
3017 | 0 | } |
3018 | | |
3019 | 0 | if (in_attr->i != out_attr->i |
3020 | 0 | || (in_attr->i != 0 && strcmp (in_attr->s, out_attr->s) != 0)) |
3021 | 0 | { |
3022 | | /* xgettext:c-format */ |
3023 | 0 | _bfd_error_handler (_("error: %pB: object tag '%d, %s' is " |
3024 | 0 | "incompatible with tag '%d, %s'"), |
3025 | 0 | ibfd, |
3026 | 0 | in_attr->i, in_attr->s ? in_attr->s : "", |
3027 | 0 | out_attr->i, out_attr->s ? out_attr->s : ""); |
3028 | 0 | return false; |
3029 | 0 | } |
3030 | 0 | } |
3031 | | |
3032 | 0 | return true; |
3033 | 0 | } |
3034 | | |
3035 | | /* Merge an unknown processor-specific attribute TAG, within the range |
3036 | | of known attributes, from IBFD into OBFD; return TRUE if the link |
3037 | | is OK, FALSE if it must fail. */ |
3038 | | |
3039 | | bool |
3040 | | _bfd_elf_merge_unknown_attribute_low (bfd *ibfd, bfd *obfd, int tag) |
3041 | 0 | { |
3042 | 0 | obj_attribute *in_attr; |
3043 | 0 | obj_attribute *out_attr; |
3044 | 0 | bfd *err_bfd = NULL; |
3045 | 0 | bool result = true; |
3046 | |
|
3047 | 0 | in_attr = elf_known_obj_attributes_proc (ibfd); |
3048 | 0 | out_attr = elf_known_obj_attributes_proc (obfd); |
3049 | |
|
3050 | 0 | if (out_attr[tag].i != 0 || out_attr[tag].s != NULL) |
3051 | 0 | err_bfd = obfd; |
3052 | 0 | else if (in_attr[tag].i != 0 || in_attr[tag].s != NULL) |
3053 | 0 | err_bfd = ibfd; |
3054 | |
|
3055 | 0 | if (err_bfd != NULL) |
3056 | 0 | result |
3057 | 0 | = get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, tag); |
3058 | | |
3059 | | /* Only pass on attributes that match in both inputs. */ |
3060 | 0 | if (in_attr[tag].i != out_attr[tag].i |
3061 | 0 | || (in_attr[tag].s == NULL) != (out_attr[tag].s == NULL) |
3062 | 0 | || (in_attr[tag].s != NULL && out_attr[tag].s != NULL |
3063 | 0 | && strcmp (in_attr[tag].s, out_attr[tag].s) != 0)) |
3064 | 0 | { |
3065 | 0 | out_attr[tag].i = 0; |
3066 | 0 | out_attr[tag].s = NULL; |
3067 | 0 | } |
3068 | |
|
3069 | 0 | return result; |
3070 | 0 | } |
3071 | | |
3072 | | /* Merge the lists of unknown processor-specific attributes, outside |
3073 | | the known range, from IBFD into OBFD; return TRUE if the link is |
3074 | | OK, FALSE if it must fail. */ |
3075 | | |
3076 | | bool |
3077 | | _bfd_elf_merge_unknown_attribute_list (bfd *ibfd, bfd *obfd) |
3078 | 0 | { |
3079 | 0 | obj_attribute_list *in_list; |
3080 | 0 | obj_attribute_list *out_list; |
3081 | 0 | obj_attribute_list **out_listp; |
3082 | 0 | bool result = true; |
3083 | |
|
3084 | 0 | in_list = elf_other_obj_attributes_proc (ibfd); |
3085 | 0 | out_listp = &elf_other_obj_attributes_proc (obfd); |
3086 | 0 | out_list = *out_listp; |
3087 | |
|
3088 | 0 | for (; in_list || out_list; ) |
3089 | 0 | { |
3090 | 0 | bfd *err_bfd = NULL; |
3091 | 0 | unsigned int err_tag = 0; |
3092 | | |
3093 | | /* The tags for each list are in numerical order. */ |
3094 | | /* If the tags are equal, then merge. */ |
3095 | 0 | if (out_list && (!in_list || in_list->tag > out_list->tag)) |
3096 | 0 | { |
3097 | | /* This attribute only exists in obfd. We can't merge, and we don't |
3098 | | know what the tag means, so delete it. */ |
3099 | 0 | err_bfd = obfd; |
3100 | 0 | err_tag = out_list->tag; |
3101 | 0 | *out_listp = out_list->next; |
3102 | 0 | out_list = *out_listp; |
3103 | 0 | } |
3104 | 0 | else if (in_list && (!out_list || in_list->tag < out_list->tag)) |
3105 | 0 | { |
3106 | | /* This attribute only exists in ibfd. We can't merge, and we don't |
3107 | | know what the tag means, so ignore it. */ |
3108 | 0 | err_bfd = ibfd; |
3109 | 0 | err_tag = in_list->tag; |
3110 | 0 | in_list = in_list->next; |
3111 | 0 | } |
3112 | 0 | else /* The tags are equal. */ |
3113 | 0 | { |
3114 | | /* As present, all attributes in the list are unknown, and |
3115 | | therefore can't be merged meaningfully. */ |
3116 | 0 | err_bfd = obfd; |
3117 | 0 | err_tag = out_list->tag; |
3118 | | |
3119 | | /* Only pass on attributes that match in both inputs. */ |
3120 | 0 | if (in_list->attr.i != out_list->attr.i |
3121 | 0 | || (in_list->attr.s == NULL) != (out_list->attr.s == NULL) |
3122 | 0 | || (in_list->attr.s && out_list->attr.s |
3123 | 0 | && strcmp (in_list->attr.s, out_list->attr.s) != 0)) |
3124 | 0 | { |
3125 | | /* No match. Delete the attribute. */ |
3126 | 0 | *out_listp = out_list->next; |
3127 | 0 | out_list = *out_listp; |
3128 | 0 | } |
3129 | 0 | else |
3130 | 0 | { |
3131 | | /* Matched. Keep the attribute and move to the next. */ |
3132 | 0 | out_list = out_list->next; |
3133 | 0 | in_list = in_list->next; |
3134 | 0 | } |
3135 | 0 | } |
3136 | |
|
3137 | 0 | if (err_bfd) |
3138 | 0 | result = result |
3139 | 0 | && get_elf_backend_data (err_bfd)->obj_attrs_handle_unknown (err_bfd, |
3140 | 0 | err_tag); |
3141 | 0 | } |
3142 | |
|
3143 | 0 | return result; |
3144 | 0 | } |
3145 | | |
3146 | | /* Create a new object attribute with key TAG and value VAL. |
3147 | | Return a pointer to it. */ |
3148 | | |
3149 | | obj_attr_v2_t * |
3150 | | bfd_elf_obj_attr_v2_init (obj_attr_tag_t tag, |
3151 | | union obj_attr_value_v2 val) |
3152 | 38.4k | { |
3153 | 38.4k | obj_attr_v2_t *attr = XCNEW (obj_attr_v2_t); |
3154 | 38.4k | attr->tag = tag; |
3155 | 38.4k | attr->val = val; |
3156 | 38.4k | attr->status = obj_attr_v2_ok; |
3157 | 38.4k | return attr; |
3158 | 38.4k | } |
3159 | | |
3160 | | /* Free memory allocated by the object attribute ATTR. */ |
3161 | | |
3162 | | void |
3163 | | _bfd_elf_obj_attr_v2_free (obj_attr_v2_t *attr, obj_attr_encoding_v2_t encoding) |
3164 | 38.4k | { |
3165 | 38.4k | if (encoding == OA_ENC_NTBS) |
3166 | | /* Note: this field never holds a string literal. */ |
3167 | 15.2k | free ((char *) attr->val.string); |
3168 | 38.4k | free (attr); |
3169 | 38.4k | } |
3170 | | |
3171 | | /* Copy an object attribute OTHER, and return a pointer to the copy. */ |
3172 | | |
3173 | | obj_attr_v2_t * |
3174 | | _bfd_elf_obj_attr_v2_copy (const obj_attr_v2_t *other, |
3175 | | obj_attr_encoding_v2_t encoding) |
3176 | 0 | { |
3177 | 0 | union obj_attr_value_v2 val; |
3178 | 0 | if (encoding == OA_ENC_NTBS) |
3179 | 0 | val.string |
3180 | 0 | = (other->val.string != NULL |
3181 | 0 | ? xstrdup (other->val.string) |
3182 | 0 | : NULL); |
3183 | 0 | else if (encoding == OA_ENC_ULEB128) |
3184 | 0 | val.uint = other->val.uint; |
3185 | 0 | else |
3186 | 0 | abort (); |
3187 | | |
3188 | 0 | obj_attr_v2_t *copy = bfd_elf_obj_attr_v2_init (other->tag, val); |
3189 | 0 | copy->status = other->status; |
3190 | 0 | return copy; |
3191 | 0 | } |
3192 | | |
3193 | | /* Compare two object attributes based on their TAG value only (partial |
3194 | | ordering), and return an integer indicating the result of the comparison, |
3195 | | as follows: |
3196 | | - 0, if A1 and A2 are equal. |
3197 | | - a negative value if A1 is less than A2. |
3198 | | - a positive value if A1 is greater than A2. */ |
3199 | | |
3200 | | int |
3201 | | _bfd_elf_obj_attr_v2_cmp (const obj_attr_v2_t *a1, const obj_attr_v2_t *a2) |
3202 | 0 | { |
3203 | 0 | if (a1->tag < a2->tag) |
3204 | 0 | return -1; |
3205 | 0 | if (a1->tag > a2->tag) |
3206 | 0 | return 1; |
3207 | 0 | return 0; |
3208 | 0 | } |
3209 | | |
3210 | | /* Return an object attribute in SUBSEC matching TAG or NULL if one is not |
3211 | | found. SORTED specifies whether the given list is ordered by tag number. |
3212 | | This allows an early return if we find a higher numbered tag. */ |
3213 | | |
3214 | | obj_attr_v2_t * |
3215 | | bfd_obj_attr_v2_find_by_tag (const obj_attr_subsection_v2_t *subsec, |
3216 | | obj_attr_tag_t tag, |
3217 | | bool sorted) |
3218 | 0 | { |
3219 | 0 | for (obj_attr_v2_t *attr = subsec->first; |
3220 | 0 | attr != NULL; |
3221 | 0 | attr = attr->next) |
3222 | 0 | { |
3223 | 0 | if (attr->tag == tag) |
3224 | 0 | return attr; |
3225 | 0 | if (sorted && attr->tag > tag) |
3226 | 0 | break; |
3227 | 0 | } |
3228 | 0 | return NULL; |
3229 | 0 | } |
3230 | | |
3231 | | /* Sort the object attributes inside a subsection. |
3232 | | Note: since a subsection is a list of attributes, the sorting algorithm is |
3233 | | implemented with a merge sort. |
3234 | | See more details in libiberty/doubly-linked-list.h */ |
3235 | | |
3236 | 38.4k | LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_v2_t, Line | Count | Source | 3236 | | LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_v2_t, |
Unexecuted instantiation: obj_attr_v2_t_prepend Unexecuted instantiation: obj_attr_v2_t_insert_before Unexecuted instantiation: obj_attr_v2_t_pop_front Unexecuted instantiation: obj_attr_v2_t_pop_back Unexecuted instantiation: obj_attr_v2_t_remove Unexecuted instantiation: obj_attr_v2_t_swap |
3237 | 38.4k | obj_attr_v2_t, /* extern */) |
3238 | 38.4k | LINKED_LIST_MERGE_SORT_DECL (obj_attr_subsection_v2_t, Unexecuted instantiation: obj_attr_v2_t_merge_sort_ Unexecuted instantiation: obj_attr_v2_t_merge_sort Unexecuted instantiation: elf-attrs.c:obj_attr_v2_t_merge_sort_compute_turtle_ Unexecuted instantiation: elf-attrs.c:obj_attr_v2_t_merge_sort_merge_ Unexecuted instantiation: elf-attrs.c:obj_attr_v2_t_merge_sort_out_append_ |
3239 | 0 | obj_attr_v2_t, /* extern */) |
3240 | 0 |
|
3241 | 0 | /* Public API wrapper for LINKED_LIST_APPEND (obj_attr_v2_t). */ |
3242 | 0 |
|
3243 | 0 | void bfd_obj_attr_subsection_v2_append (obj_attr_subsection_v2_t *subsec, |
3244 | 0 | obj_attr_v2_t *attr) |
3245 | 0 | { |
3246 | 0 | LINKED_LIST_APPEND (obj_attr_v2_t) (subsec, attr); |
3247 | 0 | } |
3248 | | |
3249 | | /* Create a new object attribute subsection with the following properties: |
3250 | | - NAME: the name of the subsection. Note: this parameter never holds a |
3251 | | string literal, so the value has to be freeable. |
3252 | | - SCOPE: the scope of the subsection (public or private). |
3253 | | - OPTIONAL: whether this subsection is optional (true) or required (false). |
3254 | | - ENCODING: the expected encoding for the attributes values (ULEB128 or NTBS). |
3255 | | Return a pointer to it. */ |
3256 | | |
3257 | | obj_attr_subsection_v2_t * |
3258 | | bfd_elf_obj_attr_subsection_v2_init (const char *name, |
3259 | | obj_attr_subsection_scope_v2_t scope, |
3260 | | bool optional, |
3261 | | obj_attr_encoding_v2_t encoding) |
3262 | 287 | { |
3263 | 287 | obj_attr_subsection_v2_t *subsection = XCNEW (obj_attr_subsection_v2_t); |
3264 | 287 | subsection->name = name; |
3265 | 287 | subsection->scope = scope; |
3266 | 287 | subsection->optional = optional; |
3267 | 287 | subsection->encoding = encoding; |
3268 | 287 | subsection->status = obj_attr_subsection_v2_ok; |
3269 | 287 | return subsection; |
3270 | 287 | } |
3271 | | |
3272 | | /* Free memory allocated by the object attribute subsection SUBSEC. */ |
3273 | | |
3274 | | void |
3275 | | _bfd_elf_obj_attr_subsection_v2_free (obj_attr_subsection_v2_t *subsec) |
3276 | 287 | { |
3277 | 287 | obj_attr_v2_t *attr = subsec->first; |
3278 | 38.7k | while (attr != NULL) |
3279 | 38.4k | { |
3280 | 38.4k | obj_attr_v2_t *a = attr; |
3281 | 38.4k | attr = attr->next; |
3282 | 38.4k | _bfd_elf_obj_attr_v2_free (a, subsec->encoding); |
3283 | 38.4k | } |
3284 | | /* Note: this field never holds a string literal. */ |
3285 | 287 | free ((char *) subsec->name); |
3286 | 287 | free (subsec); |
3287 | 287 | } |
3288 | | |
3289 | | /* Deep copy an object attribute subsection OTHER, and return a pointer to the |
3290 | | copy. */ |
3291 | | |
3292 | | static obj_attr_subsection_v2_t * |
3293 | | oav2_obj_attr_subsection_v2_copy (const obj_attr_subsection_v2_t *other) |
3294 | 0 | { |
3295 | 0 | obj_attr_subsection_v2_t *new_subsec |
3296 | 0 | = bfd_elf_obj_attr_subsection_v2_init (xstrdup (other->name), other->scope, |
3297 | 0 | other->optional, other->encoding); |
3298 | 0 | new_subsec->status = other->status; |
3299 | |
|
3300 | 0 | for (obj_attr_v2_t *attr = other->first; |
3301 | 0 | attr != NULL; |
3302 | 0 | attr = attr->next) |
3303 | 0 | { |
3304 | 0 | obj_attr_v2_t *new_attr = _bfd_elf_obj_attr_v2_copy (attr, other->encoding); |
3305 | 0 | LINKED_LIST_APPEND (obj_attr_v2_t) (new_subsec, new_attr); |
3306 | 0 | } |
3307 | 0 | return new_subsec; |
3308 | 0 | } |
3309 | | |
3310 | | /* Compare two object attribute subsections based on all their properties. |
3311 | | This operator can be used to obtain a total order in a collection. |
3312 | | Return an integer indicating the result of the comparison, as follows: |
3313 | | - 0, if S1 and S2 are equal. |
3314 | | - a negative value if S1 is less than S2. |
3315 | | - a positive value if S1 is greater than S2. |
3316 | | |
3317 | | NB: the scope is computed from the name, so is not used for the |
3318 | | comparison. */ |
3319 | | |
3320 | | int |
3321 | | _bfd_elf_obj_attr_subsection_v2_cmp (const obj_attr_subsection_v2_t *s1, |
3322 | | const obj_attr_subsection_v2_t *s2) |
3323 | 0 | { |
3324 | 0 | int res = strcmp (s1->name, s2->name); |
3325 | 0 | if (res != 0) |
3326 | 0 | return res; |
3327 | | |
3328 | | /* Note: The comparison of the encoding and optionality of subsections |
3329 | | is entirely arbitrary. The numeric values could be completely flipped |
3330 | | around without any effect. Likewise, assigning higher priority to |
3331 | | optionality than to encoding is artificial. The desired properties for |
3332 | | this comparison operator are reflexivity, transitivity, antisymmetry, |
3333 | | and totality, in order to achieve a total ordering when sorting a |
3334 | | collection of subsections. |
3335 | | If the nature of this ordering were to change in the future, it would |
3336 | | have no functional impact (but e.g. testsuite expectations might still |
3337 | | need adjusting) on the final merged result in the output file. Only the |
3338 | | order of the serialized subsections would differ, which does not affect |
3339 | | the interpretation of the object attributes. |
3340 | | Similarly, the ordering of subsections and attributes in an input file |
3341 | | does not affect the merge process in ld. The merge process never assumes |
3342 | | any particular ordering from the input files, it always sorts the |
3343 | | subsections and attributes before merging. This means that using an |
3344 | | older version of gas with a newer ld is safe, and vice versa as long as |
3345 | | no new features are used that the older ld doesn't know of. |
3346 | | In conclusion, the (arbitrary) criteria used to sort subsections during |
3347 | | the merge process are entirely internal to ld and have no effect on the |
3348 | | merge result. */ |
3349 | | |
3350 | 0 | if (!s1->optional && s2->optional) |
3351 | 0 | return -1; |
3352 | 0 | else if (s1->optional && !s2->optional) |
3353 | 0 | return 1; |
3354 | | |
3355 | 0 | if (s1->encoding < s2->encoding) |
3356 | 0 | return -1; |
3357 | 0 | else if (s1->encoding > s2->encoding) |
3358 | 0 | return 1; |
3359 | | |
3360 | 0 | return 0; |
3361 | 0 | } |
3362 | | |
3363 | | /* Return a subsection in the list FIRST matching NAME, or NULL if one is not |
3364 | | found. SORTED specifies whether the given list is ordered by name. |
3365 | | This allows an early return if we find a alphabetically-higher name. */ |
3366 | | |
3367 | | obj_attr_subsection_v2_t * |
3368 | | bfd_obj_attr_subsection_v2_find_by_name (obj_attr_subsection_v2_t *first, |
3369 | | const char *name, |
3370 | | bool sorted) |
3371 | 0 | { |
3372 | 0 | for (obj_attr_subsection_v2_t *s = first; |
3373 | 0 | s != NULL; |
3374 | 0 | s = s->next) |
3375 | 0 | { |
3376 | 0 | int cmp = strcmp (s->name, name); |
3377 | 0 | if (cmp == 0) |
3378 | 0 | return s; |
3379 | 0 | else if (sorted && cmp > 0) |
3380 | 0 | break; |
3381 | 0 | } |
3382 | 0 | return NULL; |
3383 | 0 | } |
3384 | | |
3385 | | /* Sort the subsections in a vendor section. |
3386 | | Note: since a section is a list of subsections, the sorting algorithm is |
3387 | | implemented with a merge sort. |
3388 | | See more details in libiberty/doubly-linked-list.h */ |
3389 | | |
3390 | 1.42k | LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_list_t, obj_attr_subsection_v2_t_append Line | Count | Source | 3390 | | LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_list_t, |
Unexecuted instantiation: obj_attr_subsection_v2_t_prepend Unexecuted instantiation: obj_attr_subsection_v2_t_insert_before obj_attr_subsection_v2_t_pop_front Line | Count | Source | 3390 | | LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_list_t, |
Unexecuted instantiation: obj_attr_subsection_v2_t_pop_back obj_attr_subsection_v2_t_remove Line | Count | Source | 3390 | | LINKED_LIST_MUTATIVE_OPS_DECL (obj_attr_subsection_list_t, |
Unexecuted instantiation: obj_attr_subsection_v2_t_swap |
3391 | 1.42k | obj_attr_subsection_v2_t, /* extern */) |
3392 | 1.42k | LINKED_LIST_MERGE_SORT_DECL (obj_attr_subsection_list_t, Unexecuted instantiation: obj_attr_subsection_v2_t_merge_sort_ Unexecuted instantiation: obj_attr_subsection_v2_t_merge_sort Unexecuted instantiation: elf-attrs.c:obj_attr_subsection_v2_t_merge_sort_compute_turtle_ Unexecuted instantiation: elf-attrs.c:obj_attr_subsection_v2_t_merge_sort_merge_ Unexecuted instantiation: elf-attrs.c:obj_attr_subsection_v2_t_merge_sort_out_append_ |
3393 | 0 | obj_attr_subsection_v2_t, /* extern */) |
3394 | 0 |
|
3395 | 0 | /* Public API wrapper for LINKED_LIST_APPEND (obj_attr_subsection_v2_t). */ |
3396 | 0 |
|
3397 | 0 | void |
3398 | 0 | bfd_obj_attr_subsection_v2_list_append (obj_attr_subsection_list_t *l, |
3399 | 0 | obj_attr_subsection_v2_t *subsec) |
3400 | 0 | { |
3401 | 0 | LINKED_LIST_APPEND (obj_attr_subsection_v2_t) (l, subsec); |
3402 | 0 | } |
3403 | | |
3404 | | /* Public API wrapper for LINKED_LIST_REMOVE (obj_attr_subsection_v2_t). */ |
3405 | | |
3406 | | obj_attr_subsection_v2_t * |
3407 | | bfd_obj_attr_subsection_v2_list_remove (obj_attr_subsection_list_t *l, |
3408 | | obj_attr_subsection_v2_t *subsec) |
3409 | 0 | { |
3410 | 0 | return LINKED_LIST_REMOVE (obj_attr_subsection_v2_t) (l, subsec); |
3411 | 0 | } |
3412 | | |
3413 | | /* Serialize the object attributes in ABFD into the vendor section of |
3414 | | OUTPUT_BFD. */ |
3415 | | |
3416 | | bool _bfd_elf_write_section_object_attributes |
3417 | | (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) |
3418 | 0 | { |
3419 | 0 | asection *sec = elf_obj_object_attributes (abfd); |
3420 | |
|
3421 | 0 | if (sec == NULL) |
3422 | 0 | return true; |
3423 | | |
3424 | 0 | bfd_byte *contents = (bfd_byte *) bfd_malloc (sec->size); |
3425 | 0 | if (contents == NULL) |
3426 | 0 | return false; /* Bail out and fail. */ |
3427 | | |
3428 | 0 | bfd_elf_set_obj_attr_contents (abfd, contents, sec->size); |
3429 | 0 | bfd_set_section_contents (abfd, sec, contents, 0, sec->size); |
3430 | 0 | free (contents); |
3431 | | return true; |
3432 | 0 | } |