elf_fixup.cc revision 700a402244a1a423da4f3ba8032459f4b65fa18f
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "elf_fixup.h" 18 19#include <inttypes.h> 20#include <memory> 21 22#include "base/logging.h" 23#include "base/stringprintf.h" 24#include "elf_file.h" 25#include "elf_writer.h" 26 27namespace art { 28 29static const bool DEBUG_FIXUP = false; 30 31bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) { 32 std::string error_msg; 33 std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg)); 34 CHECK(elf_file.get() != nullptr) << error_msg; 35 36 // Lookup "oatdata" symbol address. 37 Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get()); 38 Elf32_Off base_address = oat_data_begin - oatdata_address; 39 40 if (!FixupDynamic(*elf_file.get(), base_address)) { 41 LOG(WARNING) << "Failed fo fixup .dynamic in " << file->GetPath(); 42 return false; 43 } 44 if (!FixupSectionHeaders(*elf_file.get(), base_address)) { 45 LOG(WARNING) << "Failed fo fixup section headers in " << file->GetPath(); 46 return false; 47 } 48 if (!FixupProgramHeaders(*elf_file.get(), base_address)) { 49 LOG(WARNING) << "Failed fo fixup program headers in " << file->GetPath(); 50 return false; 51 } 52 if (!FixupSymbols(*elf_file.get(), base_address, true)) { 53 LOG(WARNING) << "Failed fo fixup .dynsym in " << file->GetPath(); 54 return false; 55 } 56 if (!FixupSymbols(*elf_file.get(), base_address, false)) { 57 LOG(WARNING) << "Failed fo fixup .symtab in " << file->GetPath(); 58 return false; 59 } 60 if (!FixupRelocations(*elf_file.get(), base_address)) { 61 LOG(WARNING) << "Failed fo fixup .rel.dyn in " << file->GetPath(); 62 return false; 63 } 64 return true; 65} 66 67 68bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) { 69 for (Elf32_Word i = 0; i < elf_file.GetDynamicNum(); i++) { 70 Elf32_Dyn& elf_dyn = elf_file.GetDynamic(i); 71 Elf32_Word d_tag = elf_dyn.d_tag; 72 bool elf_dyn_needs_fixup = false; 73 switch (d_tag) { 74 // case 1: well known d_tag values that imply Elf32_Dyn.d_un contains an address in d_ptr 75 case DT_PLTGOT: 76 case DT_HASH: 77 case DT_STRTAB: 78 case DT_SYMTAB: 79 case DT_RELA: 80 case DT_INIT: 81 case DT_FINI: 82 case DT_REL: 83 case DT_DEBUG: 84 case DT_JMPREL: { 85 elf_dyn_needs_fixup = true; 86 break; 87 } 88 // d_val or ignored values 89 case DT_NULL: 90 case DT_NEEDED: 91 case DT_PLTRELSZ: 92 case DT_RELASZ: 93 case DT_RELAENT: 94 case DT_STRSZ: 95 case DT_SYMENT: 96 case DT_SONAME: 97 case DT_RPATH: 98 case DT_SYMBOLIC: 99 case DT_RELSZ: 100 case DT_RELENT: 101 case DT_PLTREL: 102 case DT_TEXTREL: 103 case DT_BIND_NOW: 104 case DT_INIT_ARRAYSZ: 105 case DT_FINI_ARRAYSZ: 106 case DT_RUNPATH: 107 case DT_FLAGS: { 108 break; 109 } 110 // boundary values that should not be used 111 case DT_ENCODING: 112 case DT_LOOS: 113 case DT_HIOS: 114 case DT_LOPROC: 115 case DT_HIPROC: { 116 LOG(FATAL) << "Illegal d_tag value 0x" << std::hex << d_tag; 117 break; 118 } 119 default: { 120 // case 2: "regular" DT_* ranges where even d_tag values imply an address in d_ptr 121 if ((DT_ENCODING < d_tag && d_tag < DT_LOOS) 122 || (DT_LOOS < d_tag && d_tag < DT_HIOS) 123 || (DT_LOPROC < d_tag && d_tag < DT_HIPROC)) { 124 // Special case for MIPS which breaks the regular rules between DT_LOPROC and DT_HIPROC 125 if (elf_file.GetHeader().e_machine == EM_MIPS) { 126 switch (d_tag) { 127 case DT_MIPS_RLD_VERSION: 128 case DT_MIPS_TIME_STAMP: 129 case DT_MIPS_ICHECKSUM: 130 case DT_MIPS_IVERSION: 131 case DT_MIPS_FLAGS: 132 case DT_MIPS_LOCAL_GOTNO: 133 case DT_MIPS_CONFLICTNO: 134 case DT_MIPS_LIBLISTNO: 135 case DT_MIPS_SYMTABNO: 136 case DT_MIPS_UNREFEXTNO: 137 case DT_MIPS_GOTSYM: 138 case DT_MIPS_HIPAGENO: { 139 break; 140 } 141 case DT_MIPS_BASE_ADDRESS: 142 case DT_MIPS_CONFLICT: 143 case DT_MIPS_LIBLIST: 144 case DT_MIPS_RLD_MAP: { 145 elf_dyn_needs_fixup = true; 146 break; 147 } 148 default: { 149 LOG(FATAL) << "Unknown MIPS d_tag value 0x" << std::hex << d_tag; 150 break; 151 } 152 } 153 } else if ((elf_dyn.d_tag % 2) == 0) { 154 elf_dyn_needs_fixup = true; 155 } 156 } else { 157 LOG(FATAL) << "Unknown d_tag value 0x" << std::hex << d_tag; 158 } 159 break; 160 } 161 } 162 if (elf_dyn_needs_fixup) { 163 uint32_t d_ptr = elf_dyn.d_un.d_ptr; 164 if (DEBUG_FIXUP) { 165 LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR, 166 elf_file.GetFile().GetPath().c_str(), i, 167 d_ptr, d_ptr + base_address); 168 } 169 d_ptr += base_address; 170 elf_dyn.d_un.d_ptr = d_ptr; 171 } 172 } 173 return true; 174} 175 176bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) { 177 for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) { 178 Elf32_Shdr& sh = elf_file.GetSectionHeader(i); 179 // 0 implies that the section will not exist in the memory of the process 180 if (sh.sh_addr == 0) { 181 continue; 182 } 183 if (DEBUG_FIXUP) { 184 LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR, 185 elf_file.GetFile().GetPath().c_str(), i, 186 sh.sh_addr, sh.sh_addr + base_address); 187 } 188 sh.sh_addr += base_address; 189 } 190 return true; 191} 192 193bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) { 194 // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now. 195 for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) { 196 Elf32_Phdr& ph = elf_file.GetProgramHeader(i); 197 CHECK_EQ(ph.p_vaddr, ph.p_paddr) << elf_file.GetFile().GetPath() << " i=" << i; 198 CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1)))) 199 << elf_file.GetFile().GetPath() << " i=" << i; 200 if (DEBUG_FIXUP) { 201 LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR, 202 elf_file.GetFile().GetPath().c_str(), i, 203 ph.p_vaddr, ph.p_vaddr + base_address); 204 } 205 ph.p_vaddr += base_address; 206 ph.p_paddr += base_address; 207 CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1)))) 208 << elf_file.GetFile().GetPath() << " i=" << i; 209 } 210 return true; 211} 212 213bool ElfFixup::FixupSymbols(ElfFile& elf_file, uintptr_t base_address, bool dynamic) { 214 Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB; 215 // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile 216 Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type); 217 if (symbol_section == NULL) { 218 // file is missing optional .symtab 219 CHECK(!dynamic) << elf_file.GetFile().GetPath(); 220 return true; 221 } 222 for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) { 223 Elf32_Sym& symbol = elf_file.GetSymbol(section_type, i); 224 if (symbol.st_value != 0) { 225 if (DEBUG_FIXUP) { 226 LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR, 227 elf_file.GetFile().GetPath().c_str(), i, 228 symbol.st_value, symbol.st_value + base_address); 229 } 230 symbol.st_value += base_address; 231 } 232 } 233 return true; 234} 235 236bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) { 237 for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) { 238 Elf32_Shdr& sh = elf_file.GetSectionHeader(i); 239 if (sh.sh_type == SHT_REL) { 240 for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) { 241 Elf32_Rel& rel = elf_file.GetRel(sh, i); 242 if (DEBUG_FIXUP) { 243 LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR, 244 elf_file.GetFile().GetPath().c_str(), i, 245 rel.r_offset, rel.r_offset + base_address); 246 } 247 rel.r_offset += base_address; 248 } 249 } else if (sh.sh_type == SHT_RELA) { 250 for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) { 251 Elf32_Rela& rela = elf_file.GetRela(sh, i); 252 if (DEBUG_FIXUP) { 253 LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR, 254 elf_file.GetFile().GetPath().c_str(), i, 255 rela.r_offset, rela.r_offset + base_address); 256 } 257 rela.r_offset += base_address; 258 } 259 } 260 } 261 return true; 262} 263 264} // namespace art 265