Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: base/android/linker/crazy_linker/src/crazy_linker_elf_relocator.cpp

Issue 23717023: Android: Add chrome-specific dynamic linker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rename library Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crazy_linker_elf_relocator.h"
6
7 #include <errno.h>
8 #include <string.h>
9
10 #include "crazy_linker_debug.h"
11 #include "crazy_linker_util.h"
12 #include "linker_phdr.h"
13
14 // Set to 1 to print debug traces during relocations.
15 // Default is 0 since there are _tons_ of them.
16 #define DEBUG_RELOCATIONS 0
17
18 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__)
19 #define RLOG_ERRNO(...) LOG_IF_ERRNO(DEBUG_RELOCATIONS, __VA_ARGS__)
20
21
22 #ifndef DF_SYMBOLIC
23 #define DF_SYMBOLIC 2
24 #endif
25
26 #ifndef DF_TEXTREL
27 #define DF_TEXTREL 4
28 #endif
29
30 #ifndef DT_FLAGS
31 #define DT_FLAGS 30
32 #endif
33
34 // Processor-specific relocation types supported by the linker.
35 #ifdef __arm__
36
37 #define R_ARM_ABS32 2
38 #define R_ARM_REL32 3
39 #define R_ARM_GLOB_DAT 21
40 #define R_ARM_JUMP_SLOT 22
41 #define R_ARM_COPY 20
42 #define R_ARM_RELATIVE 23
43
44 #endif // __arm__
45
46 #ifdef __i386__
47
48 /* i386 relocations */
49 #define R_386_32 1
50 #define R_386_PC32 2
51 #define R_386_GLOB_DAT 6
52 #define R_386_JMP_SLOT 7
53 #define R_386_RELATIVE 8
54
55 #endif // __i386__
56
57 namespace crazy {
58
59 namespace {
60
61 // List of known relocation types the relocator knows about.
62 enum RelocationType {
63 RELOCATION_TYPE_UNKNOWN = 0,
64 RELOCATION_TYPE_ABSOLUTE = 1,
65 RELOCATION_TYPE_RELATIVE = 2,
66 RELOCATION_TYPE_PC_RELATIVE = 3,
67 RELOCATION_TYPE_COPY = 4,
68 };
69
70 // Convert an ELF relocation type info a RelocationType value.
71 RelocationType GetRelocationType(unsigned r_type) {
72 switch (r_type) {
73 #ifdef __arm__
74 case R_ARM_JUMP_SLOT:
75 case R_ARM_GLOB_DAT:
76 case R_ARM_ABS32:
77 return RELOCATION_TYPE_ABSOLUTE;
78
79 case R_ARM_REL32:
80 case R_ARM_RELATIVE:
81 return RELOCATION_TYPE_RELATIVE;
82
83 case R_ARM_COPY:
84 return RELOCATION_TYPE_COPY;
85 #endif
86
87 #ifdef __i386__
88 case R_386_JMP_SLOT:
89 case R_386_GLOB_DAT:
90 case R_386_32:
91 return RELOCATION_TYPE_ABSOLUTE;
92
93 case R_386_RELATIVE:
94 return RELOCATION_TYPE_RELATIVE;
95
96 case R_386_PC32:
97 return RELOCATION_TYPE_PC_RELATIVE;
98 #endif
99
100 #ifdef __mips__
101 case R_MIPS_REL32:
102 return RELOCATION_TYPE_RELATIVE;
103 #endif
104
105 default:
106 return RELOCATION_TYPE_UNKNOWN;
107 }
108 }
109
110 } // namespace
111
112 ElfRelocator::ElfRelocator() {
113 }
114
115 bool ElfRelocator::Init(const ELF::Phdr* phdr,
116 size_t phdr_count,
117 size_t load_bias,
118 const ELF::Dyn* dyn,
119 size_t count,
120 Error* error) {
121 phdr_ = phdr;
122 phdr_count_ = phdr_count;
123 load_bias_ = load_bias;
124
125 LOG("%s: phdr=%p phdr_count=%d load_bias=%x dyn_table=%p dyn_count=%d\n",
126 __FUNCTION__, phdr, (int)phdr_count, (int)load_bias, dyn, (int)count);
127
128 for ( ; count > 0; dyn++, count-- ) {
129 // Be paranoid.
130 if (dyn->d_tag == DT_NULL)
131 break;
132
133 ELF::Addr dyn_value = dyn->d_un.d_val;
134 uintptr_t dyn_addr = load_bias_ + dyn->d_un.d_ptr;
135
136 switch (dyn->d_tag) {
137 case DT_PLTREL:
138 // NOTE: Yes, there is nothing to record here, the content of
139 // plt_rel_ will come from DT_JMPREL instead.
140 RLOG(" DT_PLTREL");
141 if (dyn_value != DT_REL) {
142 *error = "Unsupported DT_RELA entry in dynamic section";
143 return false;
144 }
145 break;
146 case DT_JMPREL:
147 RLOG(" DT_JMPREL addr=%p\n", dyn_addr);
148 plt_rel_ = reinterpret_cast<ELF::Rel*>(dyn_addr);
149 break;
150 case DT_PLTRELSZ:
151 plt_rel_count_ = dyn_value / sizeof(ELF::Rel);
152 RLOG(" DT_PLTRELSZ size=%d count=%d\n", dyn_value, plt_rel_count_);
153 break;
154 case DT_REL:
155 RLOG(" DT_REL addr=%p\n", dyn_addr);
156 rel_ = reinterpret_cast<ELF::Rel*>(dyn_addr);
157 break;
158 case DT_RELSZ:
159 rel_count_ = dyn_value / sizeof(ELF::Rel);
160 RLOG(" DT_RELSZ size=%d count=%d\n", dyn_value, rel_count_);
161 break;
162 case DT_PLTGOT:
163 // NOTE from original linker:
164 // Save this in case we decide to do lazy binding. We don't yet.
165 RLOG(" DT_PLTGOT addr=%p\n", dyn_addr);
166 plt_got_ = reinterpret_cast<uintptr_t*>(dyn_addr);
167 break;
168 case DT_RELA:
169 *error = "Unsupported DT_RELA entry in dynamic section";
170 return false;
171 case DT_TEXTREL:
172 LOG(" DT_TEXTREL\n");
173 has_text_relocations_ = true;
174 break;
175 case DT_SYMBOLIC:
176 RLOG(" DT_SYMBOLIC\n");
177 has_symbolic_ = true;
178 break;
179 case DT_FLAGS:
180 if (dyn_value & DF_TEXTREL)
181 has_text_relocations_ = true;
182 if (dyn_value & DF_SYMBOLIC)
183 has_symbolic_ = true;
184 RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n",
185 has_text_relocations_ ? "true" : "false",
186 has_symbolic_ ? "true" : "false");
187 break;
188 #if defined(__mips__)
189 case DT_MIPS_SYMTABNO:
190 RLOG(" DT_MIPS_SYMTABNO value=%d\n", dyn_value);
191 mips_symtabno_ = dyn_value;
192 break;
193
194 case DT_MIPS_LOCAL_GOTNO:
195 RLOG(" DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value);
196 mips_local_gotno_ = dyn_value;
197 break;
198
199 case DT_MIPS_GOTSYM:
200 RLOG(" DT_MIPS_GOTSYM value=%d\n", dyn_value);
201 mips_gotsym_ = dyn_value;
202 break;
203 #endif
204 default:
205 RLOG(" UNKNOWN tag=%d value=%08x addr=%p\n",
206 dyn->d_tag, dyn_value, (void*)dyn_addr);
207 ;
208 }
209 }
210 LOG("%s: Done!\n", __FUNCTION__);
211 return true;
212 }
213
214 bool ElfRelocator::Apply(SymbolResolver* resolver,
215 const char* string_table,
216 const ELF::Sym* symbol_table,
217 Error* error) {
218 resolver_ = resolver;
219 string_table_ = string_table;
220 symbol_table_ = symbol_table;
221
222 LOG("%s: string_table=%p sybol_table=%p\n", __FUNCTION__,
223 string_table, symbol_table);
224
225 if (has_text_relocations_) {
226 if (phdr_table_unprotect_segments(phdr_,
227 phdr_count_,
228 load_bias_) < 0) {
229 error->Format("Can't unprotect loadable segments: %s",
230 strerror(errno));
231 return false;
232 }
233 }
234
235 if (!ApplyRelocs(plt_rel_, plt_rel_count_, error) ||
236 !ApplyRelocs(rel_, rel_count_, error)) {
237 return false;
238 }
239
240 #ifdef __mips__
241 if (!RelocateMipsGot(error))
242 return false;
243 #endif
244
245 if (has_text_relocations_) {
246 if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) {
247 error->Format("Can't protect loadable segments: %s",
248 strerror(errno));
249 return false;
250 }
251 }
252
253 // Turn on GNU RELRO protection now.
254 LOG("%s: Enabling GNU RELRO protection\n", __FUNCTION__);
255
256 if (phdr_table_protect_gnu_relro(phdr_, phdr_count_, load_bias_) < 0) {
257 error->Format("Can't enable GNU RELRO protection: %s",
258 strerror(errno));
259 return false;
260 }
261
262 LOG("%s: Done\n", __FUNCTION__);
263 return true;
264 }
265
266 bool ElfRelocator::ApplyRelocs(const ELF::Rel* rel,
267 size_t rel_count,
268 Error* error) {
269 RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count);
270
271 if (!rel)
272 return true;
273
274 for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) {
275 unsigned rel_type = ELF_R_TYPE(rel->r_info);
276 unsigned rel_symbol = ELF_R_SYM(rel->r_info);
277
278 ELF::Addr sym_addr = 0;
279 ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_);
280 LOG(" %d/%d reloc=%p offset=%p type=%d symbol=%d\n",
281 rel_n + 1, rel_count, reloc, rel->r_offset, rel_type, rel_symbol);
282
283 if (rel_type == 0)
284 continue;
285
286 RelocationType r_type = GetRelocationType(rel_type);
287 bool CRAZY_UNUSED resolved = false;
288
289 // If this is a symbolic relocation, compute the symbol's address.
290 if (rel_symbol != 0) {
291 const char* sym_name =
292 string_table_ + symbol_table_[rel_symbol].st_name;
293 RLOG(" symbol name='%s'\n", sym_name);
294 void* address = resolver_->Lookup(sym_name);
295 if (address) {
296 // The symbol was found, so compute its address.
297 RLOG("%s: symbol %s resolved to %p\n", __FUNCTION__,
298 sym_name, address);
299 resolved = true;
300 sym_addr = reinterpret_cast<ELF::Addr>(address);
301 } else {
302 // The symbol was not found. Normally this is an error except
303 // if this is a weak reference.
304 if (ELF_ST_BIND(symbol_table_[rel_symbol].st_info) != STB_WEAK) {
305 error->Format("Could not find symbol '%s'", sym_name);
306 return false;
307 }
308
309 resolved = true;
310 RLOG("%s: weak reference to unresolved symbol %s\n",
311 __FUNCTION__, sym_name);
312
313 // IHI0044C AAELF 4.5.1.1:
314 // Libraries are not searched to resolve weak references.
315 // It is not an error for a weak reference to remain
316 // unsatisfied.
317 //
318 // During linking, the value of an undefined weak reference is:
319 // - Zero if the relocation type is absolute
320 // - The address of the place if the relocation is pc-relative
321 // - The address of nominal base address if the relocation
322 // type is base-relative.
323 RelocationType r = GetRelocationType(rel_type);
324 if (r == RELOCATION_TYPE_ABSOLUTE || r == RELOCATION_TYPE_RELATIVE)
325 sym_addr = 0;
326 else if (r == RELOCATION_TYPE_PC_RELATIVE)
327 sym_addr = reloc;
328 else {
329 error->Format(
330 "Invalid weak relocation type (%d) for unknown symbol '%s'",
331 r_type, sym_name);
332 return false;
333 }
334 }
335 }
336
337 // Apply the relocation.
338 ELF::Addr* target = reinterpret_cast<ELF::Addr*>(reloc);
339 switch (rel_type) {
340 #ifdef __arm__
341 case R_ARM_JUMP_SLOT:
342 RLOG(" R_ARM_JUMP_SLOT target=%p addr=%p\n", target, sym_addr);
343 *target = sym_addr;
344 break;
345
346 case R_ARM_GLOB_DAT:
347 RLOG(" R_ARM_GLOB_DAT target=%p addr=%p\n", target, sym_addr);
348 *target = sym_addr;
349 break;
350
351 case R_ARM_ABS32:
352 RLOG(" R_ARM_ABS32 target=%p (%p) addr=%p\n", target, *target, sym_addr );
353 *target += sym_addr;
354 break;
355
356 case R_ARM_REL32:
357 RLOG(" R_ARM_REL32 target=%p (%p) addr=%p offset=%p\n", target, *target , sym_addr, rel->r_offset);
358 *target += sym_addr - rel->r_offset;
359 break;
360
361 case R_ARM_RELATIVE:
362 RLOG(" R_ARM_RELATIVE target=%p (%p) bias=%p\n", target, *target, load_ bias_);
363 if (rel_symbol) {
364 *error = "Invalid relative relocation with symbol";
365 return false;
366 }
367 *target += load_bias_;
368 break;
369
370 case R_ARM_COPY:
371 // NOTE: These relocations are forbidden in shared libraries.
372 // The Android linker has special code to deal with this, which
373 // is not needed here.
374 RLOG(" R_ARM_COPY\n");
375 *error = "Invalid R_ARM_COPY relocation in shared library";
376 return false;
377 #endif // __arm__
378
379 #ifdef __i386__
380 case R_386_JMP_SLOT:
381 *target = sym_addr;
382 break;
383
384 case R_386_GLOB_DAT:
385 *target = sym_addr;
386 break;
387
388 case R_386_RELATIVE:
389 if (rel_symbol) {
390 *error = "Invalid relative relocation with symbol";
391 return false;
392 }
393 *target += load_bias_;
394 break;
395
396 case R_386_32:
397 *target += sym_addr;
398 break;
399
400 case R_386_PC32:
401 *target += (sym_addr - reloc);
402 break;
403 #endif // __i386__
404
405 #ifdef __mips__
406 case R_MIPS_REL32:
407 if (resolved)
408 *target += sym_addr;
409 else
410 *target += load_bias_;
411 break;
412 #endif // __mips__
413
414 default:
415 error->Format("Invalid relocation type (%d)", rel_type);
416 return false;
417 }
418 }
419
420 return true;
421 }
422
423 #ifdef __mips__
424 bool ElfRelocator::RelocateMipsGot(Error* error) {
425 // TODO(digit): Implement this.
426 *error = "Relocating the MIPS GOT is not implemented";
427 return false;
428 }
429 #endif // __mips__
430
431 } // namespace crazy
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698