1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/build/unix/elfhack/elf.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,918 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#undef NDEBUG 1.9 +#include <cstring> 1.10 +#include <assert.h> 1.11 +#include "elfxx.h" 1.12 + 1.13 +template <class endian, typename R, typename T> 1.14 +void Elf_Ehdr_Traits::swap(T &t, R &r) 1.15 +{ 1.16 + memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident)); 1.17 + r.e_type = endian::swap(t.e_type); 1.18 + r.e_machine = endian::swap(t.e_machine); 1.19 + r.e_version = endian::swap(t.e_version); 1.20 + r.e_entry = endian::swap(t.e_entry); 1.21 + r.e_phoff = endian::swap(t.e_phoff); 1.22 + r.e_shoff = endian::swap(t.e_shoff); 1.23 + r.e_flags = endian::swap(t.e_flags); 1.24 + r.e_ehsize = endian::swap(t.e_ehsize); 1.25 + r.e_phentsize = endian::swap(t.e_phentsize); 1.26 + r.e_phnum = endian::swap(t.e_phnum); 1.27 + r.e_shentsize = endian::swap(t.e_shentsize); 1.28 + r.e_shnum = endian::swap(t.e_shnum); 1.29 + r.e_shstrndx = endian::swap(t.e_shstrndx); 1.30 +} 1.31 + 1.32 +template <class endian, typename R, typename T> 1.33 +void Elf_Phdr_Traits::swap(T &t, R &r) 1.34 +{ 1.35 + r.p_type = endian::swap(t.p_type); 1.36 + r.p_offset = endian::swap(t.p_offset); 1.37 + r.p_vaddr = endian::swap(t.p_vaddr); 1.38 + r.p_paddr = endian::swap(t.p_paddr); 1.39 + r.p_filesz = endian::swap(t.p_filesz); 1.40 + r.p_memsz = endian::swap(t.p_memsz); 1.41 + r.p_flags = endian::swap(t.p_flags); 1.42 + r.p_align = endian::swap(t.p_align); 1.43 +} 1.44 + 1.45 +template <class endian, typename R, typename T> 1.46 +void Elf_Shdr_Traits::swap(T &t, R &r) 1.47 +{ 1.48 + r.sh_name = endian::swap(t.sh_name); 1.49 + r.sh_type = endian::swap(t.sh_type); 1.50 + r.sh_flags = endian::swap(t.sh_flags); 1.51 + r.sh_addr = endian::swap(t.sh_addr); 1.52 + r.sh_offset = endian::swap(t.sh_offset); 1.53 + r.sh_size = endian::swap(t.sh_size); 1.54 + r.sh_link = endian::swap(t.sh_link); 1.55 + r.sh_info = endian::swap(t.sh_info); 1.56 + r.sh_addralign = endian::swap(t.sh_addralign); 1.57 + r.sh_entsize = endian::swap(t.sh_entsize); 1.58 +} 1.59 + 1.60 +template <class endian, typename R, typename T> 1.61 +void Elf_Dyn_Traits::swap(T &t, R &r) 1.62 +{ 1.63 + r.d_tag = endian::swap(t.d_tag); 1.64 + r.d_un.d_val = endian::swap(t.d_un.d_val); 1.65 +} 1.66 + 1.67 +template <class endian, typename R, typename T> 1.68 +void Elf_Sym_Traits::swap(T &t, R &r) 1.69 +{ 1.70 + r.st_name = endian::swap(t.st_name); 1.71 + r.st_value = endian::swap(t.st_value); 1.72 + r.st_size = endian::swap(t.st_size); 1.73 + r.st_info = t.st_info; 1.74 + r.st_other = t.st_other; 1.75 + r.st_shndx = endian::swap(t.st_shndx); 1.76 +} 1.77 + 1.78 +template <class endian> 1.79 +struct _Rel_info { 1.80 + static inline void swap(Elf32_Word &t, Elf32_Word &r) { r = endian::swap(t); } 1.81 + static inline void swap(Elf64_Xword &t, Elf64_Xword &r) { r = endian::swap(t); } 1.82 + static inline void swap(Elf64_Xword &t, Elf32_Word &r) { 1.83 + r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t))); 1.84 + } 1.85 + static inline void swap(Elf32_Word &t, Elf64_Xword &r) { 1.86 + r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t))); 1.87 + } 1.88 +}; 1.89 + 1.90 +template <class endian, typename R, typename T> 1.91 +void Elf_Rel_Traits::swap(T &t, R &r) 1.92 +{ 1.93 + r.r_offset = endian::swap(t.r_offset); 1.94 + _Rel_info<endian>::swap(t.r_info, r.r_info); 1.95 +} 1.96 + 1.97 +template <class endian, typename R, typename T> 1.98 +void Elf_Rela_Traits::swap(T &t, R &r) 1.99 +{ 1.100 + r.r_offset = endian::swap(t.r_offset); 1.101 + _Rel_info<endian>::swap(t.r_info, r.r_info); 1.102 + r.r_addend = endian::swap(t.r_addend); 1.103 +} 1.104 + 1.105 +static const Elf32_Shdr null32_section = 1.106 + { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 }; 1.107 + 1.108 +Elf_Shdr null_section(null32_section); 1.109 + 1.110 +Elf_Ehdr::Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data) 1.111 +: serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data), 1.112 + ElfSection(null_section, nullptr, nullptr) 1.113 +{ 1.114 + shdr.sh_size = Elf_Ehdr::size(ei_class); 1.115 +} 1.116 + 1.117 +Elf::Elf(std::ifstream &file) 1.118 +{ 1.119 + if (!file.is_open()) 1.120 + throw std::runtime_error("Error opening file"); 1.121 + 1.122 + file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit); 1.123 + // Read ELF magic number and identification information 1.124 + char e_ident[EI_VERSION]; 1.125 + file.seekg(0); 1.126 + file.read(e_ident, sizeof(e_ident)); 1.127 + file.seekg(0); 1.128 + ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]); 1.129 + 1.130 + // ELFOSABI_LINUX is kept unsupported because I haven't looked whether 1.131 + // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing. 1.132 + if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0)) 1.133 + throw std::runtime_error("unsupported ELF ABI"); 1.134 + 1.135 + if (ehdr->e_version != 1) 1.136 + throw std::runtime_error("unsupported ELF version"); 1.137 + 1.138 + // Sanity checks 1.139 + if (ehdr->e_shnum == 0) 1.140 + throw std::runtime_error("sstripped ELF files aren't supported"); 1.141 + 1.142 + if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS])) 1.143 + throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)"); 1.144 + 1.145 + if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS])) 1.146 + throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)"); 1.147 + 1.148 + if (ehdr->e_phnum == 0) { 1.149 + if (ehdr->e_phoff != 0) 1.150 + throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0"); 1.151 + if (ehdr->e_phentsize != 0) 1.152 + throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0"); 1.153 + } else if (ehdr->e_phoff != ehdr->e_ehsize) 1.154 + throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize"); 1.155 + else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS])) 1.156 + throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)"); 1.157 + 1.158 + // Read section headers 1.159 + Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum]; 1.160 + file.seekg(ehdr->e_shoff); 1.161 + for (int i = 0; i < ehdr->e_shnum; i++) 1.162 + shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]); 1.163 + 1.164 + // Sanity check in section header for index 0 1.165 + if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) || 1.166 + (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) || 1.167 + (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) || 1.168 + (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) || 1.169 + (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0)) 1.170 + throw std::runtime_error("Section header for index 0 contains unsupported values"); 1.171 + 1.172 + if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0)) 1.173 + throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0"); 1.174 + 1.175 + // Store these temporarily 1.176 + tmp_shdr = shdr; 1.177 + tmp_file = &file; 1.178 + 1.179 + // Fill sections list 1.180 + sections = new ElfSection *[ehdr->e_shnum]; 1.181 + for (int i = 0; i < ehdr->e_shnum; i++) 1.182 + sections[i] = nullptr; 1.183 + for (int i = 1; i < ehdr->e_shnum; i++) { 1.184 + if (sections[i] != nullptr) 1.185 + continue; 1.186 + getSection(i); 1.187 + } 1.188 + Elf_Shdr s; 1.189 + s.sh_name = 0; 1.190 + s.sh_type = SHT_NULL; 1.191 + s.sh_flags = 0; 1.192 + s.sh_addr = 0; 1.193 + s.sh_offset = ehdr->e_shoff; 1.194 + s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]); 1.195 + s.sh_size = s.sh_entsize * ehdr->e_shnum; 1.196 + s.sh_link = 0; 1.197 + s.sh_info = 0; 1.198 + s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8; 1.199 + shdr_section = new ElfSection(s, nullptr, nullptr); 1.200 + 1.201 + // Fake section for program headers 1.202 + s.sh_offset = ehdr->e_phoff; 1.203 + s.sh_addr = ehdr->e_phoff; 1.204 + s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]); 1.205 + s.sh_size = s.sh_entsize * ehdr->e_phnum; 1.206 + phdr_section = new ElfSection(s, nullptr, nullptr); 1.207 + 1.208 + phdr_section->insertAfter(ehdr, false); 1.209 + 1.210 + sections[1]->insertAfter(phdr_section, false); 1.211 + for (int i = 2; i < ehdr->e_shnum; i++) { 1.212 + // TODO: this should be done in a better way 1.213 + if ((shdr_section->getPrevious() == nullptr) && (shdr[i]->sh_offset > ehdr->e_shoff)) { 1.214 + shdr_section->insertAfter(sections[i - 1], false); 1.215 + sections[i]->insertAfter(shdr_section, false); 1.216 + } else 1.217 + sections[i]->insertAfter(sections[i - 1], false); 1.218 + } 1.219 + if (shdr_section->getPrevious() == nullptr) 1.220 + shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false); 1.221 + 1.222 + tmp_file = nullptr; 1.223 + tmp_shdr = nullptr; 1.224 + for (int i = 0; i < ehdr->e_shnum; i++) 1.225 + delete shdr[i]; 1.226 + delete[] shdr; 1.227 + 1.228 + eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx]; 1.229 + 1.230 + // Skip reading program headers if there aren't any 1.231 + if (ehdr->e_phnum == 0) 1.232 + return; 1.233 + 1.234 + // Read program headers 1.235 + file.seekg(ehdr->e_phoff); 1.236 + for (int i = 0; i < ehdr->e_phnum; i++) { 1.237 + Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]); 1.238 + if (phdr.p_type == PT_LOAD) { 1.239 + // Default alignment for PT_LOAD on x86-64 prevents elfhack from 1.240 + // doing anything useful. However, the system doesn't actually 1.241 + // require such a big alignment, so in order for elfhack to work 1.242 + // efficiently, reduce alignment when it's originally the default 1.243 + // one. 1.244 + if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000)) 1.245 + phdr.p_align = 0x1000; 1.246 + } 1.247 + ElfSegment *segment = new ElfSegment(&phdr); 1.248 + // Some segments aren't entirely filled (if at all) by sections 1.249 + // For those, we use fake sections 1.250 + if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) { 1.251 + // Use a fake section for ehdr and phdr 1.252 + ehdr->getShdr().sh_addr = phdr.p_vaddr; 1.253 + phdr_section->getShdr().sh_addr += phdr.p_vaddr; 1.254 + segment->addSection(ehdr); 1.255 + segment->addSection(phdr_section); 1.256 + } 1.257 + if (phdr.p_type == PT_PHDR) 1.258 + segment->addSection(phdr_section); 1.259 + for (int j = 1; j < ehdr->e_shnum; j++) 1.260 + if (phdr.contains(sections[j])) 1.261 + segment->addSection(sections[j]); 1.262 + // Make sure that our view of segments corresponds to the original 1.263 + // ELF file. 1.264 + assert(segment->getFileSize() == phdr.p_filesz); 1.265 + // gold makes TLS segments end on an aligned virtual address, even 1.266 + // when the underlying section ends before that, while bfd ld 1.267 + // doesn't. It's fine if we don't keep that alignment. 1.268 + unsigned int memsize = segment->getMemSize(); 1.269 + if (phdr.p_type == PT_TLS && memsize != phdr.p_memsz) { 1.270 + unsigned int align = segment->getAlign(); 1.271 + memsize = (memsize + align - 1) & ~(align - 1); 1.272 + } 1.273 + assert(memsize == phdr.p_memsz); 1.274 + segments.push_back(segment); 1.275 + } 1.276 + 1.277 + new (&eh_entry) ElfLocation(ehdr->e_entry, this); 1.278 +} 1.279 + 1.280 +Elf::~Elf() 1.281 +{ 1.282 + for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) 1.283 + delete *seg; 1.284 + delete[] sections; 1.285 + ElfSection *section = ehdr; 1.286 + while (section != nullptr) { 1.287 + ElfSection *next = section->getNext(); 1.288 + delete section; 1.289 + section = next; 1.290 + } 1.291 +} 1.292 + 1.293 +// TODO: This shouldn't fail after inserting sections 1.294 +ElfSection *Elf::getSection(int index) 1.295 +{ 1.296 + if ((index < -1) || (index >= ehdr->e_shnum)) 1.297 + throw std::runtime_error("Section index out of bounds"); 1.298 + if (index == -1) 1.299 + index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number 1.300 + // Special case: the section at index 0 is void 1.301 + if (index == 0) 1.302 + return nullptr; 1.303 + // Infinite recursion guard 1.304 + if (sections[index] == (ElfSection *)this) 1.305 + return nullptr; 1.306 + if (sections[index] == nullptr) { 1.307 + sections[index] = (ElfSection *)this; 1.308 + switch (tmp_shdr[index]->sh_type) { 1.309 + case SHT_DYNAMIC: 1.310 + sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this); 1.311 + break; 1.312 + case SHT_REL: 1.313 + sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this); 1.314 + break; 1.315 + case SHT_RELA: 1.316 + sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this); 1.317 + break; 1.318 + case SHT_DYNSYM: 1.319 + case SHT_SYMTAB: 1.320 + sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this); 1.321 + break; 1.322 + case SHT_STRTAB: 1.323 + sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this); 1.324 + break; 1.325 + default: 1.326 + sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this); 1.327 + } 1.328 + } 1.329 + return sections[index]; 1.330 +} 1.331 + 1.332 +ElfSection *Elf::getSectionAt(unsigned int offset) 1.333 +{ 1.334 + for (int i = 1; i < ehdr->e_shnum; i++) { 1.335 + ElfSection *section = getSection(i); 1.336 + if ((section != nullptr) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) && 1.337 + (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize())) 1.338 + return section; 1.339 + } 1.340 + return nullptr; 1.341 +} 1.342 + 1.343 +ElfSegment *Elf::getSegmentByType(unsigned int type, ElfSegment *last) 1.344 +{ 1.345 + std::vector<ElfSegment *>::iterator seg; 1.346 + if (last) { 1.347 + seg = std::find(segments.begin(), segments.end(), last); 1.348 + ++seg; 1.349 + } else 1.350 + seg = segments.begin(); 1.351 + for (; seg != segments.end(); seg++) 1.352 + if ((*seg)->getType() == type) 1.353 + return *seg; 1.354 + return nullptr; 1.355 +} 1.356 + 1.357 +void Elf::removeSegment(ElfSegment *segment) 1.358 +{ 1.359 + if (!segment) 1.360 + return; 1.361 + std::vector<ElfSegment *>::iterator seg; 1.362 + seg = std::find(segments.begin(), segments.end(), segment); 1.363 + if (seg == segments.end()) 1.364 + return; 1.365 + segment->clear(); 1.366 + segments.erase(seg); 1.367 +} 1.368 + 1.369 +ElfDynamic_Section *Elf::getDynSection() 1.370 +{ 1.371 + for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) 1.372 + if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != nullptr) && 1.373 + (*seg)->getFirstSection()->getType() == SHT_DYNAMIC) 1.374 + return (ElfDynamic_Section *)(*seg)->getFirstSection(); 1.375 + 1.376 + return nullptr; 1.377 +} 1.378 + 1.379 +void Elf::normalize() 1.380 +{ 1.381 + // fixup section headers sh_name; TODO: that should be done by sections 1.382 + // themselves 1.383 + for (ElfSection *section = ehdr; section != nullptr; section = section->getNext()) { 1.384 + if (section->getIndex() == 0) 1.385 + continue; 1.386 + else 1.387 + ehdr->e_shnum = section->getIndex() + 1; 1.388 + section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName()); 1.389 + } 1.390 + ehdr->markDirty(); 1.391 + // Check segments consistency 1.392 + int i = 0; 1.393 + for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) { 1.394 + std::list<ElfSection *>::iterator it = (*seg)->begin(); 1.395 + for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) { 1.396 + if (((*it)->getType() != SHT_NOBITS) && 1.397 + ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) { 1.398 + throw std::runtime_error("Segments inconsistency"); 1.399 + } 1.400 + } 1.401 + } 1.402 + // fixup ehdr before writing 1.403 + if (ehdr->e_phnum != segments.size()) { 1.404 + ehdr->e_phnum = segments.size(); 1.405 + phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]); 1.406 + phdr_section->getNext()->markDirty(); 1.407 + } 1.408 + // fixup shdr before writing 1.409 + if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize()) 1.410 + shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]); 1.411 + ehdr->e_shoff = shdr_section->getOffset(); 1.412 + ehdr->e_entry = eh_entry.getValue(); 1.413 + ehdr->e_shstrndx = eh_shstrndx->getIndex(); 1.414 +} 1.415 + 1.416 +void Elf::write(std::ofstream &file) 1.417 +{ 1.418 + normalize(); 1.419 + for (ElfSection *section = ehdr; 1.420 + section != nullptr; section = section->getNext()) { 1.421 + file.seekp(section->getOffset()); 1.422 + if (section == phdr_section) { 1.423 + for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) { 1.424 + Elf_Phdr phdr; 1.425 + phdr.p_type = (*seg)->getType(); 1.426 + phdr.p_flags = (*seg)->getFlags(); 1.427 + phdr.p_offset = (*seg)->getOffset(); 1.428 + phdr.p_vaddr = (*seg)->getAddr(); 1.429 + phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff(); 1.430 + phdr.p_filesz = (*seg)->getFileSize(); 1.431 + phdr.p_memsz = (*seg)->getMemSize(); 1.432 + phdr.p_align = (*seg)->getAlign(); 1.433 + phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); 1.434 + } 1.435 + } else if (section == shdr_section) { 1.436 + null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); 1.437 + for (ElfSection *sec = ehdr; sec!= nullptr; sec = sec->getNext()) { 1.438 + if (sec->getType() != SHT_NULL) 1.439 + sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); 1.440 + } 1.441 + } else 1.442 + section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]); 1.443 + } 1.444 +} 1.445 + 1.446 +ElfSection::ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent) 1.447 +: shdr(s), 1.448 + link(shdr.sh_link == SHN_UNDEF ? nullptr : parent->getSection(shdr.sh_link)), 1.449 + next(nullptr), previous(nullptr), index(-1) 1.450 +{ 1.451 + if ((file == nullptr) || (shdr.sh_type == SHT_NULL) || (shdr.sh_type == SHT_NOBITS)) 1.452 + data = nullptr; 1.453 + else { 1.454 + data = new char[shdr.sh_size]; 1.455 + int pos = file->tellg(); 1.456 + file->seekg(shdr.sh_offset); 1.457 + file->read(data, shdr.sh_size); 1.458 + file->seekg(pos); 1.459 + } 1.460 + if (shdr.sh_name == 0) 1.461 + name = nullptr; 1.462 + else { 1.463 + ElfStrtab_Section *strtab = (ElfStrtab_Section *) parent->getSection(-1); 1.464 + // Special case (see elfgeneric.cpp): if strtab is nullptr, the 1.465 + // section being created is the strtab. 1.466 + if (strtab == nullptr) 1.467 + name = &data[shdr.sh_name]; 1.468 + else 1.469 + name = strtab->getStr(shdr.sh_name); 1.470 + } 1.471 + // Only SHT_REL/SHT_RELA sections use sh_info to store a section 1.472 + // number. 1.473 + if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA)) 1.474 + info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : nullptr; 1.475 + else 1.476 + info.index = shdr.sh_info; 1.477 +} 1.478 + 1.479 +unsigned int ElfSection::getAddr() 1.480 +{ 1.481 + if (shdr.sh_addr != (Elf32_Word)-1) 1.482 + return shdr.sh_addr; 1.483 + 1.484 + // It should be safe to adjust sh_addr for all allocated sections that 1.485 + // are neither SHT_NOBITS nor SHT_PROGBITS 1.486 + if ((previous != nullptr) && isRelocatable()) { 1.487 + unsigned int addr = previous->getAddr(); 1.488 + if (previous->getType() != SHT_NOBITS) 1.489 + addr += previous->getSize(); 1.490 + 1.491 + if (addr & (getAddrAlign() - 1)) 1.492 + addr = (addr | (getAddrAlign() - 1)) + 1; 1.493 + 1.494 + return (shdr.sh_addr = addr); 1.495 + } 1.496 + return shdr.sh_addr; 1.497 +} 1.498 + 1.499 +unsigned int ElfSection::getOffset() 1.500 +{ 1.501 + if (shdr.sh_offset != (Elf32_Word)-1) 1.502 + return shdr.sh_offset; 1.503 + 1.504 + if (previous == nullptr) 1.505 + return (shdr.sh_offset = 0); 1.506 + 1.507 + unsigned int offset = previous->getOffset(); 1.508 + 1.509 + ElfSegment *ptload = getSegmentByType(PT_LOAD); 1.510 + ElfSegment *prev_ptload = previous->getSegmentByType(PT_LOAD); 1.511 + 1.512 + if (ptload && (ptload == prev_ptload)) { 1.513 + offset += getAddr() - previous->getAddr(); 1.514 + return (shdr.sh_offset = offset); 1.515 + } 1.516 + 1.517 + if (previous->getType() != SHT_NOBITS) 1.518 + offset += previous->getSize(); 1.519 + 1.520 + Elf32_Word align = 0x1000; 1.521 + for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) 1.522 + align = std::max(align, (*seg)->getAlign()); 1.523 + 1.524 + Elf32_Word mask = align - 1; 1.525 + // SHF_TLS is used for .tbss which is some kind of special case. 1.526 + if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) { 1.527 + if ((getAddr() & mask) < (offset & mask)) 1.528 + offset = (offset | mask) + (getAddr() & mask) + 1; 1.529 + else 1.530 + offset = (offset & ~mask) + (getAddr() & mask); 1.531 + } 1.532 + if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1))) 1.533 + offset = (offset | (getAddrAlign() - 1)) + 1; 1.534 + 1.535 + // Two subsequent sections can't be mapped in the same page in memory 1.536 + // if they aren't in the same 4K block on disk. 1.537 + if ((getType() != SHT_NOBITS) && getAddr()) { 1.538 + if (((offset >> 12) != (previous->getOffset() >> 12)) && 1.539 + ((getAddr() >> 12) == (previous->getAddr() >> 12))) 1.540 + throw std::runtime_error("Moving section would require overlapping segments"); 1.541 + } 1.542 + 1.543 + return (shdr.sh_offset = offset); 1.544 +} 1.545 + 1.546 +int ElfSection::getIndex() 1.547 +{ 1.548 + if (index != -1) 1.549 + return index; 1.550 + if (getType() == SHT_NULL) 1.551 + return (index = 0); 1.552 + ElfSection *reference; 1.553 + for (reference = previous; (reference != nullptr) && (reference->getType() == SHT_NULL); reference = reference->getPrevious()); 1.554 + if (reference == nullptr) 1.555 + return (index = 1); 1.556 + return (index = reference->getIndex() + 1); 1.557 +} 1.558 + 1.559 +Elf_Shdr &ElfSection::getShdr() 1.560 +{ 1.561 + getOffset(); 1.562 + if (shdr.sh_link == (Elf32_Word)-1) 1.563 + shdr.sh_link = getLink() ? getLink()->getIndex() : 0; 1.564 + if (shdr.sh_info == (Elf32_Word)-1) 1.565 + shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) ? 1.566 + (getInfo().section ? getInfo().section->getIndex() : 0) : 1.567 + getInfo().index; 1.568 + 1.569 + return shdr; 1.570 +} 1.571 + 1.572 +ElfSegment::ElfSegment(Elf_Phdr *phdr) 1.573 +: type(phdr->p_type), v_p_diff(phdr->p_paddr - phdr->p_vaddr), 1.574 + flags(phdr->p_flags), align(phdr->p_align), vaddr(phdr->p_vaddr), 1.575 + filesz(phdr->p_filesz), memsz(phdr->p_memsz) {} 1.576 + 1.577 +void ElfSegment::addSection(ElfSection *section) 1.578 +{ 1.579 + // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack 1.580 + assert(!((type == PT_GNU_RELRO) && (section->isRelocatable()))); 1.581 + 1.582 + //TODO: Check overlapping sections 1.583 + std::list<ElfSection *>::iterator i; 1.584 + for (i = sections.begin(); i != sections.end(); ++i) 1.585 + if ((*i)->getAddr() > section->getAddr()) 1.586 + break; 1.587 + sections.insert(i, section); 1.588 + section->addToSegment(this); 1.589 +} 1.590 + 1.591 +void ElfSegment::removeSection(ElfSection *section) 1.592 +{ 1.593 + sections.remove(section); 1.594 + section->removeFromSegment(this); 1.595 +} 1.596 + 1.597 +unsigned int ElfSegment::getFileSize() 1.598 +{ 1.599 + if (type == PT_GNU_RELRO || isElfHackFillerSegment()) 1.600 + return filesz; 1.601 + 1.602 + if (sections.empty()) 1.603 + return 0; 1.604 + // Search the last section that is not SHT_NOBITS 1.605 + std::list<ElfSection *>::reverse_iterator i; 1.606 + for (i = sections.rbegin(); (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i); 1.607 + // All sections are SHT_NOBITS 1.608 + if (i == sections.rend()) 1.609 + return 0; 1.610 + 1.611 + unsigned int end = (*i)->getAddr() + (*i)->getSize(); 1.612 + 1.613 + return end - sections.front()->getAddr(); 1.614 +} 1.615 + 1.616 +unsigned int ElfSegment::getMemSize() 1.617 +{ 1.618 + if (type == PT_GNU_RELRO || isElfHackFillerSegment()) 1.619 + return memsz; 1.620 + 1.621 + if (sections.empty()) 1.622 + return 0; 1.623 + 1.624 + unsigned int end = sections.back()->getAddr() + sections.back()->getSize(); 1.625 + 1.626 + return end - sections.front()->getAddr(); 1.627 +} 1.628 + 1.629 +unsigned int ElfSegment::getOffset() 1.630 +{ 1.631 + if ((type == PT_GNU_RELRO) && !sections.empty() && 1.632 + (sections.front()->getAddr() != vaddr)) 1.633 + throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start"); 1.634 + 1.635 + // Neither bionic nor glibc linkers seem to like when the offset of that segment is 0 1.636 + if (isElfHackFillerSegment()) 1.637 + return vaddr; 1.638 + 1.639 + return sections.empty() ? 0 : sections.front()->getOffset(); 1.640 +} 1.641 + 1.642 +unsigned int ElfSegment::getAddr() 1.643 +{ 1.644 + if ((type == PT_GNU_RELRO) && !sections.empty() && 1.645 + (sections.front()->getAddr() != vaddr)) 1.646 + throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start"); 1.647 + 1.648 + if (isElfHackFillerSegment()) 1.649 + return vaddr; 1.650 + 1.651 + return sections.empty() ? 0 : sections.front()->getAddr(); 1.652 +} 1.653 + 1.654 +void ElfSegment::clear() 1.655 +{ 1.656 + for (std::list<ElfSection *>::iterator i = sections.begin(); i != sections.end(); ++i) 1.657 + (*i)->removeFromSegment(this); 1.658 + sections.clear(); 1.659 +} 1.660 + 1.661 +ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag) 1.662 +{ 1.663 + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) 1.664 + if (dyns[i].tag == tag) 1.665 + return dyns[i].value; 1.666 + 1.667 + return nullptr; 1.668 +} 1.669 + 1.670 +ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag) 1.671 +{ 1.672 + ElfValue *value = getValueForType(tag); 1.673 + return value ? value->getSection() : nullptr; 1.674 +} 1.675 + 1.676 +bool ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val) 1.677 +{ 1.678 + unsigned int i; 1.679 + unsigned int shnum = shdr.sh_size / shdr.sh_entsize; 1.680 + for (i = 0; (i < shnum) && (dyns[i].tag != DT_NULL); i++) 1.681 + if (dyns[i].tag == tag) { 1.682 + delete dyns[i].value; 1.683 + dyns[i].value = val; 1.684 + return true; 1.685 + } 1.686 + // If we get here, this means we didn't match for the given tag 1.687 + // Most of the time, there are a few DT_NULL entries, that we can 1.688 + // use to add our value, but if we are on the last entry, we can't. 1.689 + if (i >= shnum - 1) 1.690 + return false; 1.691 + 1.692 + dyns[i].tag = tag; 1.693 + dyns[i].value = val; 1.694 + return true; 1.695 +} 1.696 + 1.697 +ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent) 1.698 +: ElfSection(s, file, parent) 1.699 +{ 1.700 + int pos = file->tellg(); 1.701 + dyns.resize(s.sh_size / s.sh_entsize); 1.702 + file->seekg(shdr.sh_offset); 1.703 + // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts 1.704 + // for .rel.dyn size) 1.705 + for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) { 1.706 + Elf_Dyn dyn(*file, parent->getClass(), parent->getData()); 1.707 + dyns[i].tag = dyn.d_tag; 1.708 + switch (dyn.d_tag) { 1.709 + case DT_NULL: 1.710 + case DT_SYMBOLIC: 1.711 + case DT_TEXTREL: 1.712 + case DT_BIND_NOW: 1.713 + dyns[i].value = new ElfValue(); 1.714 + break; 1.715 + case DT_NEEDED: 1.716 + case DT_SONAME: 1.717 + case DT_RPATH: 1.718 + case DT_PLTREL: 1.719 + case DT_RUNPATH: 1.720 + case DT_FLAGS: 1.721 + case DT_RELACOUNT: 1.722 + case DT_RELCOUNT: 1.723 + case DT_VERDEFNUM: 1.724 + case DT_VERNEEDNUM: 1.725 + dyns[i].value = new ElfPlainValue(dyn.d_un.d_val); 1.726 + break; 1.727 + case DT_PLTGOT: 1.728 + case DT_HASH: 1.729 + case DT_STRTAB: 1.730 + case DT_SYMTAB: 1.731 + case DT_RELA: 1.732 + case DT_INIT: 1.733 + case DT_FINI: 1.734 + case DT_REL: 1.735 + case DT_JMPREL: 1.736 + case DT_INIT_ARRAY: 1.737 + case DT_FINI_ARRAY: 1.738 + case DT_GNU_HASH: 1.739 + case DT_VERSYM: 1.740 + case DT_VERNEED: 1.741 + case DT_VERDEF: 1.742 + dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent); 1.743 + break; 1.744 + default: 1.745 + dyns[i].value = nullptr; 1.746 + } 1.747 + } 1.748 + // Another loop to get the section sizes 1.749 + for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) 1.750 + switch (dyns[i].tag) { 1.751 + case DT_PLTRELSZ: 1.752 + dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL)); 1.753 + break; 1.754 + case DT_RELASZ: 1.755 + dyns[i].value = new ElfSize(getSectionForType(DT_RELA)); 1.756 + break; 1.757 + case DT_STRSZ: 1.758 + dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB)); 1.759 + break; 1.760 + case DT_RELSZ: 1.761 + dyns[i].value = new ElfSize(getSectionForType(DT_REL)); 1.762 + break; 1.763 + case DT_INIT_ARRAYSZ: 1.764 + dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY)); 1.765 + break; 1.766 + case DT_FINI_ARRAYSZ: 1.767 + dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY)); 1.768 + break; 1.769 + case DT_RELAENT: 1.770 + dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA)); 1.771 + break; 1.772 + case DT_SYMENT: 1.773 + dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB)); 1.774 + break; 1.775 + case DT_RELENT: 1.776 + dyns[i].value = new ElfEntSize(getSectionForType(DT_REL)); 1.777 + break; 1.778 + } 1.779 + 1.780 + file->seekg(pos); 1.781 +} 1.782 + 1.783 +ElfDynamic_Section::~ElfDynamic_Section() 1.784 +{ 1.785 + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) 1.786 + delete dyns[i].value; 1.787 +} 1.788 + 1.789 +void ElfDynamic_Section::serialize(std::ofstream &file, char ei_class, char ei_data) 1.790 +{ 1.791 + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 1.792 + Elf_Dyn dyn; 1.793 + dyn.d_tag = dyns[i].tag; 1.794 + dyn.d_un.d_val = (dyns[i].value != nullptr) ? dyns[i].value->getValue() : 0; 1.795 + dyn.serialize(file, ei_class, ei_data); 1.796 + } 1.797 +} 1.798 + 1.799 +ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent) 1.800 +: ElfSection(s, file, parent) 1.801 +{ 1.802 + int pos = file->tellg(); 1.803 + syms.resize(s.sh_size / s.sh_entsize); 1.804 + ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink(); 1.805 + file->seekg(shdr.sh_offset); 1.806 + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 1.807 + Elf_Sym sym(*file, parent->getClass(), parent->getData()); 1.808 + syms[i].name = strtab->getStr(sym.st_name); 1.809 + syms[i].info = sym.st_info; 1.810 + syms[i].other = sym.st_other; 1.811 + ElfSection *section = (sym.st_shndx == SHN_ABS) ? nullptr : parent->getSection(sym.st_shndx); 1.812 + new (&syms[i].value) ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE); 1.813 + syms[i].size = sym.st_size; 1.814 + syms[i].defined = (sym.st_shndx != SHN_UNDEF); 1.815 + } 1.816 + file->seekg(pos); 1.817 +} 1.818 + 1.819 +void 1.820 +ElfSymtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data) 1.821 +{ 1.822 + ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink(); 1.823 + for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) { 1.824 + Elf_Sym sym; 1.825 + sym.st_name = strtab->getStrIndex(syms[i].name); 1.826 + sym.st_info = syms[i].info; 1.827 + sym.st_other = syms[i].other; 1.828 + sym.st_value = syms[i].value.getValue(); 1.829 + ElfSection *section = syms[i].value.getSection(); 1.830 + if (syms[i].defined) 1.831 + sym.st_shndx = section ? section->getIndex() : SHN_ABS; 1.832 + else 1.833 + sym.st_shndx = SHN_UNDEF; 1.834 + sym.st_size = syms[i].size; 1.835 + sym.serialize(file, ei_class, ei_data); 1.836 + } 1.837 +} 1.838 + 1.839 +Elf_SymValue * 1.840 +ElfSymtab_Section::lookup(const char *name, unsigned int type_filter) 1.841 +{ 1.842 + for (std::vector<Elf_SymValue>::iterator sym = syms.begin(); 1.843 + sym != syms.end(); sym++) { 1.844 + if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) && 1.845 + (strcmp(sym->name, name) == 0)) { 1.846 + return &*sym; 1.847 + } 1.848 + } 1.849 + return nullptr; 1.850 +} 1.851 + 1.852 +const char * 1.853 +ElfStrtab_Section::getStr(unsigned int index) 1.854 +{ 1.855 + for (std::vector<table_storage>::iterator t = table.begin(); 1.856 + t != table.end(); t++) { 1.857 + if (index < t->used) 1.858 + return t->buf + index; 1.859 + index -= t->used; 1.860 + } 1.861 + assert(1 == 0); 1.862 + return nullptr; 1.863 +} 1.864 + 1.865 +const char * 1.866 +ElfStrtab_Section::getStr(const char *string) 1.867 +{ 1.868 + if (string == nullptr) 1.869 + return nullptr; 1.870 + 1.871 + // If the given string is within the section, return it 1.872 + for (std::vector<table_storage>::iterator t = table.begin(); 1.873 + t != table.end(); t++) 1.874 + if ((string >= t->buf) && (string < t->buf + t->used)) 1.875 + return string; 1.876 + 1.877 + // TODO: should scan in the section to find an existing string 1.878 + 1.879 + // If not, we need to allocate the string in the section 1.880 + size_t len = strlen(string) + 1; 1.881 + 1.882 + if (table.back().size - table.back().used < len) 1.883 + table.resize(table.size() + 1); 1.884 + 1.885 + char *alloc_str = table.back().buf + table.back().used; 1.886 + memcpy(alloc_str, string, len); 1.887 + table.back().used += len; 1.888 + 1.889 + shdr.sh_size += len; 1.890 + markDirty(); 1.891 + 1.892 + return alloc_str; 1.893 +} 1.894 + 1.895 +unsigned int 1.896 +ElfStrtab_Section::getStrIndex(const char *string) 1.897 +{ 1.898 + if (string == nullptr) 1.899 + return 0; 1.900 + 1.901 + unsigned int index = 0; 1.902 + string = getStr(string); 1.903 + for (std::vector<table_storage>::iterator t = table.begin(); 1.904 + t != table.end(); t++) { 1.905 + if ((string >= t->buf) && (string < t->buf + t->used)) 1.906 + return index + (string - t->buf); 1.907 + index += t->used; 1.908 + } 1.909 + 1.910 + assert(1 == 0); 1.911 + return 0; 1.912 +} 1.913 + 1.914 +void 1.915 +ElfStrtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data) 1.916 +{ 1.917 + file.seekp(getOffset()); 1.918 + for (std::vector<table_storage>::iterator t = table.begin(); 1.919 + t != table.end(); t++) 1.920 + file.write(t->buf, t->used); 1.921 +}