blob: 6fd4a7302a601a3494d4288035ad9296535c5ac3 [file] [log] [blame]
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -07001/*
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
Nicolas Geoffray50cfe742014-02-19 13:27:42 +000019#include <inttypes.h>
20
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -070021#include "base/logging.h"
22#include "base/stringprintf.h"
23#include "elf_file.h"
24#include "elf_writer.h"
25#include "UniquePtr.h"
26
27namespace art {
28
29static const bool DEBUG_FIXUP = false;
30
31bool ElfFixup::Fixup(File* file, uintptr_t oat_data_begin) {
Ian Rogers8d31bbd2013-10-13 10:44:14 -070032 std::string error_msg;
33 UniquePtr<ElfFile> elf_file(ElfFile::Open(file, true, false, &error_msg));
34 CHECK(elf_file.get() != nullptr) << error_msg;
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -070035
36 // Lookup "oatdata" symbol address.
Nicolas Geoffray50cfe742014-02-19 13:27:42 +000037 Elf32_Addr oatdata_address = ElfWriter::GetOatDataAddress(elf_file.get());
38 Elf32_Off base_address = oat_data_begin - oatdata_address;
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -070039
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
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -070067
68bool ElfFixup::FixupDynamic(ElfFile& elf_file, uintptr_t base_address) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +000069 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;
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -070072 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
Nicolas Geoffray50cfe742014-02-19 13:27:42 +000075 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: {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -070085 elf_dyn_needs_fixup = true;
86 break;
87 }
88 // d_val or ignored values
Nicolas Geoffray50cfe742014-02-19 13:27:42 +000089 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: {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700108 break;
109 }
110 // boundary values that should not be used
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000111 case DT_ENCODING:
112 case DT_LOOS:
113 case DT_HIOS:
114 case DT_LOPROC:
115 case DT_HIPROC: {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700116 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
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000121 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)) {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700124 // Special case for MIPS which breaks the regular rules between DT_LOPROC and DT_HIPROC
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000125 if (elf_file.GetHeader().e_machine == EM_MIPS) {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700126 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) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800165 LOG(INFO) << StringPrintf("In %s moving Elf32_Dyn[%d] from 0x%08x to 0x%08" PRIxPTR,
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700166 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) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000177 for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
178 Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700179 // 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) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800184 LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR,
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700185 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.
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000195 for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
196 Elf32_Phdr& ph = elf_file.GetProgramHeader(i);
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700197 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) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800201 LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR,
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700202 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) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000214 Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700215 // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000216 Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700217 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++) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000223 Elf32_Sym& symbol = elf_file.GetSymbol(section_type, i);
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700224 if (symbol.st_value != 0) {
225 if (DEBUG_FIXUP) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800226 LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR,
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700227 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) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000237 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) {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700240 for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000241 Elf32_Rel& rel = elf_file.GetRel(sh, i);
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700242 if (DEBUG_FIXUP) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800243 LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR,
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700244 elf_file.GetFile().GetPath().c_str(), i,
245 rel.r_offset, rel.r_offset + base_address);
246 }
247 rel.r_offset += base_address;
248 }
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000249 } else if (sh.sh_type == SHT_RELA) {
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700250 for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) {
Nicolas Geoffray50cfe742014-02-19 13:27:42 +0000251 Elf32_Rela& rela = elf_file.GetRela(sh, i);
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700252 if (DEBUG_FIXUP) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800253 LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR,
Brian Carlstrom6a47b9d2013-05-17 10:58:25 -0700254 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