| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Implementation notes: | 5 // Implementation notes: |
| 6 // | 6 // |
| 7 // We need to remove a piece from the ELF shared library. However, we also | 7 // We need to remove a piece from the ELF shared library. However, we also |
| 8 // want to ensure that code and data loads at the same addresses as before | 8 // want to ensure that code and data loads at the same addresses as before |
| 9 // packing, so that tools like breakpad can still match up addresses found | 9 // packing, so that tools like breakpad can still match up addresses found |
| 10 // in any crash dumps with data extracted from the pre-packed version of | 10 // in any crash dumps with data extracted from the pre-packed version of |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 // android packed relocations section. | 49 // android packed relocations section. |
| 50 static const ELF::Sword DT_ANDROID_REL_OFFSET = DT_LOOS; | 50 static const ELF::Sword DT_ANDROID_REL_OFFSET = DT_LOOS; |
| 51 static const ELF::Sword DT_ANDROID_REL_SIZE = DT_LOOS + 1; | 51 static const ELF::Sword DT_ANDROID_REL_SIZE = DT_LOOS + 1; |
| 52 | 52 |
| 53 // Alignment to preserve, in bytes. This must be at least as large as the | 53 // Alignment to preserve, in bytes. This must be at least as large as the |
| 54 // largest d_align and sh_addralign values found in the loaded file. | 54 // largest d_align and sh_addralign values found in the loaded file. |
| 55 // Out of caution for RELRO page alignment, we preserve to a complete target | 55 // Out of caution for RELRO page alignment, we preserve to a complete target |
| 56 // page. See http://www.airs.com/blog/archives/189. | 56 // page. See http://www.airs.com/blog/archives/189. |
| 57 static const size_t kPreserveAlignment = 4096; | 57 static const size_t kPreserveAlignment = 4096; |
| 58 | 58 |
| 59 // Alignment values used by ld and gold for the GNU_STACK segment. Different |
| 60 // linkers write different values; the actual value is immaterial on Android |
| 61 // because it ignores GNU_STACK segments. However, it is useful for binary |
| 62 // comparison and unit test purposes if packing and unpacking can preserve |
| 63 // them through a round-trip. |
| 64 static const size_t kLdGnuStackSegmentAlignment = 16; |
| 65 static const size_t kGoldGnuStackSegmentAlignment = 0; |
| 66 |
| 59 namespace { | 67 namespace { |
| 60 | 68 |
| 61 // Get section data. Checks that the section has exactly one data entry, | 69 // Get section data. Checks that the section has exactly one data entry, |
| 62 // so that the section size and the data size are the same. True in | 70 // so that the section size and the data size are the same. True in |
| 63 // practice for all sections we resize when packing or unpacking. Done | 71 // practice for all sections we resize when packing or unpacking. Done |
| 64 // by ensuring that a call to elf_getdata(section, data) returns NULL as | 72 // by ensuring that a call to elf_getdata(section, data) returns NULL as |
| 65 // the next data entry. | 73 // the next data entry. |
| 66 Elf_Data* GetSectionData(Elf_Scn* section) { | 74 Elf_Data* GetSectionData(Elf_Scn* section) { |
| 67 Elf_Data* data = elf_getdata(section, NULL); | 75 Elf_Data* data = elf_getdata(section, NULL); |
| 68 CHECK(data && elf_getdata(section, data) == NULL); | 76 CHECK(data && elf_getdata(section, data) == NULL); |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 program_header->p_paddr == 0) { | 364 program_header->p_paddr == 0) { |
| 357 first_loadable_segment = program_header; | 365 first_loadable_segment = program_header; |
| 358 } | 366 } |
| 359 } | 367 } |
| 360 LOG_IF(FATAL, !first_loadable_segment) | 368 LOG_IF(FATAL, !first_loadable_segment) |
| 361 << "Cannot locate a LOAD segment with address and offset zero"; | 369 << "Cannot locate a LOAD segment with address and offset zero"; |
| 362 | 370 |
| 363 return first_loadable_segment; | 371 return first_loadable_segment; |
| 364 } | 372 } |
| 365 | 373 |
| 374 // Helper for ResizeSection(). Deduce the alignment that the PT_GNU_STACK |
| 375 // segment will use. Determined by sensing the linker that was used to |
| 376 // create the shared library. |
| 377 size_t DeduceGnuStackSegmentAlignment(Elf* elf) { |
| 378 size_t string_index; |
| 379 elf_getshdrstrndx(elf, &string_index); |
| 380 |
| 381 Elf_Scn* section = NULL; |
| 382 size_t gnu_stack_segment_alignment = kLdGnuStackSegmentAlignment; |
| 383 |
| 384 while ((section = elf_nextscn(elf, section)) != NULL) { |
| 385 const ELF::Shdr* section_header = ELF::getshdr(section); |
| 386 std::string name = elf_strptr(elf, string_index, section_header->sh_name); |
| 387 |
| 388 if (name == ".note.gnu.gold-version") { |
| 389 gnu_stack_segment_alignment = kGoldGnuStackSegmentAlignment; |
| 390 break; |
| 391 } |
| 392 } |
| 393 |
| 394 return gnu_stack_segment_alignment; |
| 395 } |
| 396 |
| 366 // Helper for ResizeSection(). Find the PT_GNU_STACK segment, and check | 397 // Helper for ResizeSection(). Find the PT_GNU_STACK segment, and check |
| 367 // that it contains what we expect so we can restore it on unpack if needed. | 398 // that it contains what we expect so we can restore it on unpack if needed. |
| 368 ELF::Phdr* FindUnusedGnuStackSegment(ELF::Phdr* program_headers, | 399 ELF::Phdr* FindUnusedGnuStackSegment(Elf* elf, |
| 400 ELF::Phdr* program_headers, |
| 369 size_t count) { | 401 size_t count) { |
| 370 ELF::Phdr* unused_segment = NULL; | 402 ELF::Phdr* unused_segment = NULL; |
| 403 const size_t stack_alignment = DeduceGnuStackSegmentAlignment(elf); |
| 371 | 404 |
| 372 for (size_t i = 0; i < count; ++i) { | 405 for (size_t i = 0; i < count; ++i) { |
| 373 ELF::Phdr* program_header = &program_headers[i]; | 406 ELF::Phdr* program_header = &program_headers[i]; |
| 374 | 407 |
| 375 if (program_header->p_type == PT_GNU_STACK && | 408 if (program_header->p_type == PT_GNU_STACK && |
| 376 program_header->p_offset == 0 && | 409 program_header->p_offset == 0 && |
| 377 program_header->p_vaddr == 0 && | 410 program_header->p_vaddr == 0 && |
| 378 program_header->p_paddr == 0 && | 411 program_header->p_paddr == 0 && |
| 379 program_header->p_filesz == 0 && | 412 program_header->p_filesz == 0 && |
| 380 program_header->p_memsz == 0 && | 413 program_header->p_memsz == 0 && |
| 381 program_header->p_flags == (PF_R | PF_W) && | 414 program_header->p_flags == (PF_R | PF_W) && |
| 382 program_header->p_align == ELF::kGnuStackSegmentAlignment) { | 415 program_header->p_align == stack_alignment) { |
| 383 unused_segment = program_header; | 416 unused_segment = program_header; |
| 384 } | 417 } |
| 385 } | 418 } |
| 386 LOG_IF(FATAL, !unused_segment) | 419 LOG_IF(FATAL, !unused_segment) |
| 387 << "Cannot locate the expected GNU_STACK segment"; | 420 << "Cannot locate the expected GNU_STACK segment"; |
| 388 | 421 |
| 389 return unused_segment; | 422 return unused_segment; |
| 390 } | 423 } |
| 391 | 424 |
| 392 // Helper for ResizeSection(). Find the segment that was the first loadable | 425 // Helper for ResizeSection(). Find the segment that was the first loadable |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 CHECK(elf_header); | 584 CHECK(elf_header); |
| 552 | 585 |
| 553 ELF::Phdr* elf_program_header = ELF::getphdr(elf); | 586 ELF::Phdr* elf_program_header = ELF::getphdr(elf); |
| 554 CHECK(elf_program_header); | 587 CHECK(elf_program_header); |
| 555 | 588 |
| 556 const size_t program_header_count = elf_header->e_phnum; | 589 const size_t program_header_count = elf_header->e_phnum; |
| 557 | 590 |
| 558 // Locate the segment that we can overwrite to form the new LOAD entry, | 591 // Locate the segment that we can overwrite to form the new LOAD entry, |
| 559 // and the segment that we are going to split into two parts. | 592 // and the segment that we are going to split into two parts. |
| 560 ELF::Phdr* spliced_header = | 593 ELF::Phdr* spliced_header = |
| 561 FindUnusedGnuStackSegment(elf_program_header, program_header_count); | 594 FindUnusedGnuStackSegment(elf, elf_program_header, program_header_count); |
| 562 ELF::Phdr* split_header = | 595 ELF::Phdr* split_header = |
| 563 FindFirstLoadSegment(elf_program_header, program_header_count); | 596 FindFirstLoadSegment(elf_program_header, program_header_count); |
| 564 | 597 |
| 565 VLOG(1) << "phdr[" << split_header - elf_program_header << "] split"; | 598 VLOG(1) << "phdr[" << split_header - elf_program_header << "] split"; |
| 566 VLOG(1) << "phdr[" << spliced_header - elf_program_header << "] new LOAD"; | 599 VLOG(1) << "phdr[" << spliced_header - elf_program_header << "] new LOAD"; |
| 567 | 600 |
| 568 // Find the section that contains the hole. We split on the section that | 601 // Find the section that contains the hole. We split on the section that |
| 569 // follows it. | 602 // follows it. |
| 570 Elf_Scn* holed_section = | 603 Elf_Scn* holed_section = |
| 571 FindSectionContainingHole(elf, hole_start, hole_size); | 604 FindSectionContainingHole(elf, hole_start, hole_size); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 CHECK(split_header->p_vaddr == split_header->p_paddr); | 706 CHECK(split_header->p_vaddr == split_header->p_paddr); |
| 674 split_header->p_vaddr = spliced_header->p_vaddr; | 707 split_header->p_vaddr = spliced_header->p_vaddr; |
| 675 split_header->p_paddr = spliced_header->p_vaddr; | 708 split_header->p_paddr = spliced_header->p_vaddr; |
| 676 CHECK(split_header->p_filesz == split_header->p_memsz); | 709 CHECK(split_header->p_filesz == split_header->p_memsz); |
| 677 split_header->p_filesz = | 710 split_header->p_filesz = |
| 678 last_section_header->sh_offset + last_section_header->sh_size; | 711 last_section_header->sh_offset + last_section_header->sh_size; |
| 679 split_header->p_memsz = | 712 split_header->p_memsz = |
| 680 last_section_header->sh_offset + last_section_header->sh_size; | 713 last_section_header->sh_offset + last_section_header->sh_size; |
| 681 | 714 |
| 682 // Reconstruct the original GNU_STACK segment into spliced_header. | 715 // Reconstruct the original GNU_STACK segment into spliced_header. |
| 716 const size_t stack_alignment = DeduceGnuStackSegmentAlignment(elf); |
| 683 spliced_header->p_type = PT_GNU_STACK; | 717 spliced_header->p_type = PT_GNU_STACK; |
| 684 spliced_header->p_offset = 0; | 718 spliced_header->p_offset = 0; |
| 685 spliced_header->p_vaddr = 0; | 719 spliced_header->p_vaddr = 0; |
| 686 spliced_header->p_paddr = 0; | 720 spliced_header->p_paddr = 0; |
| 687 spliced_header->p_filesz = 0; | 721 spliced_header->p_filesz = 0; |
| 688 spliced_header->p_memsz = 0; | 722 spliced_header->p_memsz = 0; |
| 689 spliced_header->p_flags = PF_R | PF_W; | 723 spliced_header->p_flags = PF_R | PF_W; |
| 690 spliced_header->p_align = ELF::kGnuStackSegmentAlignment; | 724 spliced_header->p_align = stack_alignment; |
| 691 | 725 |
| 692 // Adjust the offsets of all program headers that are not one of the pair | 726 // Adjust the offsets of all program headers that are not one of the pair |
| 693 // we just coalesced. | 727 // we just coalesced. |
| 694 AdjustProgramHeaderOffsets(elf_program_header, | 728 AdjustProgramHeaderOffsets(elf_program_header, |
| 695 program_header_count, | 729 program_header_count, |
| 696 spliced_header, | 730 spliced_header, |
| 697 split_header, | 731 split_header, |
| 698 hole_start, | 732 hole_start, |
| 699 hole_size); | 733 hole_size); |
| 700 | 734 |
| (...skipping 573 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1274 | 1308 |
| 1275 // Clean up libelf, and truncate the output file to the number of bytes | 1309 // Clean up libelf, and truncate the output file to the number of bytes |
| 1276 // written by elf_update(). | 1310 // written by elf_update(). |
| 1277 elf_end(elf_); | 1311 elf_end(elf_); |
| 1278 elf_ = NULL; | 1312 elf_ = NULL; |
| 1279 const int truncate = ftruncate(fd_, file_bytes); | 1313 const int truncate = ftruncate(fd_, file_bytes); |
| 1280 CHECK(truncate == 0); | 1314 CHECK(truncate == 0); |
| 1281 } | 1315 } |
| 1282 | 1316 |
| 1283 } // namespace relocation_packer | 1317 } // namespace relocation_packer |
| OLD | NEW |