1 /* ELF program property support. 2 Copyright (C) 2017 Free Software Foundation, Inc. 3 4 This file is part of BFD, the Binary File Descriptor library. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 /* GNU program property draft is at: 22 23 https://github.com/hjl-tools/linux-abi/wiki/property-draft.pdf 24 */ 25 26 #include "sysdep.h" 27 #include "bfd.h" 28 #include "libbfd.h" 29 #include "elf-bfd.h" 30 31 /* Get a property, allocate a new one if needed. */ 32 33 elf_property * 34 _bfd_elf_get_property (bfd *abfd, unsigned int type, unsigned int datasz) 35 { 36 elf_property_list *p, **lastp; 37 38 if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) 39 { 40 /* Never should happen. */ 41 abort (); 42 } 43 44 /* Keep the property list in order of type. */ 45 lastp = &elf_properties (abfd); 46 for (p = *lastp; p; p = p->next) 47 { 48 /* Reuse the existing entry. */ 49 if (type == p->property.pr_type) 50 { 51 if (datasz > p->property.pr_datasz) 52 { 53 /* This can happen when mixing 32-bit and 64-bit objects. */ 54 p->property.pr_datasz = datasz; 55 } 56 return &p->property; 57 } 58 else if (type < p->property.pr_type) 59 break; 60 lastp = &p->next; 61 } 62 p = (elf_property_list *) bfd_alloc (abfd, sizeof (*p)); 63 if (p == NULL) 64 { 65 _bfd_error_handler (_("%B: out of memory in _bfd_elf_get_property"), 66 abfd); 67 _exit (EXIT_FAILURE); 68 } 69 memset (p, 0, sizeof (*p)); 70 p->property.pr_type = type; 71 p->property.pr_datasz = datasz; 72 p->next = *lastp; 73 *lastp = p; 74 return &p->property; 75 } 76 77 /* Parse GNU properties. */ 78 79 bfd_boolean 80 _bfd_elf_parse_gnu_properties (bfd *abfd, Elf_Internal_Note *note) 81 { 82 const struct elf_backend_data *bed = get_elf_backend_data (abfd); 83 unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; 84 bfd_byte *ptr = (bfd_byte *) note->descdata; 85 bfd_byte *ptr_end = ptr + note->descsz; 86 87 if (note->descsz < 8 || (note->descsz % align_size) != 0) 88 { 89 bad_size: 90 _bfd_error_handler 91 (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) size: %#lx"), 92 abfd, note->type, note->descsz); 93 return FALSE; 94 } 95 96 while (1) 97 { 98 unsigned int type = bfd_h_get_32 (abfd, ptr); 99 unsigned int datasz = bfd_h_get_32 (abfd, ptr + 4); 100 elf_property *prop; 101 102 ptr += 8; 103 104 if ((ptr + datasz) > ptr_end) 105 { 106 _bfd_error_handler 107 (_("warning: %B: corrupt GNU_PROPERTY_TYPE (%ld) type (0x%x) datasz: 0x%x"), 108 abfd, note->type, type, datasz); 109 /* Clear all properties. */ 110 elf_properties (abfd) = NULL; 111 return FALSE; 112 } 113 114 if (type >= GNU_PROPERTY_LOPROC) 115 { 116 if (bed->elf_machine_code == EM_NONE) 117 { 118 /* Ignore processor-specific properties with generic ELF 119 target vector. They should be handled by the matching 120 ELF target vector. */ 121 goto next; 122 } 123 else if (type < GNU_PROPERTY_LOUSER 124 && bed->parse_gnu_properties) 125 { 126 enum elf_property_kind kind 127 = bed->parse_gnu_properties (abfd, type, ptr, datasz); 128 if (kind == property_corrupt) 129 { 130 /* Clear all properties. */ 131 elf_properties (abfd) = NULL; 132 return FALSE; 133 } 134 else if (kind != property_ignored) 135 goto next; 136 } 137 } 138 else 139 { 140 switch (type) 141 { 142 case GNU_PROPERTY_STACK_SIZE: 143 if (datasz != align_size) 144 { 145 _bfd_error_handler 146 (_("warning: %B: corrupt stack size: 0x%x"), 147 abfd, datasz); 148 /* Clear all properties. */ 149 elf_properties (abfd) = NULL; 150 return FALSE; 151 } 152 prop = _bfd_elf_get_property (abfd, type, datasz); 153 if (datasz == 8) 154 prop->u.number = bfd_h_get_64 (abfd, ptr); 155 else 156 prop->u.number = bfd_h_get_32 (abfd, ptr); 157 prop->pr_kind = property_number; 158 goto next; 159 160 case GNU_PROPERTY_NO_COPY_ON_PROTECTED: 161 if (datasz != 0) 162 { 163 _bfd_error_handler 164 (_("warning: %B: corrupt no copy on protected size: 0x%x"), 165 abfd, datasz); 166 /* Clear all properties. */ 167 elf_properties (abfd) = NULL; 168 return FALSE; 169 } 170 prop = _bfd_elf_get_property (abfd, type, datasz); 171 prop->pr_kind = property_number; 172 goto next; 173 174 default: 175 break; 176 } 177 } 178 179 _bfd_error_handler 180 (_("warning: %B: unsupported GNU_PROPERTY_TYPE (%ld) type: 0x%x"), 181 abfd, note->type, type); 182 183 next: 184 ptr += (datasz + (align_size - 1)) & ~ (align_size - 1); 185 if (ptr == ptr_end) 186 break; 187 188 if (ptr > (ptr_end - 8)) 189 goto bad_size; 190 } 191 192 return TRUE; 193 } 194 195 /* Merge GNU property BPROP with APROP. If APROP isn't NULL, return TRUE 196 if APROP is updated. Otherwise, return TRUE if BPROP should be merged 197 with ABFD. */ 198 199 static bfd_boolean 200 elf_merge_gnu_properties (bfd *abfd, elf_property *aprop, 201 elf_property *bprop) 202 { 203 const struct elf_backend_data *bed = get_elf_backend_data (abfd); 204 unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; 205 206 if (bed->merge_gnu_properties != NULL 207 && pr_type >= GNU_PROPERTY_LOPROC 208 && pr_type < GNU_PROPERTY_LOUSER) 209 return bed->merge_gnu_properties (abfd, aprop, bprop); 210 211 switch (pr_type) 212 { 213 case GNU_PROPERTY_STACK_SIZE: 214 if (aprop != NULL && bprop != NULL) 215 { 216 if (bprop->u.number > aprop->u.number) 217 { 218 aprop->u.number = bprop->u.number; 219 return TRUE; 220 } 221 break; 222 } 223 /* FALLTHROUGH */ 224 225 case GNU_PROPERTY_NO_COPY_ON_PROTECTED: 226 /* Return TRUE if APROP is NULL to indicate that BPROP should 227 be added to ABFD. */ 228 return aprop == NULL; 229 230 default: 231 /* Never should happen. */ 232 abort (); 233 } 234 235 return FALSE; 236 } 237 238 /* Return the property of TYPE on *LISTP and remove it from *LISTP. 239 Return NULL if not found. */ 240 241 static elf_property * 242 elf_find_and_remove_property (elf_property_list **listp, 243 unsigned int type) 244 { 245 elf_property_list *list; 246 247 for (list = *listp; list; list = list->next) 248 { 249 if (type == list->property.pr_type) 250 { 251 /* Remove this property. */ 252 *listp = list->next; 253 return &list->property; 254 } 255 else if (type < list->property.pr_type) 256 break; 257 listp = &list->next; 258 } 259 260 return NULL; 261 } 262 263 /* Merge GNU property list *LISTP with ABFD. */ 264 265 static void 266 elf_merge_gnu_property_list (bfd *abfd, elf_property_list **listp) 267 { 268 elf_property_list *p, **lastp; 269 elf_property *pr; 270 271 /* Merge each GNU property in ABFD with the one on *LISTP. */ 272 lastp = &elf_properties (abfd); 273 for (p = *lastp; p; p = p->next) 274 { 275 pr = elf_find_and_remove_property (listp, p->property.pr_type); 276 /* Pass NULL to elf_merge_gnu_properties for the property which 277 isn't on *LISTP. */ 278 elf_merge_gnu_properties (abfd, &p->property, pr); 279 if (p->property.pr_kind == property_remove) 280 { 281 /* Remove this property. */ 282 *lastp = p->next; 283 continue; 284 } 285 lastp = &p->next; 286 } 287 288 /* Merge the remaining properties on *LISTP with ABFD. */ 289 for (p = *listp; p != NULL; p = p->next) 290 if (elf_merge_gnu_properties (abfd, NULL, &p->property)) 291 { 292 pr = _bfd_elf_get_property (abfd, p->property.pr_type, 293 p->property.pr_datasz); 294 /* It must be a new property. */ 295 if (pr->pr_kind != property_unknown) 296 abort (); 297 /* Add a new property. */ 298 *pr = p->property; 299 } 300 } 301 302 /* Set up GNU properties. */ 303 304 void 305 _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) 306 { 307 bfd *abfd, *first_pbfd = NULL; 308 elf_property_list *list; 309 asection *sec; 310 bfd_boolean has_properties = FALSE; 311 const struct elf_backend_data *bed 312 = get_elf_backend_data (info->output_bfd); 313 unsigned int elfclass = bed->s->elfclass; 314 int elf_machine_code = bed->elf_machine_code; 315 316 /* Find the first relocatable ELF input with GNU properties. */ 317 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 318 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour 319 && bfd_count_sections (abfd) != 0 320 && elf_properties (abfd) != NULL) 321 { 322 has_properties = TRUE; 323 324 /* Ignore GNU properties from ELF objects with different machine 325 code or class. */ 326 if ((elf_machine_code 327 == get_elf_backend_data (abfd)->elf_machine_code) 328 && (elfclass 329 == get_elf_backend_data (abfd)->s->elfclass)) 330 { 331 /* Keep .note.gnu.property section in FIRST_PBFD. */ 332 first_pbfd = abfd; 333 break; 334 } 335 } 336 337 /* Do nothing if there is no .note.gnu.property section. */ 338 if (!has_properties) 339 return; 340 341 /* Merge .note.gnu.property sections. */ 342 for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) 343 if (abfd != first_pbfd && bfd_count_sections (abfd) != 0) 344 { 345 elf_property_list *null_ptr = NULL; 346 elf_property_list **listp = &null_ptr; 347 348 /* Merge .note.gnu.property section in relocatable ELF input. */ 349 if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) 350 { 351 list = elf_properties (abfd); 352 353 /* Ignore GNU properties from ELF objects with different 354 machine code. */ 355 if (list != NULL 356 && (elf_machine_code 357 == get_elf_backend_data (abfd)->elf_machine_code)) 358 listp = &elf_properties (abfd); 359 } 360 else 361 list = NULL; 362 363 /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL 364 when all properties are from ELF objects with different 365 machine code or class. */ 366 if (first_pbfd != NULL) 367 elf_merge_gnu_property_list (first_pbfd, listp); 368 369 if (list != NULL) 370 { 371 /* Discard .note.gnu.property section in the rest inputs. */ 372 sec = bfd_get_section_by_name (abfd, 373 NOTE_GNU_PROPERTY_SECTION_NAME); 374 sec->output_section = bfd_abs_section_ptr; 375 } 376 } 377 378 /* Rewrite .note.gnu.property section so that GNU properties are 379 always sorted by type even if input GNU properties aren't sorted. */ 380 if (first_pbfd != NULL) 381 { 382 unsigned int size; 383 unsigned int descsz; 384 bfd_byte *contents; 385 Elf_External_Note *e_note; 386 unsigned int align_size = bed->s->elfclass == ELFCLASS64 ? 8 : 4; 387 388 sec = bfd_get_section_by_name (first_pbfd, 389 NOTE_GNU_PROPERTY_SECTION_NAME); 390 391 /* Update stack size in .note.gnu.property with -z stack-size=N 392 if N > 0. */ 393 if (info->stacksize > 0) 394 { 395 elf_property *p; 396 bfd_vma stacksize = info->stacksize; 397 398 p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, 399 align_size); 400 if (p->pr_kind == property_unknown) 401 { 402 /* Create GNU_PROPERTY_STACK_SIZE. */ 403 p->u.number = stacksize; 404 p->pr_kind = property_number; 405 } 406 else if (stacksize > p->u.number) 407 p->u.number = stacksize; 408 } 409 else if (elf_properties (first_pbfd) == NULL) 410 { 411 /* Discard .note.gnu.property section if all properties have 412 been removed. */ 413 sec->output_section = bfd_abs_section_ptr; 414 return; 415 } 416 417 /* Compute the section size. */ 418 descsz = offsetof (Elf_External_Note, name[sizeof "GNU"]); 419 descsz = (descsz + 3) & -(unsigned int) 4; 420 size = descsz; 421 for (list = elf_properties (first_pbfd); 422 list != NULL; 423 list = list->next) 424 { 425 /* There are 4 byte type + 4 byte datasz for each property. */ 426 size += 4 + 4 + list->property.pr_datasz; 427 /* Align each property. */ 428 size = (size + (align_size - 1)) & ~(align_size - 1); 429 } 430 431 /* Update .note.gnu.property section now. */ 432 sec->size = size; 433 contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); 434 435 e_note = (Elf_External_Note *) contents; 436 bfd_h_put_32 (first_pbfd, sizeof "GNU", &e_note->namesz); 437 bfd_h_put_32 (first_pbfd, size - descsz, &e_note->descsz); 438 bfd_h_put_32 (first_pbfd, NT_GNU_PROPERTY_TYPE_0, &e_note->type); 439 memcpy (e_note->name, "GNU", sizeof "GNU"); 440 441 size = descsz; 442 for (list = elf_properties (first_pbfd); 443 list != NULL; 444 list = list->next) 445 { 446 /* There are 4 byte type + 4 byte datasz for each property. */ 447 bfd_h_put_32 (first_pbfd, list->property.pr_type, 448 contents + size); 449 bfd_h_put_32 (first_pbfd, list->property.pr_datasz, 450 contents + size + 4); 451 size += 4 + 4; 452 453 /* Write out property value. */ 454 switch (list->property.pr_kind) 455 { 456 case property_number: 457 switch (list->property.pr_datasz) 458 { 459 default: 460 /* Never should happen. */ 461 abort (); 462 463 case 0: 464 break; 465 466 case 4: 467 bfd_h_put_32 (first_pbfd, list->property.u.number, 468 contents + size); 469 break; 470 471 case 8: 472 bfd_h_put_64 (first_pbfd, list->property.u.number, 473 contents + size); 474 break; 475 } 476 break; 477 478 default: 479 /* Never should happen. */ 480 abort (); 481 } 482 size += list->property.pr_datasz; 483 484 /* Align each property. */ 485 size = (size + (align_size - 1)) & ~ (align_size - 1); 486 } 487 488 /* Cache the section contents for elf_link_input_bfd. */ 489 elf_section_data (sec)->this_hdr.contents = contents; 490 } 491 } 492