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 |