1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file. 4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Implementation notes: 61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// We need to remove a piece from the ELF shared library. However, we also 81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// want to ensure that code and data loads at the same addresses as before 91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// packing, so that tools like breakpad can still match up addresses found 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// in any crash dumps with data extracted from the pre-packed version of 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// the shared library. 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Arranging this means that we have to split one of the LOAD segments into 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// two. Unfortunately, the program headers are located at the very start 151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// of the shared library file, so expanding the program header section 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// would cause a lot of consequent changes to files offsets that we don't 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// really want to have to handle. 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Luckily, though, there is a segment that is always present and always 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// unused on Android; the GNU_STACK segment. What we do is to steal that 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// and repurpose it to be one of the split LOAD segments. We then have to 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// sort LOAD segments by offset to keep the crazy linker happy. 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// All of this takes place in SplitProgramHeadersForHole(), used on packing, 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// and is unraveled on unpacking in CoalesceProgramHeadersForHole(). See 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// commentary on those functions for an example of this segment stealing 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// in action. 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "elf_file.h" 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <stdlib.h> 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <sys/types.h> 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <unistd.h> 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <algorithm> 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <string> 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <vector> 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "debug.h" 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "elf_traits.h" 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "libelf.h" 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "packer.h" 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace relocation_packer { 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Stub identifier written to 'null out' packed data, "NULL". 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const uint32_t kStubIdentifier = 0x4c4c554eu; 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Out-of-band dynamic tags used to indicate the offset and size of the 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// android packed relocations section. 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const ELF::Sword DT_ANDROID_REL_OFFSET = DT_LOOS; 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const ELF::Sword DT_ANDROID_REL_SIZE = DT_LOOS + 1; 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Alignment to preserve, in bytes. This must be at least as large as the 54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// largest d_align and sh_addralign values found in the loaded file. 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Out of caution for RELRO page alignment, we preserve to a complete target 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// page. See http://www.airs.com/blog/archives/189. 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const size_t kPreserveAlignment = 4096; 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace { 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Get section data. Checks that the section has exactly one data entry, 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// so that the section size and the data size are the same. True in 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// practice for all sections we resize when packing or unpacking. Done 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// by ensuring that a call to elf_getdata(section, data) returns NULL as 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// the next data entry. 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)Elf_Data* GetSectionData(Elf_Scn* section) { 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Data* data = elf_getdata(section, NULL); 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(data && elf_getdata(section, data) == NULL); 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return data; 70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Rewrite section data. Allocates new data and makes it the data element's 73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// buffer. Relies on program exit to free allocated data. 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void RewriteSectionData(Elf_Data* data, 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* section_data, 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t size) { 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(size == data->d_size); 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint8_t* area = new uint8_t[size]; 79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) memcpy(area, section_data, size); 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) data->d_buf = area; 81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Verbose ELF header logging. 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void VerboseLogElfHeader(const ELF::Ehdr* elf_header) { 85116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_phoff = " << elf_header->e_phoff; 86116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_shoff = " << elf_header->e_shoff; 87116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_ehsize = " << elf_header->e_ehsize; 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_phentsize = " << elf_header->e_phentsize; 89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_phnum = " << elf_header->e_phnum; 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_shnum = " << elf_header->e_shnum; 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_shstrndx = " << elf_header->e_shstrndx; 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Verbose ELF program header logging. 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VerboseLogProgramHeader(size_t program_header_index, 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Phdr* program_header) { 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string type; 98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) switch (program_header->p_type) { 99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case PT_NULL: type = "NULL"; break; 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case PT_LOAD: type = "LOAD"; break; 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case PT_DYNAMIC: type = "DYNAMIC"; break; 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case PT_INTERP: type = "INTERP"; break; 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) case PT_PHDR: type = "PHDR"; break; 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case PT_GNU_RELRO: type = "GNU_RELRO"; break; 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case PT_GNU_STACK: type = "GNU_STACK"; break; 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci case PT_ARM_EXIDX: type = "EXIDX"; break; 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) default: type = "(OTHER)"; break; 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "phdr[" << program_header_index << "] : " << type; 110116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " p_offset = " << program_header->p_offset; 111116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " p_vaddr = " << program_header->p_vaddr; 112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " p_paddr = " << program_header->p_paddr; 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " p_filesz = " << program_header->p_filesz; 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " p_memsz = " << program_header->p_memsz; 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << " p_flags = " << program_header->p_flags; 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << " p_align = " << program_header->p_align; 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Verbose ELF section header logging. 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VerboseLogSectionHeader(const std::string& section_name, 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Shdr* section_header) { 122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "section " << section_name; 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " sh_addr = " << section_header->sh_addr; 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " sh_offset = " << section_header->sh_offset; 125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " sh_size = " << section_header->sh_size; 126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " sh_addralign = " << section_header->sh_addralign; 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Verbose ELF section data logging. 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void VerboseLogSectionData(const Elf_Data* data) { 131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " data"; 132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " d_buf = " << data->d_buf; 133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " d_off = " << data->d_off; 134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " d_size = " << data->d_size; 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << " d_align = " << data->d_align; 136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 138f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 139f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Load the complete ELF file into a memory image in libelf, and identify 1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// the .rel.dyn or .rela.dyn, .dynamic, and .android.rel.dyn or 1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// .android.rela.dyn sections. No-op if the ELF file has already been loaded. 143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfFile::Load() { 144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (elf_) 145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf* elf = elf_begin(fd_, ELF_C_RDWR, NULL); 1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(elf); 149f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (elf_kind(elf) != ELF_K_ELF) { 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(ERROR) << "File not in ELF format"; 152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Ehdr* elf_header = ELF::getehdr(elf); 156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!elf_header) { 1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Failed to load ELF header: " << elf_errmsg(elf_errno()); 1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (elf_header->e_machine != ELF::kMachine) { 1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "ELF file architecture is not " << ELF::Machine(); 162f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 163f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (elf_header->e_type != ET_DYN) { 1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "ELF file is not a shared object"; 166f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 167f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 168f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 169f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Require that our endianness matches that of the target, and that both 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // are little-endian. Safe for all current build/target combinations. 1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int endian = elf_header->e_ident[EI_DATA]; 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(endian == ELFDATA2LSB); 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__); 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Also require that the file class is as expected. 1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const int file_class = elf_header->e_ident[EI_CLASS]; 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(file_class == ELF::kFileClass); 1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VLOG(1) << "endian = " << endian << ", file class = " << file_class; 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VerboseLogElfHeader(elf_header); 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Phdr* elf_program_header = ELF::getphdr(elf); 183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(elf_program_header); 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Phdr* dynamic_program_header = NULL; 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < elf_header->e_phnum; ++i) { 1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Phdr* program_header = &elf_program_header[i]; 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VerboseLogProgramHeader(i, program_header); 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (program_header->p_type == PT_DYNAMIC) { 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(dynamic_program_header == NULL); 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_program_header = program_header; 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(dynamic_program_header != NULL); 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t string_index; 1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) elf_getshdrstrndx(elf, &string_index); 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Notes of the dynamic relocations, packed relocations, and .dynamic 2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // sections. Found while iterating sections, and later stored in class 2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // attributes. 2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf_Scn* found_relocations_section = NULL; 2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf_Scn* found_android_relocations_section = NULL; 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Scn* found_dynamic_section = NULL; 206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Notes of relocation section types seen. We require one or the other of 2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // these; both is unsupported. 2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool has_rel_relocations = false; 2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool has_rela_relocations = false; 2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Scn* section = NULL; 2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while ((section = elf_nextscn(elf, section)) != NULL) { 2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Shdr* section_header = ELF::getshdr(section); 2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::string name = elf_strptr(elf, string_index, section_header->sh_name); 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VerboseLogSectionHeader(name, section_header); 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Note relocation section types. 2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (section_header->sh_type == SHT_REL) { 2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) has_rel_relocations = true; 2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (section_header->sh_type == SHT_RELA) { 2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) has_rela_relocations = true; 2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Note special sections as we encounter them. 2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ((name == ".rel.dyn" || name == ".rela.dyn") && 2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) section_header->sh_size > 0) { 2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) found_relocations_section = section; 230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if ((name == ".android.rel.dyn" || name == ".android.rela.dyn") && 2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) section_header->sh_size > 0) { 2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) found_android_relocations_section = section; 234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (section_header->sh_offset == dynamic_program_header->p_offset) { 236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) found_dynamic_section = section; 237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Ensure we preserve alignment, repeated later for the data block(s). 240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(section_header->sh_addralign <= kPreserveAlignment); 241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Data* data = NULL; 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while ((data = elf_getdata(section, data)) != NULL) { 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(data->d_align <= kPreserveAlignment); 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VerboseLogSectionData(data); 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Loading failed if we did not find the required special sections. 2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!found_relocations_section) { 2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Missing or empty .rel.dyn or .rela.dyn section"; 2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!found_android_relocations_section) { 2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Missing or empty .android.rel.dyn or .android.rela.dyn " 2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << "section (to fix, run with --help and follow the " 2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << "pre-packing instructions)"; 258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!found_dynamic_section) { 261116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(ERROR) << "Missing .dynamic section"; 262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Loading failed if we could not identify the relocations type. 2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!has_rel_relocations && !has_rela_relocations) { 2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "No relocations sections found"; 2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (has_rel_relocations && has_rela_relocations) { 2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Multiple relocations sections with different types found, " 2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << "not currently supported"; 273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) elf_ = elf; 2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations_section_ = found_relocations_section; 278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_section_ = found_dynamic_section; 2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) android_relocations_section_ = found_android_relocations_section; 2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations_type_ = has_rel_relocations ? REL : RELA; 281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace { 285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Helper for ResizeSection(). Adjust the main ELF header for the hole. 2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AdjustElfHeaderForHole(ELF::Ehdr* elf_header, 2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Off hole_start, 2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ssize_t hole_size) { 290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (elf_header->e_phoff > hole_start) { 291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_header->e_phoff += hole_size; 292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_phoff adjusted to " << elf_header->e_phoff; 293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (elf_header->e_shoff > hole_start) { 295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_header->e_shoff += hole_size; 296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "e_shoff adjusted to " << elf_header->e_shoff; 297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Helper for ResizeSection(). Adjust all section headers for the hole. 301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void AdjustSectionHeadersForHole(Elf* elf, 3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Off hole_start, 3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ssize_t hole_size) { 304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t string_index; 305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_getshdrstrndx(elf, &string_index); 306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Scn* section = NULL; 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while ((section = elf_nextscn(elf, section)) != NULL) { 3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Shdr* section_header = ELF::getshdr(section); 310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string name = elf_strptr(elf, string_index, section_header->sh_name); 311f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (section_header->sh_offset > hole_start) { 313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) section_header->sh_offset += hole_size; 314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "section " << name 315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << " sh_offset adjusted to " << section_header->sh_offset; 3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Adjust the offsets of any program headers 3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// that have offsets currently beyond the hole start. 3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid AdjustProgramHeaderOffsets(ELF::Phdr* program_headers, 3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t count, 3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* ignored_1, 3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* ignored_2, 3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off hole_start, 3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ssize_t hole_size) { 3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < count; ++i) { 3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* program_header = &program_headers[i]; 3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header == ignored_1 || program_header == ignored_2) 3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci continue; 3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header->p_offset > hole_start) { 3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The hole start is past this segment, so adjust offset. 3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_offset += hole_size; 3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "phdr[" << i 3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "] p_offset adjusted to "<< program_header->p_offset; 3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Find the first loadable segment in the 3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// file. We expect it to map from file offset zero. 3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciELF::Phdr* FindFirstLoadSegment(ELF::Phdr* program_headers, 3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t count) { 3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* first_loadable_segment = NULL; 3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < count; ++i) { 3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* program_header = &program_headers[i]; 3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header->p_type == PT_LOAD && 3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_offset == 0 && 3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_vaddr == 0 && 3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_paddr == 0) { 3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci first_loadable_segment = program_header; 3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !first_loadable_segment) 3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Cannot locate a LOAD segment with address and offset zero"; 3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return first_loadable_segment; 3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Find the PT_GNU_STACK segment, and check 3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// that it contains what we expect so we can restore it on unpack if needed. 3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciELF::Phdr* FindUnusedGnuStackSegment(ELF::Phdr* program_headers, 3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t count) { 3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* unused_segment = NULL; 3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < count; ++i) { 3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* program_header = &program_headers[i]; 3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header->p_type == PT_GNU_STACK && 3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_offset == 0 && 3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_vaddr == 0 && 3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_paddr == 0 && 3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_filesz == 0 && 3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_memsz == 0 && 3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_flags == (PF_R | PF_W) && 3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_align == ELF::kGnuStackSegmentAlignment) { 3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci unused_segment = program_header; 3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !unused_segment) 3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Cannot locate the expected GNU_STACK segment"; 3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return unused_segment; 3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Find the segment that was the first loadable 3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// one before we split it into two. This is the one into which we coalesce 3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// the split segments on unpacking. 3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciELF::Phdr* FindOriginalFirstLoadSegment(ELF::Phdr* program_headers, 3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t count) { 3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Phdr* first_loadable_segment = 3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindFirstLoadSegment(program_headers, count); 3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* original_first_loadable_segment = NULL; 4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < count; ++i) { 4021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* program_header = &program_headers[i]; 4031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The original first loadable segment is the one that follows on from 4051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // the one we wrote on split to be the current first loadable segment. 4061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header->p_type == PT_LOAD && 4071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_offset == first_loadable_segment->p_filesz) { 4081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci original_first_loadable_segment = program_header; 4091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !original_first_loadable_segment) 4121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Cannot locate the LOAD segment that follows a LOAD at offset zero"; 4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return original_first_loadable_segment; 4151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 4161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Find the segment that contains the hole. 4181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciElf_Scn* FindSectionContainingHole(Elf* elf, 4191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off hole_start, 4201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ssize_t hole_size) { 4211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* section = NULL; 4221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* last_unholed_section = NULL; 4231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci while ((section = elf_nextscn(elf, section)) != NULL) { 4251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Shdr* section_header = ELF::getshdr(section); 4261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Because we get here after section headers have been adjusted for the 4281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // hole, we need to 'undo' that adjustment to give a view of the original 4291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // sections layout. 4301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off offset = section_header->sh_offset; 4311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (section_header->sh_offset >= hole_start) { 4321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci offset -= hole_size; 4331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (offset <= hole_start) { 4361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci last_unholed_section = section; 4371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !last_unholed_section) 4401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Cannot identify the section before the one containing the hole"; 4411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The section containing the hole is the one after the last one found 4431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // by the loop above. 4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* holed_section = elf_nextscn(elf, last_unholed_section); 4451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !holed_section) 4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Cannot identify the section containing the hole"; 4471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return holed_section; 4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Find the last section contained in a segment. 4521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciElf_Scn* FindLastSectionInSegment(Elf* elf, 4531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* program_header, 4541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off hole_start, 4551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ssize_t hole_size) { 4561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Off segment_end = 4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_offset + program_header->p_filesz; 4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* section = NULL; 4601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* last_section = NULL; 4611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci while ((section = elf_nextscn(elf, section)) != NULL) { 4631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Shdr* section_header = ELF::getshdr(section); 4641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // As above, 'undo' any section offset adjustment to give a view of the 4661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // original sections layout. 4671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off offset = section_header->sh_offset; 4681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (section_header->sh_offset >= hole_start) { 4691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci offset -= hole_size; 4701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (offset < segment_end) { 4731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci last_section = section; 4741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !last_section) 4771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "Cannot identify the last section in the given segment"; 4781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return last_section; 4801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 4811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Order loadable segments by their offsets. 4831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The crazy linker contains assumptions about loadable segment ordering, 4841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// and it is better if we do not break them. 4851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid SortOrderSensitiveProgramHeaders(ELF::Phdr* program_headers, 4861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t count) { 4871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::vector<ELF::Phdr*> orderable; 4881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Collect together orderable program headers. These are all the LOAD 4901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // segments, and any GNU_STACK that may be present (removed on packing, 4911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // but replaced on unpacking). 4921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < count; ++i) { 4931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* program_header = &program_headers[i]; 4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 4951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header->p_type == PT_LOAD || 4961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header->p_type == PT_GNU_STACK) { 4971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci orderable.push_back(program_header); 4981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 4991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 5001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Order these program headers so that any PT_GNU_STACK is last, and 5021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // the LOAD segments that precede it appear in offset order. Uses 5031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // insertion sort. 5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 1; i < orderable.size(); ++i) { 5051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t j = i; j > 0; --j) { 5061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* first = orderable[j - 1]; 5071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* second = orderable[j]; 5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!(first->p_type == PT_GNU_STACK || 5101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci first->p_offset > second->p_offset)) { 5111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci break; 512f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 5131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::swap(*first, *second); 514f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 515f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 516f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 517f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 5181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). The GNU_STACK program header is unused in 5191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Android, so we can repurpose it here. Before packing, the program header 5201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// table contains something like: 5211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 5221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 5231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// LOAD 0x000000 0x00000000 0x00000000 0x1efc818 0x1efc818 R E 0x1000 5241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// LOAD 0x1efd008 0x01efe008 0x01efe008 0x17ec3c 0x1a0324 RW 0x1000 5251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// DYNAMIC 0x205ec50 0x0205fc50 0x0205fc50 0x00108 0x00108 RW 0x4 5261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0 5271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 5281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The hole in the file is in the first of these. In order to preserve all 5291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// load addresses, what we do is to turn the GNU_STACK into a new LOAD entry 5301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// that maps segments up to where we created the hole, adjust the first LOAD 5311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// entry so that it maps segments after that, adjust any other program 5321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// headers whose offset is after the hole start, and finally order the LOAD 5331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// segments by offset, to give: 5341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 5351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align 5361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// LOAD 0x000000 0x00000000 0x00000000 0x14ea4 0x14ea4 R E 0x1000 5371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// LOAD 0x014ea4 0x00212ea4 0x00212ea4 0x1cea164 0x1cea164 R E 0x1000 5381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// DYNAMIC 0x1e60c50 0x0205fc50 0x0205fc50 0x00108 0x00108 RW 0x4 5391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// LOAD 0x1cff008 0x01efe008 0x01efe008 0x17ec3c 0x1a0324 RW 0x1000 5401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 5411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// We work out the split points by finding the .rel.dyn or .rela.dyn section 5421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// that contains the hole, and by finding the last section in a given segment. 5431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 5441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// To unpack, we reverse the above to leave the file as it was originally. 5451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid SplitProgramHeadersForHole(Elf* elf, 5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off hole_start, 5471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ssize_t hole_size) { 5481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(hole_size < 0); 5491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Ehdr* elf_header = ELF::getehdr(elf); 5501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(elf_header); 5511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* elf_program_header = ELF::getphdr(elf); 5531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(elf_program_header); 5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const size_t program_header_count = elf_header->e_phnum; 5561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Locate the segment that we can overwrite to form the new LOAD entry, 5581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // and the segment that we are going to split into two parts. 5591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* spliced_header = 5601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindUnusedGnuStackSegment(elf_program_header, program_header_count); 5611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* split_header = 5621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindFirstLoadSegment(elf_program_header, program_header_count); 5631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "phdr[" << split_header - elf_program_header << "] split"; 5651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "phdr[" << spliced_header - elf_program_header << "] new LOAD"; 5661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Find the section that contains the hole. We split on the section that 5681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // follows it. 5691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* holed_section = 5701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindSectionContainingHole(elf, hole_start, hole_size); 5711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t string_index; 5731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci elf_getshdrstrndx(elf, &string_index); 5741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Shdr* section_header = ELF::getshdr(holed_section); 5761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::string name = elf_strptr(elf, string_index, section_header->sh_name); 5771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "section " << name << " split after"; 5781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Find the last section in the segment we are splitting. 5801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* last_section = 5811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindLastSectionInSegment(elf, split_header, hole_start, hole_size); 5821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci section_header = ELF::getshdr(last_section); 5841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci name = elf_strptr(elf, string_index, section_header->sh_name); 5851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "section " << name << " split end"; 5861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Split on the section following the holed one, and up to (but not 5881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // including) the section following the last one in the split segment. 5891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* split_section = elf_nextscn(elf, holed_section); 5901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !split_section) 5911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "No section follows the section that contains the hole"; 5921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* end_section = elf_nextscn(elf, last_section); 5931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci LOG_IF(FATAL, !end_section) 5941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << "No section follows the last section in the segment being split"; 5951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Split the first portion of split_header into spliced_header. 5971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Shdr* split_section_header = ELF::getshdr(split_section); 5981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_type = split_header->p_type; 5991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_offset = split_header->p_offset; 6001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_vaddr = split_header->p_vaddr; 6011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_paddr = split_header->p_paddr; 6021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(split_header->p_filesz == split_header->p_memsz); 6031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_filesz = split_section_header->sh_offset; 6041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_memsz = split_section_header->sh_offset; 6051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_flags = split_header->p_flags; 6061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_align = split_header->p_align; 6071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Now rewrite split_header to remove the part we spliced from it. 6091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Shdr* end_section_header = ELF::getshdr(end_section); 6101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_offset = spliced_header->p_filesz; 6111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(split_header->p_vaddr == split_header->p_paddr); 6121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_vaddr = split_section_header->sh_addr; 6131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_paddr = split_section_header->sh_addr; 6141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(split_header->p_filesz == split_header->p_memsz); 6151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_filesz = 6161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci end_section_header->sh_offset - spliced_header->p_filesz; 6171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_memsz = 6181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci end_section_header->sh_offset - spliced_header->p_filesz; 6191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Adjust the offsets of all program headers that are not one of the pair 6211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // we just created by splitting. 6221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AdjustProgramHeaderOffsets(elf_program_header, 6231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header_count, 6241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header, 6251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header, 6261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci hole_start, 6271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci hole_size); 6281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Finally, order loadable segments by offset/address. The crazy linker 6301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // contains assumptions about loadable segment ordering. 6311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SortOrderSensitiveProgramHeaders(elf_program_header, 6321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header_count); 6331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 6341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Undo the work of SplitProgramHeadersForHole(). 6361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid CoalesceProgramHeadersForHole(Elf* elf, 6371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off hole_start, 6381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ssize_t hole_size) { 6391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(hole_size > 0); 6401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Ehdr* elf_header = ELF::getehdr(elf); 6411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(elf_header); 6421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* elf_program_header = ELF::getphdr(elf); 6441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(elf_program_header); 6451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const size_t program_header_count = elf_header->e_phnum; 6471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Locate the segment that we overwrote to form the new LOAD entry, and 6491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // the segment that we split into two parts on packing. 6501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* spliced_header = 6511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindFirstLoadSegment(elf_program_header, program_header_count); 6521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Phdr* split_header = 6531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindOriginalFirstLoadSegment(elf_program_header, program_header_count); 6541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "phdr[" << spliced_header - elf_program_header << "] stack"; 6561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "phdr[" << split_header - elf_program_header << "] coalesce"; 6571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Find the last section in the second segment we are coalescing. 6591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* last_section = 6601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FindLastSectionInSegment(elf, split_header, hole_start, hole_size); 6611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci size_t string_index; 6631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci elf_getshdrstrndx(elf, &string_index); 6641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Shdr* section_header = ELF::getshdr(last_section); 6661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci std::string name = elf_strptr(elf, string_index, section_header->sh_name); 6671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci VLOG(1) << "section " << name << " coalesced"; 6681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Rewrite the coalesced segment into split_header. 6701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Shdr* last_section_header = ELF::getshdr(last_section); 6711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_offset = spliced_header->p_offset; 6721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(split_header->p_vaddr == split_header->p_paddr); 6731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_vaddr = spliced_header->p_vaddr; 6741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_paddr = spliced_header->p_vaddr; 6751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(split_header->p_filesz == split_header->p_memsz); 6761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_filesz = 6771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci last_section_header->sh_offset + last_section_header->sh_size; 6781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header->p_memsz = 6791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci last_section_header->sh_offset + last_section_header->sh_size; 6801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Reconstruct the original GNU_STACK segment into spliced_header. 6821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_type = PT_GNU_STACK; 6831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_offset = 0; 6841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_vaddr = 0; 6851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_paddr = 0; 6861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_filesz = 0; 6871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_memsz = 0; 6881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_flags = PF_R | PF_W; 6891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header->p_align = ELF::kGnuStackSegmentAlignment; 6901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 6911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Adjust the offsets of all program headers that are not one of the pair 6921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // we just coalesced. 6931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AdjustProgramHeaderOffsets(elf_program_header, 6941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header_count, 6951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci spliced_header, 6961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci split_header, 6971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci hole_start, 6981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci hole_size); 6991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Finally, order loadable segments by offset/address. The crazy linker 7011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // contains assumptions about loadable segment ordering. 7021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SortOrderSensitiveProgramHeaders(elf_program_header, 7031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci program_header_count); 7041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 7051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Rewrite program headers. 7071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid RewriteProgramHeadersForHole(Elf* elf, 7081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Off hole_start, 7091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ssize_t hole_size) { 7101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If hole_size is negative then we are removing a piece of the file, and 7111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // we want to split program headers so that we keep the same addresses 7121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // for text and data. If positive, then we are putting that piece of the 7131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // file back in, so we coalesce the previously split program headers. 7141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (hole_size < 0) 7151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SplitProgramHeadersForHole(elf, hole_start, hole_size); 7161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci else if (hole_size > 0) 7171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CoalesceProgramHeadersForHole(elf, hole_start, hole_size); 7181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 7191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for ResizeSection(). Locate and return the dynamic section. 7211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciElf_Scn* GetDynamicSection(Elf* elf) { 7221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Ehdr* elf_header = ELF::getehdr(elf); 7231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(elf_header); 7241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Phdr* elf_program_header = ELF::getphdr(elf); 7261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(elf_program_header); 7271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Find the program header that describes the dynamic section. 7291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Phdr* dynamic_program_header = NULL; 7301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for (size_t i = 0; i < elf_header->e_phnum; ++i) { 7311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const ELF::Phdr* program_header = &elf_program_header[i]; 7321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (program_header->p_type == PT_DYNAMIC) { 7341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dynamic_program_header = program_header; 7351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(dynamic_program_header); 7381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Now find the section with the same offset as this program header. 7401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* dynamic_section = NULL; 7411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* section = NULL; 7421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci while ((section = elf_nextscn(elf, section)) != NULL) { 7431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Shdr* section_header = ELF::getshdr(section); 7441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (section_header->sh_offset == dynamic_program_header->p_offset) { 7461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dynamic_section = section; 7471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CHECK(dynamic_section != NULL); 7501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return dynamic_section; 7521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 7531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 754f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Helper for ResizeSection(). Adjust the .dynamic section for the hole. 7555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <typename Rel> 756f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void AdjustDynamicSectionForHole(Elf_Scn* dynamic_section, 7575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Off hole_start, 7585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ssize_t hole_size) { 759f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Data* data = GetSectionData(dynamic_section); 760f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Dyn* dynamic_base = reinterpret_cast<ELF::Dyn*>(data->d_buf); 7625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Dyn> dynamics( 763f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_base, 764f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_base + data->d_size / sizeof(dynamics[0])); 765f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 766f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < dynamics.size(); ++i) { 7675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Dyn* dynamic = &dynamics[i]; 7685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Sword tag = dynamic->d_tag; 769f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // DT_RELSZ or DT_RELASZ indicate the overall size of relocations. 7716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Only one will be present. Adjust by hole size. 7726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (tag == DT_RELSZ || tag == DT_RELASZ) { 7735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dynamic->d_un.d_val += hole_size; 7745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag 7755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << " d_val adjusted to " << dynamic->d_un.d_val; 7765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 777f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 7786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // DT_RELCOUNT or DT_RELACOUNT hold the count of relative relocations. 7796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Only one will be present. Packing reduces it to the alignment 7806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // padding, if any; unpacking restores it to its former value. The 7816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // crazy linker does not use it, but we update it anyway. 7826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (tag == DT_RELCOUNT || tag == DT_RELACOUNT) { 7835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Cast sizeof to a signed type to avoid the division result being 7845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // promoted into an unsigned size_t. 7855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ssize_t sizeof_rel = static_cast<ssize_t>(sizeof(Rel)); 7865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dynamic->d_un.d_val += hole_size / sizeof_rel; 7875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag 7885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << " d_val adjusted to " << dynamic->d_un.d_val; 7895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 7905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 7911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // DT_RELENT and DT_RELAENT do not change, but make sure they are what 7926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // we expect. Only one will be present. 7936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (tag == DT_RELENT || tag == DT_RELAENT) { 7945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(dynamic->d_un.d_val == sizeof(Rel)); 795f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 796f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 797f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 798f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) void* section_data = &dynamics[0]; 799f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t bytes = dynamics.size() * sizeof(dynamics[0]); 800f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, section_data, bytes); 801f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 802f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 803f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Resize a section. If the new size is larger than the current size, open 804f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// up a hole by increasing file offsets that come after the hole. If smaller 805f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// than the current size, remove the hole by decreasing those offsets. 8065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <typename Rel> 807f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ResizeSection(Elf* elf, Elf_Scn* section, size_t new_size) { 8085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Shdr* section_header = ELF::getshdr(section); 809f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (section_header->sh_size == new_size) 810f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 811f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Note if we are resizing the real dyn relocations. 813f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t string_index; 814f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_getshdrstrndx(elf, &string_index); 815f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string section_name = 816f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_strptr(elf, string_index, section_header->sh_name); 8175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const bool is_relocations_resize = 8185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) (section_name == ".rel.dyn" || section_name == ".rela.dyn"); 819f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 820f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Require that the section size and the data size are the same. True 821f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // in practice for all sections we resize when packing or unpacking. 822f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Elf_Data* data = GetSectionData(section); 823f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(data->d_off == 0 && data->d_size == section_header->sh_size); 824f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 825f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Require that the section is not zero-length (that is, has allocated 826f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // data that we can validly expand). 827f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(data->d_size && data->d_buf); 828f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Off hole_start = section_header->sh_offset; 8305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ssize_t hole_size = new_size - data->d_size; 831f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 832116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG_IF(1, (hole_size > 0)) << "expand section size = " << data->d_size; 833116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG_IF(1, (hole_size < 0)) << "shrink section size = " << data->d_size; 834f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 835f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Resize the data and the section header. 836f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) data->d_size += hole_size; 837f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) section_header->sh_size += hole_size; 838f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 839f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Add the hole size to all offsets in the ELF file that are after the 840f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // start of the hole. If the hole size is positive we are expanding the 841f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // section to create a new hole; if negative, we are closing up a hole. 842f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 843f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Start with the main ELF header. 8441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Ehdr* elf_header = ELF::getehdr(elf); 845f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AdjustElfHeaderForHole(elf_header, hole_start, hole_size); 846f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 847f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Adjust all section headers. 848f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AdjustSectionHeadersForHole(elf, hole_start, hole_size); 849f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If resizing the dynamic relocations, rewrite the program headers to 8511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // either split or coalesce segments, and adjust dynamic entries to match. 8521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (is_relocations_resize) { 8531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RewriteProgramHeadersForHole(elf, hole_start, hole_size); 854f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci Elf_Scn* dynamic_section = GetDynamicSection(elf); 8561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AdjustDynamicSectionForHole<Rel>(dynamic_section, hole_start, hole_size); 857f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 858f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 859f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Find the first slot in a dynamics array with the given tag. The array 8615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// always ends with a free (unused) element, and which we exclude from the 8625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// search. Returns dynamics->size() if not found. 8635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)size_t FindDynamicEntry(ELF::Sword tag, 8645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Dyn>* dynamics) { 8655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Loop until the penultimate entry. We exclude the end sentinel. 8665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = 0; i < dynamics->size() - 1; ++i) { 8675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (dynamics->at(i).d_tag == tag) 8685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return i; 8695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 8705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 8715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // The tag was not found. 8725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return dynamics->size(); 8735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 8745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 875f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Replace the first free (unused) slot in a dynamics vector with the given 876f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// value. The vector always ends with a free (unused) element, so the slot 877f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found cannot be the last one in the vector. 8785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void AddDynamicEntry(const ELF::Dyn& dyn, 8795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Dyn>* dynamics) { 8805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t slot = FindDynamicEntry(DT_NULL, dynamics); 8815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (slot == dynamics->size()) { 8825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(FATAL) << "No spare dynamic array slots found " 8835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << "(to fix, increase gold's --spare-dynamic-tags value)"; 884f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 885f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Replace this entry with the one supplied. 8875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dynamics->at(slot) = dyn; 8885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VLOG(1) << "dynamic[" << slot << "] overwritten with " << dyn.d_tag; 889f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 890f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 891f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Remove the element in the dynamics vector that matches the given tag with 892f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// unused slot data. Shuffle the following elements up, and ensure that the 893f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// last is the null sentinel. 8945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void RemoveDynamicEntry(ELF::Sword tag, 8955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Dyn>* dynamics) { 8965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t slot = FindDynamicEntry(tag, dynamics); 8975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(slot != dynamics->size()); 8985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 8995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Remove this entry by shuffling up everything that follows. 9005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) for (size_t i = slot; i < dynamics->size() - 1; ++i) { 9015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dynamics->at(i) = dynamics->at(i + 1); 9025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) VLOG(1) << "dynamic[" << i 9035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) << "] overwritten with dynamic[" << i + 1 << "]"; 904f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 905f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Ensure that the end sentinel is still present. 9075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(dynamics->at(dynamics->size() - 1).d_tag == DT_NULL); 908f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 909f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <typename Rel> 9115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void PadRelocations(size_t count, std::vector<Rel>* relocations); 9125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 9135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <> 9145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void PadRelocations<ELF::Rel>(size_t count, 9155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Rel>* relocations) { 9165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Rel null_relocation; 9175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_relocation.r_offset = 0; 9185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_relocation.r_info = ELF_R_INFO(0, ELF::kNoRelocationCode); 9195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Rel> padding(count, null_relocation); 9205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations->insert(relocations->end(), padding.begin(), padding.end()); 9215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 9225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 9235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <> 9245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void PadRelocations<ELF::Rela>(size_t count, 9255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Rela>* relocations) { 9265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Rela null_relocation; 9275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_relocation.r_offset = 0; 9285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_relocation.r_info = ELF_R_INFO(0, ELF::kNoRelocationCode); 9295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) null_relocation.r_addend = 0; 9305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Rela> padding(count, null_relocation); 931f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relocations->insert(relocations->end(), padding.begin(), padding.end()); 932f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 933f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 934f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 935f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Remove relative entries from dynamic relocations and write as packed 9375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// data into android packed relocations. 938f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfFile::PackRelocations() { 939f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Load the ELF file into libelf. 940f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!Load()) { 9415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Failed to load as ELF"; 942f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 943f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 944f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Retrieve the current dynamic relocations section data. 9465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf_Data* data = GetSectionData(relocations_section_); 947f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (relocations_type_ == REL) { 9495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Convert data to a vector of relocations. 9505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Rel* relocations_base = reinterpret_cast<ELF::Rel*>(data->d_buf); 9515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Rel> relocations( 9525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations_base, 9535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations_base + data->d_size / sizeof(relocations[0])); 9545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 9555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Relocations : REL"; 9565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return PackTypedRelocations<ELF::Rel>(relocations, data); 9575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 958f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 9595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (relocations_type_ == RELA) { 9605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Convert data to a vector of relocations with addends. 9615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Rela* relocations_base = 9625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) reinterpret_cast<ELF::Rela*>(data->d_buf); 9635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Rela> relocations( 9645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations_base, 9655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) relocations_base + data->d_size / sizeof(relocations[0])); 9665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 9675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Relocations : RELA"; 9685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return PackTypedRelocations<ELF::Rela>(relocations, data); 9695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 9705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 9715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) NOTREACHED(); 9725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 9735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 9745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 9755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Helper for PackRelocations(). Rel type is one of ELF::Rel or ELF::Rela. 9765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <typename Rel> 9775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ElfFile::PackTypedRelocations(const std::vector<Rel>& relocations, 9785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf_Data* data) { 9795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Filter relocations into those that are relative and others. 9805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<Rel> relative_relocations; 9815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<Rel> other_relocations; 982f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 983f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < relocations.size(); ++i) { 9845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Rel& relocation = relocations[i]; 9855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ELF_R_TYPE(relocation.r_info) == ELF::kRelativeRelocationCode) { 9865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(ELF_R_SYM(relocation.r_info) == 0); 987f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relative_relocations.push_back(relocation); 988f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 989f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) other_relocations.push_back(relocation); 990f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 991f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 9925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Relative : " << relative_relocations.size() << " entries"; 993116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(INFO) << "Other : " << other_relocations.size() << " entries"; 994116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(INFO) << "Total : " << relocations.size() << " entries"; 995f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 996f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // If no relative relocations then we have nothing packable. Perhaps 997f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the shared object has already been packed? 998f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (relative_relocations.empty()) { 9995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "No relative relocations found (already packed?)"; 1000f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 1001f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1002f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If not padding fully, apply only enough padding to preserve alignment. 10041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Otherwise, pad so that we do not shrink the relocations section at all. 10055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (!is_padding_relocations_) { 10061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Calculate the size of the hole we will close up when we rewrite 10071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // dynamic relocations. 10085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Shdr* section_header = ELF::getshdr(relocations_section_); 10095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Off hole_start = section_header->sh_offset; 10105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ssize_t hole_size = 1011f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relative_relocations.size() * sizeof(relative_relocations[0]); 10125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ssize_t unaligned_hole_size = hole_size; 1013f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Adjust the actual hole size to preserve alignment. We always adjust 10155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // by a whole number of NONE-type relocations. 10165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) while (hole_size % kPreserveAlignment) 10175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) hole_size -= sizeof(relative_relocations[0]); 1018116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(INFO) << "Compaction : " << hole_size << " bytes"; 1019f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1020f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Adjusting for alignment may have removed any packing benefit. 1021f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (hole_size == 0) { 10225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Too few relative relocations to pack after alignment"; 1023f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 1024f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1025f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Find the padding needed in other_relocations to preserve alignment. 10275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Ensure that we never completely empty the real relocations section. 10285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t padding_bytes = unaligned_hole_size - hole_size; 10295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (padding_bytes == 0 && other_relocations.size() == 0) { 10305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) do { 10315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) padding_bytes += sizeof(relative_relocations[0]); 10325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } while (padding_bytes % kPreserveAlignment); 10335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 1034f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(padding_bytes % sizeof(other_relocations[0]) == 0); 10355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t padding = padding_bytes / sizeof(other_relocations[0]); 10365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 10375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Padding may have removed any packing benefit. 10385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (padding >= relative_relocations.size()) { 10395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Too few relative relocations to pack after padding"; 10405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 10415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 10425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 10435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Add null relocations to other_relocations to preserve alignment. 10445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PadRelocations<Rel>(padding, &other_relocations); 10455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Alignment pad : " << padding << " relocations"; 1046f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 10475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If padding, add NONE-type relocations to other_relocations to make it 1048f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the same size as the the original relocations we read in. This makes 1049f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // the ResizeSection() below a no-op. 10505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const size_t padding = relocations.size() - other_relocations.size(); 10515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) PadRelocations<Rel>(padding, &other_relocations); 1052f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1053f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Pack relative relocations. 1055f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t initial_bytes = 1056f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relative_relocations.size() * sizeof(relative_relocations[0]); 10575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Unpacked relative: " << initial_bytes << " bytes"; 1058f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<uint8_t> packed; 1059f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RelocationPacker packer; 1060f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) packer.PackRelativeRelocations(relative_relocations, &packed); 1061f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* packed_data = &packed[0]; 1062f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t packed_bytes = packed.size() * sizeof(packed[0]); 10635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Packed relative: " << packed_bytes << " bytes"; 1064f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If we have insufficient relative relocations to form a run then 1066f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // packing fails. 1067f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (packed.empty()) { 10685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Too few relative relocations to pack"; 1069f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 1070f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1071f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1072f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Run a loopback self-test as a check that packing is lossless. 10735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<Rel> unpacked; 1074f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) packer.UnpackRelativeRelocations(packed, &unpacked); 1075f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(unpacked.size() == relative_relocations.size()); 10765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(!memcmp(&unpacked[0], 10775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) &relative_relocations[0], 10785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) unpacked.size() * sizeof(unpacked[0]))); 1079f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1080f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Make sure packing saved some space. 1081f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (packed_bytes >= initial_bytes) { 10825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Packing relative relocations saves no space"; 1083f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 1084f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1085f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Rewrite the current dynamic relocations section to be only the ARM 10875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // non-relative relocations, then shrink it to size. 1088f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* section_data = &other_relocations[0]; 1089f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t bytes = other_relocations.size() * sizeof(other_relocations[0]); 10905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ResizeSection<Rel>(elf_, relocations_section_, bytes); 1091f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, section_data, bytes); 1092f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Rewrite the current packed android relocations section to hold the packed 10945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // relative relocations. 10955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data = GetSectionData(android_relocations_section_); 10965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ResizeSection<Rel>(elf_, android_relocations_section_, packed_bytes); 1097f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, packed_data, packed_bytes); 1098f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 10995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Rewrite .dynamic to include two new tags describing the packed android 11005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // relocations. 1101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) data = GetSectionData(dynamic_section_); 11025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Dyn* dynamic_base = reinterpret_cast<ELF::Dyn*>(data->d_buf); 11035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Dyn> dynamics( 1104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_base, 1105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_base + data->d_size / sizeof(dynamics[0])); 11065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Use two of the spare slots to describe the packed section. 11075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Shdr* section_header = ELF::getshdr(android_relocations_section_); 11081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci { 11091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Dyn dyn; 11101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dyn.d_tag = DT_ANDROID_REL_OFFSET; 11111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dyn.d_un.d_ptr = section_header->sh_offset; 11121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AddDynamicEntry(dyn, &dynamics); 11131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 11141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci { 11151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ELF::Dyn dyn; 11161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dyn.d_tag = DT_ANDROID_REL_SIZE; 11171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci dyn.d_un.d_val = section_header->sh_size; 11181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AddDynamicEntry(dyn, &dynamics); 11191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 1120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* dynamics_data = &dynamics[0]; 1121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t dynamics_bytes = dynamics.size() * sizeof(dynamics[0]); 1122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, dynamics_data, dynamics_bytes); 1123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Flush(); 1125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 1126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 1127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Find packed relative relocations in the packed android relocations 11295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// section, unpack them, and rewrite the dynamic relocations section to 11305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// contain unpacked data. 1131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool ElfFile::UnpackRelocations() { 1132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Load the ELF file into libelf. 1133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!Load()) { 11345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Failed to load as ELF"; 1135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return false; 1136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Retrieve the current packed android relocations section data. 11395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf_Data* data = GetSectionData(android_relocations_section_); 1140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1141f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Convert data to a vector of bytes. 1142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const uint8_t* packed_base = reinterpret_cast<uint8_t*>(data->d_buf); 1143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::vector<uint8_t> packed( 1144f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) packed_base, 1145f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) packed_base + data->d_size / sizeof(packed[0])); 1146f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (packed.size() > 3 && 11485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[0] == 'A' && 11495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[1] == 'P' && 11505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[2] == 'R' && 11515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[3] == '1') { 11525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Signature is APR1, unpack relocations. 11535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(relocations_type_ == REL); 11545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Relocations : REL"; 11555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return UnpackTypedRelocations<ELF::Rel>(packed, data); 1156f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (packed.size() > 3 && 11595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[0] == 'A' && 11605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[1] == 'P' && 11615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[2] == 'A' && 11625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) packed[3] == '1') { 11635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Signature is APA1, unpack relocations with addends. 11645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) CHECK(relocations_type_ == RELA); 11655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Relocations : RELA"; 11665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return UnpackTypedRelocations<ELF::Rela>(packed, data); 11675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 11685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(ERROR) << "Packed relative relocations not found (not packed?)"; 11705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return false; 11715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 11725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Helper for UnpackRelocations(). Rel type is one of ELF::Rel or ELF::Rela. 11745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <typename Rel> 11755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)bool ElfFile::UnpackTypedRelocations(const std::vector<uint8_t>& packed, 11765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Elf_Data* data) { 11775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Unpack the data to re-materialize the relative relocations. 1178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t packed_bytes = packed.size() * sizeof(packed[0]); 11795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Packed relative: " << packed_bytes << " bytes"; 11805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<Rel> relative_relocations; 1181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RelocationPacker packer; 1182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) packer.UnpackRelativeRelocations(packed, &relative_relocations); 1183f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t unpacked_bytes = 1184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relative_relocations.size() * sizeof(relative_relocations[0]); 11855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Unpacked relative: " << unpacked_bytes << " bytes"; 1186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Retrieve the current dynamic relocations section data. 11885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data = GetSectionData(relocations_section_); 1189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Interpret data as relocations. 11915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Rel* relocations_base = reinterpret_cast<Rel*>(data->d_buf); 11925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<Rel> relocations( 1193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relocations_base, 1194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relocations_base + data->d_size / sizeof(relocations[0])); 1195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<Rel> other_relocations; 1197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t padding = 0; 1198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 11995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Filter relocations to locate any that are NONE-type. These will occur 1200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // if padding was turned on for packing. 1201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (size_t i = 0; i < relocations.size(); ++i) { 12025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Rel& relocation = relocations[i]; 12035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (ELF_R_TYPE(relocation.r_info) != ELF::kNoRelocationCode) { 1204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) other_relocations.push_back(relocation); 1205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 1206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ++padding; 1207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 12095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) LOG(INFO) << "Relative : " << relative_relocations.size() << " entries"; 1210116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(INFO) << "Other : " << other_relocations.size() << " entries"; 1211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If we found the same number of null relocation entries in the dynamic 12135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // relocations section as we hold as unpacked relative relocations, then 12145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // this is a padded file. 1215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const bool is_padded = padding == relative_relocations.size(); 1216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Unless padded, pre-apply relative relocations to account for the 1218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // hole, and pre-adjust all relocation offsets accordingly. 1219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!is_padded) { 1220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Pre-calculate the size of the hole we will open up when we rewrite 12215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // dynamic relocations. We have to adjust relocation addresses to 12225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // account for this. 12235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ELF::Shdr* section_header = ELF::getshdr(relocations_section_); 12245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Off hole_start = section_header->sh_offset; 12255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ssize_t hole_size = 1226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relative_relocations.size() * sizeof(relative_relocations[0]); 1227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Adjust the hole size for the padding added to preserve alignment. 1229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) hole_size -= padding * sizeof(other_relocations[0]); 1230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(INFO) << "Expansion : " << hole_size << " bytes"; 1231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Rewrite the current dynamic relocations section to be the relative 12345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // relocations followed by other relocations. This is the usual order in 12355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // which we find them after linking, so this action will normally put the 12365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // entire dynamic relocations section back to its pre-split-and-packed state. 1237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relocations.assign(relative_relocations.begin(), relative_relocations.end()); 1238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) relocations.insert(relocations.end(), 1239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) other_relocations.begin(), other_relocations.end()); 1240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* section_data = &relocations[0]; 1241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t bytes = relocations.size() * sizeof(relocations[0]); 1242116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch LOG(INFO) << "Total : " << relocations.size() << " entries"; 12435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ResizeSection<Rel>(elf_, relocations_section_, bytes); 1244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, section_data, bytes); 1245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Nearly empty the current packed android relocations section. Leaves a 12475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // four-byte stub so that some data remains allocated to the section. 12485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // This is a convenience which allows us to re-pack this file again without 1249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // having to remove the section and then add a new small one with objcopy. 1250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // The way we resize sections relies on there being some data in a section. 12515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) data = GetSectionData(android_relocations_section_); 12525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) ResizeSection<Rel>( 12535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) elf_, android_relocations_section_, sizeof(kStubIdentifier)); 1254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, &kStubIdentifier, sizeof(kStubIdentifier)); 1255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 12565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Rewrite .dynamic to remove two tags describing packed android relocations. 1257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) data = GetSectionData(dynamic_section_); 12585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const ELF::Dyn* dynamic_base = reinterpret_cast<ELF::Dyn*>(data->d_buf); 12595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) std::vector<ELF::Dyn> dynamics( 1260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_base, 1261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dynamic_base + data->d_size / sizeof(dynamics[0])); 12625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) RemoveDynamicEntry(DT_ANDROID_REL_OFFSET, &dynamics); 12635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) RemoveDynamicEntry(DT_ANDROID_REL_SIZE, &dynamics); 1264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const void* dynamics_data = &dynamics[0]; 1265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const size_t dynamics_bytes = dynamics.size() * sizeof(dynamics[0]); 1266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) RewriteSectionData(data, dynamics_data, dynamics_bytes); 1267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) Flush(); 1269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return true; 1270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 1271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Flush rewritten shared object file data. 1273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void ElfFile::Flush() { 1274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Flag all ELF data held in memory as needing to be written back to the 1275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // file, and tell libelf that we have controlled the file layout. 1276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_flagelf(elf_, ELF_C_SET, ELF_F_DIRTY); 1277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_flagelf(elf_, ELF_C_SET, ELF_F_LAYOUT); 1278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Write ELF data back to disk. 1280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const off_t file_bytes = elf_update(elf_, ELF_C_WRITE); 1281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(file_bytes > 0); 1282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch VLOG(1) << "elf_update returned: " << file_bytes; 1283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Clean up libelf, and truncate the output file to the number of bytes 1285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // written by elf_update(). 1286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_end(elf_); 1287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) elf_ = NULL; 1288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const int truncate = ftruncate(fd_, file_bytes); 1289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CHECK(truncate == 0); 1290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 1291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 1292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace relocation_packer 1293