OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "crazy_linker_elf_relocations.h" | 5 #include "crazy_linker_elf_relocations.h" |
6 | 6 |
7 #include <assert.h> | |
7 #include <errno.h> | 8 #include <errno.h> |
8 | 9 |
9 #include "crazy_linker_debug.h" | 10 #include "crazy_linker_debug.h" |
10 #include "crazy_linker_elf_symbols.h" | 11 #include "crazy_linker_elf_symbols.h" |
11 #include "crazy_linker_elf_view.h" | 12 #include "crazy_linker_elf_view.h" |
12 #include "crazy_linker_error.h" | 13 #include "crazy_linker_error.h" |
13 #include "crazy_linker_leb128.h" | 14 #include "crazy_linker_leb128.h" |
14 #include "crazy_linker_system.h" | 15 #include "crazy_linker_system.h" |
15 #include "crazy_linker_util.h" | 16 #include "crazy_linker_util.h" |
16 #include "linker_phdr.h" | 17 #include "linker_phdr.h" |
17 | 18 |
18 #define DEBUG_RELOCATIONS 0 | 19 #define DEBUG_RELOCATIONS 0 |
19 | 20 |
20 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__) | 21 #define RLOG(...) LOG_IF(DEBUG_RELOCATIONS, __VA_ARGS__) |
21 #define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__) | 22 #define RLOG_ERRNO(...) LOG_ERRNO_IF(DEBUG_RELOCATIONS, __VA_ARGS__) |
22 | 23 |
23 #ifndef DF_SYMBOLIC | 24 #ifndef DF_SYMBOLIC |
24 #define DF_SYMBOLIC 2 | 25 #define DF_SYMBOLIC 2 |
25 #endif | 26 #endif |
26 | 27 |
27 #ifndef DF_TEXTREL | 28 #ifndef DF_TEXTREL |
28 #define DF_TEXTREL 4 | 29 #define DF_TEXTREL 4 |
29 #endif | 30 #endif |
30 | 31 |
31 #ifndef DT_FLAGS | 32 #ifndef DT_FLAGS |
32 #define DT_FLAGS 30 | 33 #define DT_FLAGS 30 |
33 #endif | 34 #endif |
34 | 35 |
36 // Extension dynamic tags for Android packed relocations. | |
37 #ifndef DT_LOOS | |
38 #define DT_LOOS 0x6000000d | |
39 #endif | |
40 #ifndef DT_ANDROID_REL | |
41 #define DT_ANDROID_REL (DT_LOOS + 2) | |
42 #endif | |
43 #ifndef DT_ANDROID_RELSZ | |
44 #define DT_ANDROID_RELSZ (DT_LOOS + 3) | |
45 #endif | |
46 #ifndef DT_ANDROID_RELA | |
47 #define DT_ANDROID_RELA (DT_LOOS + 4) | |
48 #endif | |
49 #ifndef DT_ANDROID_RELASZ | |
50 #define DT_ANDROID_RELASZ (DT_LOOS + 5) | |
51 #endif | |
52 | |
35 // Processor-specific relocation types supported by the linker. | 53 // Processor-specific relocation types supported by the linker. |
36 #ifdef __arm__ | 54 #ifdef __arm__ |
37 | 55 |
38 /* arm32 relocations */ | 56 /* arm32 relocations */ |
39 #define R_ARM_ABS32 2 | 57 #define R_ARM_ABS32 2 |
40 #define R_ARM_REL32 3 | 58 #define R_ARM_REL32 3 |
41 #define R_ARM_GLOB_DAT 21 | 59 #define R_ARM_GLOB_DAT 21 |
42 #define R_ARM_JUMP_SLOT 22 | 60 #define R_ARM_JUMP_SLOT 22 |
43 #define R_ARM_COPY 20 | 61 #define R_ARM_COPY 20 |
44 #define R_ARM_RELATIVE 23 | 62 #define R_ARM_RELATIVE 23 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
221 if (relocations_size_) { | 239 if (relocations_size_) { |
222 *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section"; | 240 *error = "Unsupported DT_RELASZ/DT_RELSZ combination in dyn section"; |
223 return false; | 241 return false; |
224 } | 242 } |
225 relocations_size_ = dyn_value; | 243 relocations_size_ = dyn_value; |
226 if (tag == DT_RELASZ) | 244 if (tag == DT_RELASZ) |
227 has_rela_relocations = true; | 245 has_rela_relocations = true; |
228 else | 246 else |
229 has_rel_relocations = true; | 247 has_rel_relocations = true; |
230 break; | 248 break; |
249 case DT_ANDROID_RELA: | |
250 case DT_ANDROID_REL: | |
251 RLOG(" %s addr=%p\n", | |
252 (tag == DT_ANDROID_RELA) ? "DT_ANDROID_RELA" : "DT_ANDROID_REL", | |
253 dyn_addr); | |
254 if (android_relocations_) { | |
255 *error = "Unsupported DT_ANDROID_RELA/DT_ANDROID_REL " | |
256 "combination in dynamic section"; | |
257 return false; | |
258 } | |
259 android_relocations_ = reinterpret_cast<uint8_t*>(dyn_addr); | |
260 if (tag == DT_ANDROID_RELA) | |
261 has_rela_relocations = true; | |
262 else | |
263 has_rel_relocations = true; | |
264 break; | |
265 case DT_ANDROID_RELASZ: | |
266 case DT_ANDROID_RELSZ: | |
267 RLOG(" %s size=%d\n", | |
268 (tag == DT_ANDROID_RELASZ) | |
269 ? "DT_ANDROID_RELASZ" : "DT_ANDROID_RELSZ", dyn_addr); | |
270 if (android_relocations_size_) { | |
271 *error = "Unsupported DT_ANDROID_RELASZ/DT_ANDROID_RELSZ " | |
272 "combination in dyn section"; | |
273 return false; | |
274 } | |
275 android_relocations_size_ = dyn_value; | |
276 if (tag == DT_ANDROID_RELASZ) | |
277 has_rela_relocations = true; | |
278 else | |
279 has_rel_relocations = true; | |
280 break; | |
231 case DT_PLTGOT: | 281 case DT_PLTGOT: |
232 // Only used on MIPS currently. Could also be used on other platforms | 282 // Only used on MIPS currently. Could also be used on other platforms |
233 // when lazy binding (i.e. RTLD_LAZY) is implemented. | 283 // when lazy binding (i.e. RTLD_LAZY) is implemented. |
234 RLOG(" DT_PLTGOT addr=%p\n", dyn_addr); | 284 RLOG(" DT_PLTGOT addr=%p\n", dyn_addr); |
235 plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr); | 285 plt_got_ = reinterpret_cast<ELF::Addr*>(dyn_addr); |
236 break; | 286 break; |
237 case DT_TEXTREL: | 287 case DT_TEXTREL: |
238 RLOG(" DT_TEXTREL\n"); | 288 RLOG(" DT_TEXTREL\n"); |
239 has_text_relocations_ = true; | 289 has_text_relocations_ = true; |
240 break; | 290 break; |
241 case DT_SYMBOLIC: | 291 case DT_SYMBOLIC: |
242 RLOG(" DT_SYMBOLIC\n"); | 292 RLOG(" DT_SYMBOLIC\n"); |
243 has_symbolic_ = true; | 293 has_symbolic_ = true; |
244 break; | 294 break; |
245 case DT_FLAGS: | 295 case DT_FLAGS: |
246 if (dyn_value & DF_TEXTREL) | 296 if (dyn_value & DF_TEXTREL) |
247 has_text_relocations_ = true; | 297 has_text_relocations_ = true; |
248 if (dyn_value & DF_SYMBOLIC) | 298 if (dyn_value & DF_SYMBOLIC) |
249 has_symbolic_ = true; | 299 has_symbolic_ = true; |
250 RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", | 300 RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", |
251 has_text_relocations_ ? "true" : "false", | 301 has_text_relocations_ ? "true" : "false", |
252 has_symbolic_ ? "true" : "false"); | 302 has_symbolic_ ? "true" : "false"); |
253 break; | 303 break; |
254 #if defined(__mips__) | 304 #if defined(__mips__) |
255 case DT_MIPS_SYMTABNO: | 305 case DT_MIPS_SYMTABNO: |
256 RLOG(" DT_MIPS_SYMTABNO value=%d\n", dyn_value); | 306 RLOG(" DT_MIPS_SYMTABNO value=%d\n", dyn_value); |
257 mips_symtab_count_ = dyn_value; | 307 mips_symtab_count_ = dyn_value; |
258 break; | 308 break; |
259 | 309 |
260 case DT_MIPS_LOCAL_GOTNO: | 310 case DT_MIPS_LOCAL_GOTNO: |
261 RLOG(" DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value); | 311 RLOG(" DT_MIPS_LOCAL_GOTNO value=%d\n", dyn_value); |
262 mips_local_got_count_ = dyn_value; | 312 mips_local_got_count_ = dyn_value; |
263 break; | 313 break; |
264 | 314 |
265 case DT_MIPS_GOTSYM: | 315 case DT_MIPS_GOTSYM: |
266 RLOG(" DT_MIPS_GOTSYM value=%d\n", dyn_value); | 316 RLOG(" DT_MIPS_GOTSYM value=%d\n", dyn_value); |
267 mips_gotsym_ = dyn_value; | 317 mips_gotsym_ = dyn_value; |
268 break; | 318 break; |
269 #endif | 319 #endif |
270 default: | 320 default: |
271 ; | 321 ; |
272 } | 322 } |
273 } | 323 } |
274 | 324 |
275 if (has_rel_relocations && has_rela_relocations) { | 325 if (has_rel_relocations && has_rela_relocations) { |
276 *error = "Combining DT_REL and DT_RELA is not currently supported"; | 326 *error = "Combining relocations with and without addends is not " |
327 "currently supported"; | |
277 return false; | 328 return false; |
278 } | 329 } |
279 | 330 |
280 // If DT_PLTREL did not explicitly assign relocations_type_, set it | 331 // If DT_PLTREL did not explicitly assign relocations_type_, set it |
281 // here based on the type of relocations found. | 332 // here based on the type of relocations found. |
282 if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) { | 333 if (relocations_type_ != DT_REL && relocations_type_ != DT_RELA) { |
283 if (has_rel_relocations) | 334 if (has_rel_relocations) |
284 relocations_type_ = DT_REL; | 335 relocations_type_ = DT_REL; |
285 else if (has_rela_relocations) | 336 else if (has_rela_relocations) |
286 relocations_type_ = DT_RELA; | 337 relocations_type_ = DT_RELA; |
287 } | 338 } |
288 | 339 |
289 if (relocations_type_ == DT_REL && has_rela_relocations) { | 340 if (relocations_type_ == DT_REL && has_rela_relocations) { |
290 *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL"; | 341 *error = "Found relocations with addends in dyn section, " |
342 "but DT_PLTREL is DT_REL"; | |
291 return false; | 343 return false; |
292 } | 344 } |
293 if (relocations_type_ == DT_RELA && has_rel_relocations) { | 345 if (relocations_type_ == DT_RELA && has_rel_relocations) { |
294 *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA"; | 346 *error = "Found relocations without addends in dyn section, " |
347 "but DT_PLTREL is DT_RELA"; | |
295 return false; | 348 return false; |
296 } | 349 } |
297 | 350 |
298 return true; | 351 return true; |
299 } | 352 } |
300 | 353 |
301 bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, | 354 bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, |
302 SymbolResolver* resolver, | 355 SymbolResolver* resolver, |
303 Error* error) { | 356 Error* error) { |
304 LOG("%s: Enter\n", __FUNCTION__); | 357 LOG("%s: Enter\n", __FUNCTION__); |
305 | 358 |
306 if (has_text_relocations_) { | 359 if (has_text_relocations_) { |
307 if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) { | 360 if (phdr_table_unprotect_segments(phdr_, phdr_count_, load_bias_) < 0) { |
308 error->Format("Can't unprotect loadable segments: %s", strerror(errno)); | 361 error->Format("Can't unprotect loadable segments: %s", strerror(errno)); |
309 return false; | 362 return false; |
310 } | 363 } |
311 } | 364 } |
312 | 365 |
313 #if defined(__arm__) || defined(__aarch64__) | 366 if (!ApplyAndroidRelocations(symbols, resolver, error)) |
314 if (!ApplyPackedRelocations(error)) | |
315 return false; | 367 return false; |
316 #endif | |
317 | 368 |
318 if (relocations_type_ == DT_REL) { | 369 if (relocations_type_ == DT_REL) { |
319 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), | 370 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), |
320 relocations_size_ / sizeof(ELF::Rel), | 371 relocations_size_ / sizeof(ELF::Rel), |
321 symbols, | 372 symbols, |
322 resolver, | 373 resolver, |
323 error)) | 374 error)) |
324 return false; | 375 return false; |
325 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_), | 376 if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(plt_relocations_), |
326 plt_relocations_size_ / sizeof(ELF::Rel), | 377 plt_relocations_size_ / sizeof(ELF::Rel), |
(...skipping 27 matching lines...) Expand all Loading... | |
354 if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) { | 405 if (phdr_table_protect_segments(phdr_, phdr_count_, load_bias_) < 0) { |
355 error->Format("Can't reprotect loadable segments: %s", strerror(errno)); | 406 error->Format("Can't reprotect loadable segments: %s", strerror(errno)); |
356 return false; | 407 return false; |
357 } | 408 } |
358 } | 409 } |
359 | 410 |
360 LOG("%s: Done\n", __FUNCTION__); | 411 LOG("%s: Done\n", __FUNCTION__); |
361 return true; | 412 return true; |
362 } | 413 } |
363 | 414 |
364 #if defined(__arm__) || defined(__aarch64__) | 415 // Helper class for Android packed relocations. Encapsulates the packing |
416 // flags used by Android for packed relocation groups. | |
417 class AndroidPackedRelocationGroupFlags { | |
418 public: | |
419 explicit AndroidPackedRelocationGroupFlags(size_t flags) : flags_(flags) { } | |
365 | 420 |
366 void ElfRelocations::RegisterPackedRelocations(uint8_t* packed_relocations) { | 421 bool is_relocation_grouped_by_info() const { |
367 packed_relocations_ = packed_relocations; | 422 return hasFlag(RELOCATION_GROUPED_BY_INFO_FLAG); |
368 } | 423 } |
369 | 424 bool is_relocation_grouped_by_offset_delta() const { |
370 bool ElfRelocations::ApplyPackedRel(const uint8_t* packed_relocations, | 425 return hasFlag(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG); |
371 Error* error) { | 426 } |
372 Leb128Decoder decoder(packed_relocations); | 427 bool is_relocation_grouped_by_addend() const { |
373 | 428 return hasFlag(RELOCATION_GROUPED_BY_ADDEND_FLAG); |
374 // Find the count of pairs and the start address. | 429 } |
375 size_t pairs = decoder.Dequeue(); | 430 bool is_relocation_group_has_addend() const { |
376 const ELF::Addr start_address = decoder.Dequeue(); | 431 return hasFlag(RELOCATION_GROUP_HAS_ADDEND_FLAG); |
377 | |
378 // Emit initial relative relocation. | |
379 ELF::Rel relocation; | |
380 relocation.r_offset = start_address; | |
381 relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE); | |
382 const ELF::Addr sym_addr = 0; | |
383 const bool resolved = false; | |
384 if (!ApplyRelReloc(&relocation, sym_addr, resolved, error)) | |
385 return false; | |
386 | |
387 size_t unpacked_count = 1; | |
388 | |
389 // Emit relocations for each count-delta pair. | |
390 while (pairs) { | |
391 size_t count = decoder.Dequeue(); | |
392 const size_t delta = decoder.Dequeue(); | |
393 | |
394 // Emit count relative relocations with delta offset. | |
395 while (count) { | |
396 relocation.r_offset += delta; | |
397 if (!ApplyRelReloc(&relocation, sym_addr, resolved, error)) | |
398 return false; | |
399 unpacked_count++; | |
400 count--; | |
401 } | |
402 pairs--; | |
403 } | 432 } |
404 | 433 |
405 RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count); | 434 private: |
435 bool hasFlag(size_t flag) const { return (flags_ & flag) != 0; } | |
436 | |
437 static const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1 << 0; | |
438 static const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 1 << 1; | |
439 static const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 1 << 2; | |
440 static const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 1 << 3; | |
441 | |
442 const size_t flags_; | |
443 }; | |
444 | |
445 bool ElfRelocations::ForEachAndroidRelocation(RelocationHandler handler, | |
446 void* opaque) { | |
447 // Skip over the "APU2" or "APS2" signature. | |
448 const uint8_t* data_start = android_relocations_ + 4; | |
449 const size_t data_size = android_relocations_size_ - 4; | |
450 | |
451 // Create the appropriate type of LEB128 decoder, and wrap it inside a | |
452 // ScopedPtr for convenience. | |
453 Leb128Decoder* decoder; | |
454 if (android_relocations_[2] == 'U') | |
455 decoder = new Uleb128Decoder(data_start, data_size); | |
456 else | |
457 decoder = new Sleb128Decoder(data_start, data_size); | |
rmcilroy
2015/04/13 10:36:10
nit - add a DCHECK that android_relocations_[2] ==
simonb (inactive)
2015/04/28 14:39:41
Gone -- the android packer no longer generates uns
| |
458 ScopedPtr<Leb128Decoder> scoped_decoder(decoder); | |
459 | |
460 // Unpacking into a relocation with addend, both for REL and RELA, is | |
461 // convenient at this point. If REL, the handler needs to take care of | |
462 // any conversion before use. | |
463 ELF::Rela relocation; | |
464 memset(&relocation, 0, sizeof(relocation)); | |
465 | |
466 // Read the relocation count and initial offset. | |
467 const size_t relocation_count = decoder->pop_front(); | |
468 relocation.r_offset = decoder->pop_front(); | |
469 | |
470 LOG("%s: relocation_count=%d, initial r_offset=%p\n", | |
471 __FUNCTION__, | |
472 relocation_count, | |
473 relocation.r_offset); | |
474 | |
475 size_t relocations_handled = 0; | |
476 while (relocations_handled < relocation_count) { | |
477 // Read the start of the group header to obtain its size and flags. | |
478 const size_t group_size = decoder->pop_front(); | |
479 AndroidPackedRelocationGroupFlags group_flags(decoder->pop_front()); | |
rmcilroy
2015/04/13 10:36:10
Maybe we could just package up the different group
simonb (inactive)
2015/04/28 14:39:41
I'd like to keep this code close to that of the an
rmcilroy
2015/05/01 14:15:22
Ok, SGTM.
| |
480 | |
481 // Read other group header fields, depending on the flags read above. | |
482 size_t group_r_offset_delta = 0; | |
483 if (group_flags.is_relocation_grouped_by_offset_delta()) | |
484 group_r_offset_delta = decoder->pop_front(); | |
485 | |
486 if (group_flags.is_relocation_grouped_by_info()) | |
487 relocation.r_info = decoder->pop_front(); | |
488 | |
489 if (group_flags.is_relocation_group_has_addend() && | |
490 group_flags.is_relocation_grouped_by_addend()) | |
491 relocation.r_addend += decoder->pop_front(); | |
492 else if (!group_flags.is_relocation_group_has_addend()) | |
493 relocation.r_addend = 0; | |
494 | |
495 // Expand the group into individual relocations. | |
496 for (size_t group_index = 0; group_index < group_size; group_index++) { | |
497 if (group_flags.is_relocation_grouped_by_offset_delta()) | |
498 relocation.r_offset += group_r_offset_delta; | |
499 else | |
500 relocation.r_offset += decoder->pop_front(); | |
501 | |
502 if (!group_flags.is_relocation_grouped_by_info()) | |
503 relocation.r_info = decoder->pop_front(); | |
504 | |
505 if (group_flags.is_relocation_group_has_addend() && | |
506 !group_flags.is_relocation_grouped_by_addend()) | |
507 relocation.r_addend += decoder->pop_front(); | |
rmcilroy
2015/04/13 10:36:10
If you do the suggestion above then the AndroidRel
simonb (inactive)
2015/04/28 14:39:41
Acknowledged.
| |
508 | |
509 // Pass the relocation to the supplied handler function. If the handler | |
510 // returns false we view this as failure and return false to our caller. | |
511 if (!handler(this, &relocation, opaque)) { | |
512 LOG("%s: failed handling relocation %d\n", | |
513 __FUNCTION__, | |
514 relocations_handled); | |
515 return false; | |
516 } | |
517 | |
518 relocations_handled++; | |
519 } | |
520 } | |
521 | |
522 LOG("%s: relocations_handled=%d\n", __FUNCTION__, relocations_handled); | |
406 return true; | 523 return true; |
407 } | 524 } |
408 | 525 |
409 bool ElfRelocations::ApplyPackedRela(const uint8_t* packed_relocations, | 526 namespace { |
rmcilroy
2015/04/13 10:36:10
Could we just make these private static functions
simonb (inactive)
2015/04/28 14:39:41
We could. Not sure what it would buy us though.
rmcilroy
2015/05/01 14:15:21
It just seems strange to have a mix of private fun
| |
410 Error* error) { | |
411 Sleb128Decoder decoder(packed_relocations); | |
412 | 527 |
413 // Find the count of pairs. | 528 // Validate the Android packed relocations signature. |
414 size_t pairs = decoder.Dequeue(); | 529 bool IsValidAndroidPackedRelocations(const uint8_t* android_relocations, |
530 size_t android_relocations_size) { | |
531 if (android_relocations_size < 4) | |
532 return false; | |
415 | 533 |
416 ELF::Addr offset = 0; | 534 // Check for an initial APU2 or APS2 Android packed relocations header. |
417 ELF::Sxword addend = 0; | 535 return (android_relocations[0] == 'A' && |
536 android_relocations[1] == 'P' && | |
537 (android_relocations[2] == 'U' || android_relocations[2] == 'S') && | |
538 android_relocations[3] == '2'); | |
539 } | |
418 | 540 |
419 const ELF::Addr sym_addr = 0; | 541 // Narrow a Rela to its equivalent Rel. The r_addend field in the input |
420 const bool resolved = false; | 542 // Rela must be zero. |
543 void ConvertRelaToRel(const ELF::Rela* rela, ELF::Rel* rel) { | |
544 assert(rela->r_addend == 0); | |
545 rel->r_offset = rela->r_offset; | |
546 rel->r_info = rela->r_info; | |
547 } | |
421 | 548 |
422 size_t unpacked_count = 0; | 549 } // namespace |
423 | 550 |
424 // Emit relocations for each deltas pair. | 551 // Args for ApplyAndroidRelocation handler function. |
425 while (pairs) { | 552 struct ApplyAndroidRelocationArgs { |
426 offset += decoder.Dequeue(); | 553 ELF::Addr relocations_type; |
427 addend += decoder.Dequeue(); | 554 const ElfSymbols* symbols; |
555 ElfRelocations::SymbolResolver* resolver; | |
556 Error* error; | |
557 }; | |
428 | 558 |
429 ELF::Rela relocation; | 559 // Static ForEachAndroidRelocation() handler. |
430 relocation.r_offset = offset; | 560 bool ElfRelocations::ApplyAndroidRelocation(ElfRelocations* relocations, |
431 relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE); | 561 const ELF::Rela* relocation, |
432 relocation.r_addend = addend; | 562 void* opaque) { |
433 if (!ApplyRelaReloc(&relocation, sym_addr, resolved, error)) | 563 // Unpack args from opaque. |
434 return false; | 564 ApplyAndroidRelocationArgs* args = |
435 unpacked_count++; | 565 reinterpret_cast<ApplyAndroidRelocationArgs*>(opaque); |
436 pairs--; | 566 const ELF::Addr relocations_type = args->relocations_type; |
567 const ElfSymbols* symbols = args->symbols; | |
568 ElfRelocations::SymbolResolver* resolver = args->resolver; | |
569 Error* error = args->error; | |
570 | |
571 // For REL relocations, convert from RELA to REL and apply the conversion. | |
572 // For RELA relocations, apply RELA directly. | |
573 if (relocations_type == DT_REL) { | |
574 ELF::Rel converted; | |
575 ConvertRelaToRel(relocation, &converted); | |
576 return relocations->ApplyRelReloc(&converted, symbols, resolver, error); | |
437 } | 577 } |
438 | 578 |
439 RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count); | 579 if (relocations_type == DT_RELA) |
580 return relocations->ApplyRelaReloc(relocation, symbols, resolver, error); | |
581 | |
440 return true; | 582 return true; |
rmcilroy
2015/04/13 10:36:10
Are non DT_REL / DT_RELA relocations allowed to go
simonb (inactive)
2015/04/28 14:39:41
Relocations are either DT_REL or DT_RELA, but cann
rmcilroy
2015/05/01 14:15:22
I see, that's fine.
| |
441 } | 583 } |
442 | 584 |
443 bool ElfRelocations::ApplyPackedRelocations(Error* error) { | 585 bool ElfRelocations::ApplyAndroidRelocations(const ElfSymbols* symbols, |
444 if (!packed_relocations_) | 586 SymbolResolver* resolver, |
587 Error* error) { | |
588 if (!android_relocations_) | |
445 return true; | 589 return true; |
446 | 590 |
447 // Check for an initial APR1 header, packed relocations. | 591 if (!IsValidAndroidPackedRelocations(android_relocations_, |
448 if (packed_relocations_[0] == 'A' && | 592 android_relocations_size_)) |
449 packed_relocations_[1] == 'P' && | 593 return false; |
450 packed_relocations_[2] == 'R' && | |
451 packed_relocations_[3] == '1') { | |
452 return ApplyPackedRel(packed_relocations_ + 4, error); | |
453 } | |
454 | 594 |
455 // Check for an initial APA1 header, packed relocations with addend. | 595 ApplyAndroidRelocationArgs args; |
456 if (packed_relocations_[0] == 'A' && | 596 args.relocations_type = relocations_type_; |
457 packed_relocations_[1] == 'P' && | 597 args.symbols = symbols; |
458 packed_relocations_[2] == 'A' && | 598 args.resolver = resolver; |
459 packed_relocations_[3] == '1') { | 599 args.error = error; |
460 return ApplyPackedRela(packed_relocations_ + 4, error); | 600 return ForEachAndroidRelocation(&ApplyAndroidRelocation, &args); |
461 } | 601 } |
462 | 602 |
463 error->Format("Bad packed relocations ident, expected APR1 or APA1"); | 603 bool ElfRelocations::ApplyResolvedRelaReloc(const ELF::Rela* rela, |
464 return false; | 604 ELF::Addr sym_addr, |
465 } | 605 bool resolved CRAZY_UNUSED, |
466 #endif // __arm__ || __aarch64__ | 606 Error* error) { |
467 | |
468 bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, | |
469 ELF::Addr sym_addr, | |
470 bool resolved CRAZY_UNUSED, | |
471 Error* error) { | |
472 const ELF::Word rela_type = ELF_R_TYPE(rela->r_info); | 607 const ELF::Word rela_type = ELF_R_TYPE(rela->r_info); |
473 const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info); | 608 const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info); |
474 const ELF::Sword CRAZY_UNUSED addend = rela->r_addend; | 609 const ELF::Sword CRAZY_UNUSED addend = rela->r_addend; |
475 | 610 |
476 const ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); | 611 const ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); |
477 | 612 |
478 RLOG(" rela reloc=%p offset=%p type=%d addend=%p\n", | 613 RLOG(" rela reloc=%p offset=%p type=%d addend=%p\n", |
479 reloc, | 614 reloc, |
480 rela->r_offset, | 615 rela->r_offset, |
481 rela_type, | 616 rela_type, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
553 #endif // __x86_64__ | 688 #endif // __x86_64__ |
554 | 689 |
555 default: | 690 default: |
556 error->Format("Invalid relocation type (%d)", rela_type); | 691 error->Format("Invalid relocation type (%d)", rela_type); |
557 return false; | 692 return false; |
558 } | 693 } |
559 | 694 |
560 return true; | 695 return true; |
561 } | 696 } |
562 | 697 |
563 bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel, | 698 bool ElfRelocations::ApplyResolvedRelReloc(const ELF::Rel* rel, |
564 ELF::Addr sym_addr, | 699 ELF::Addr sym_addr, |
565 bool resolved CRAZY_UNUSED, | 700 bool resolved CRAZY_UNUSED, |
566 Error* error) { | 701 Error* error) { |
567 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | 702 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); |
568 const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info); | 703 const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info); |
569 | 704 |
570 const ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); | 705 const ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); |
571 | 706 |
572 RLOG(" rel reloc=%p offset=%p type=%d\n", reloc, rel->r_offset, rel_type); | 707 RLOG(" rel reloc=%p offset=%p type=%d\n", reloc, rel->r_offset, rel_type); |
573 | 708 |
574 // Apply the relocation. | 709 // Apply the relocation. |
575 ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc); | 710 ELF::Addr* CRAZY_UNUSED target = reinterpret_cast<ELF::Addr*>(reloc); |
576 switch (rel_type) { | 711 switch (rel_type) { |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
714 return true; | 849 return true; |
715 } | 850 } |
716 | 851 |
717 error->Format( | 852 error->Format( |
718 "Invalid weak relocation type (%d) for unknown symbol '%s'", | 853 "Invalid weak relocation type (%d) for unknown symbol '%s'", |
719 r, | 854 r, |
720 sym_name); | 855 sym_name); |
721 return false; | 856 return false; |
722 } | 857 } |
723 | 858 |
859 bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel, | |
860 const ElfSymbols* symbols, | |
861 SymbolResolver* resolver, | |
862 Error* error) { | |
863 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | |
864 const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); | |
865 | |
866 ELF::Addr sym_addr = 0; | |
867 ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); | |
868 RLOG(" reloc=%p offset=%p type=%d symbol=%d\n", | |
869 reloc, | |
870 rel->r_offset, | |
871 rel_type, | |
872 rel_symbol); | |
873 | |
874 if (rel_type == 0) | |
875 return true; | |
876 | |
877 bool resolved = false; | |
878 | |
879 // If this is a symbolic relocation, compute the symbol's address. | |
880 if (__builtin_expect(rel_symbol != 0, 0)) { | |
881 if (!ResolveSymbol(rel_type, | |
882 rel_symbol, | |
883 symbols, | |
884 resolver, | |
885 reloc, | |
886 &sym_addr, | |
887 error)) { | |
888 return false; | |
889 } | |
890 resolved = true; | |
891 } | |
892 | |
893 return ApplyResolvedRelReloc(rel, sym_addr, resolved, error); | |
894 } | |
895 | |
724 bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel, | 896 bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel, |
725 size_t rel_count, | 897 size_t rel_count, |
726 const ElfSymbols* symbols, | 898 const ElfSymbols* symbols, |
727 SymbolResolver* resolver, | 899 SymbolResolver* resolver, |
728 Error* error) { | 900 Error* error) { |
729 RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count); | 901 RLOG("%s: rel=%p rel_count=%d\n", __FUNCTION__, rel, rel_count); |
730 | 902 |
731 if (!rel) | 903 if (!rel) |
732 return true; | 904 return true; |
733 | 905 |
734 for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) { | 906 for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) { |
735 const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | 907 RLOG(" Relocation %d of %d:\n", rel_n + 1, rel_count); |
736 const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); | |
737 | 908 |
738 ELF::Addr sym_addr = 0; | 909 if (!ApplyRelReloc(rel, symbols, resolver, error)) |
739 ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); | |
740 RLOG(" %d/%d reloc=%p offset=%p type=%d symbol=%d\n", | |
741 rel_n + 1, | |
742 rel_count, | |
743 reloc, | |
744 rel->r_offset, | |
745 rel_type, | |
746 rel_symbol); | |
747 | |
748 if (rel_type == 0) | |
749 continue; | |
750 | |
751 bool resolved = false; | |
752 | |
753 // If this is a symbolic relocation, compute the symbol's address. | |
754 if (__builtin_expect(rel_symbol != 0, 0)) { | |
755 if (!ResolveSymbol(rel_type, | |
756 rel_symbol, | |
757 symbols, | |
758 resolver, | |
759 reloc, | |
760 &sym_addr, | |
761 error)) { | |
762 return false; | |
763 } | |
764 resolved = true; | |
765 } | |
766 | |
767 if (!ApplyRelReloc(rel, sym_addr, resolved, error)) | |
768 return false; | 910 return false; |
769 } | 911 } |
770 | 912 |
771 return true; | 913 return true; |
772 } | 914 } |
773 | 915 |
916 bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, | |
rmcilroy
2015/04/13 10:36:10
Could you template this with ApplyRelReloc? Not su
simonb (inactive)
2015/04/28 14:39:41
Possible, but the result doesn't aid readability m
rmcilroy
2015/05/01 14:15:22
Acknowledged.
| |
917 const ElfSymbols* symbols, | |
918 SymbolResolver* resolver, | |
919 Error* error) { | |
920 const ELF::Word rel_type = ELF_R_TYPE(rela->r_info); | |
921 const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info); | |
922 | |
923 ELF::Addr sym_addr = 0; | |
924 ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); | |
925 RLOG(" reloc=%p offset=%p type=%d symbol=%d\n", | |
926 reloc, | |
927 rela->r_offset, | |
928 rel_type, | |
929 rel_symbol); | |
930 | |
931 if (rel_type == 0) | |
932 return true; | |
933 | |
934 bool resolved = false; | |
935 | |
936 // If this is a symbolic relocation, compute the symbol's address. | |
937 if (__builtin_expect(rel_symbol != 0, 0)) { | |
938 if (!ResolveSymbol(rel_type, | |
939 rel_symbol, | |
940 symbols, | |
941 resolver, | |
942 reloc, | |
943 &sym_addr, | |
944 error)) { | |
945 return false; | |
946 } | |
947 resolved = true; | |
948 } | |
949 | |
950 return ApplyResolvedRelaReloc(rela, sym_addr, resolved, error); | |
951 } | |
952 | |
774 bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela, | 953 bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela, |
775 size_t rela_count, | 954 size_t rela_count, |
776 const ElfSymbols* symbols, | 955 const ElfSymbols* symbols, |
777 SymbolResolver* resolver, | 956 SymbolResolver* resolver, |
778 Error* error) { | 957 Error* error) { |
779 RLOG("%s: rela=%p rela_count=%d\n", __FUNCTION__, rela, rela_count); | 958 RLOG("%s: rela=%p rela_count=%d\n", __FUNCTION__, rela, rela_count); |
780 | 959 |
781 if (!rela) | 960 if (!rela) |
782 return true; | 961 return true; |
783 | 962 |
784 for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) { | 963 for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) { |
785 const ELF::Word rel_type = ELF_R_TYPE(rela->r_info); | 964 RLOG(" Relocation %d of %d:\n", rel_n + 1, rela_count); |
786 const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info); | |
787 | 965 |
788 ELF::Addr sym_addr = 0; | 966 if (!ApplyRelaReloc(rela, symbols, resolver, error)) |
789 ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); | |
790 RLOG(" %d/%d reloc=%p offset=%p type=%d symbol=%d\n", | |
791 rel_n + 1, | |
792 rela_count, | |
793 reloc, | |
794 rela->r_offset, | |
795 rel_type, | |
796 rel_symbol); | |
797 | |
798 if (rel_type == 0) | |
799 continue; | |
800 | |
801 bool resolved = false; | |
802 | |
803 // If this is a symbolic relocation, compute the symbol's address. | |
804 if (__builtin_expect(rel_symbol != 0, 0)) { | |
805 if (!ResolveSymbol(rel_type, | |
806 rel_symbol, | |
807 symbols, | |
808 resolver, | |
809 reloc, | |
810 &sym_addr, | |
811 error)) { | |
812 return false; | |
813 } | |
814 resolved = true; | |
815 } | |
816 | |
817 if (!ApplyRelaReloc(rela, sym_addr, resolved, error)) | |
818 return false; | 967 return false; |
819 } | 968 } |
820 | 969 |
821 return true; | 970 return true; |
822 } | 971 } |
823 | 972 |
824 #ifdef __mips__ | 973 #ifdef __mips__ |
825 bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols, | 974 bool ElfRelocations::RelocateMipsGot(const ElfSymbols* symbols, |
826 SymbolResolver* resolver, | 975 SymbolResolver* resolver, |
827 Error* error) { | 976 Error* error) { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
903 #ifdef __mips__ | 1052 #ifdef __mips__ |
904 case R_MIPS_REL32: | 1053 case R_MIPS_REL32: |
905 *dst_ptr += map_delta; | 1054 *dst_ptr += map_delta; |
906 break; | 1055 break; |
907 #endif | 1056 #endif |
908 default: | 1057 default: |
909 ; | 1058 ; |
910 } | 1059 } |
911 } | 1060 } |
912 | 1061 |
1062 // Args for ApplyAndroidRelocation handler function. | |
1063 struct RelocateAndroidRelocationArgs { | |
rmcilroy
2015/04/13 10:36:10
nit - move down to just above RelocateAndroidReloc
simonb (inactive)
2015/04/28 14:39:41
Done.
| |
1064 size_t src_addr; | |
1065 size_t dst_addr; | |
1066 size_t map_addr; | |
1067 size_t size; | |
1068 }; | |
1069 | |
1070 void ElfRelocations::RelocateAndroidReloc(const ELF::Rela* relocation, | |
1071 size_t src_addr, | |
1072 size_t dst_addr, | |
1073 size_t map_addr, | |
1074 size_t size) { | |
1075 // Add this value to each source address to get the corresponding | |
1076 // destination address. | |
1077 const size_t dst_delta = dst_addr - src_addr; | |
1078 const size_t map_delta = map_addr - src_addr; | |
1079 | |
1080 const ELF::Word rel_type = ELF_R_TYPE(relocation->r_info); | |
1081 const ELF::Word rel_symbol = ELF_R_SYM(relocation->r_info); | |
1082 ELF::Addr src_reloc = | |
1083 static_cast<ELF::Addr>(relocation->r_offset + load_bias_); | |
1084 | |
1085 if (rel_type == 0 || rel_symbol != 0) { | |
1086 // Ignore empty and symbolic relocations | |
1087 return; | |
1088 } | |
1089 | |
1090 if (src_reloc < src_addr || src_reloc >= src_addr + size) { | |
1091 // Ignore entries that don't relocate addresses inside the source section. | |
1092 return; | |
1093 } | |
1094 | |
1095 AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); | |
1096 } | |
1097 | |
1098 // Static ForEachAndroidRelocation() handler. | |
1099 bool ElfRelocations::RelocateAndroidRelocation(ElfRelocations* relocations, | |
1100 const ELF::Rela* relocation, | |
1101 void* opaque) { | |
1102 // Unpack args from opaque, to obtain addrs and size; | |
1103 RelocateAndroidRelocationArgs* args = | |
1104 reinterpret_cast<RelocateAndroidRelocationArgs*>(opaque); | |
1105 const size_t src_addr = args->src_addr; | |
1106 const size_t dst_addr = args->dst_addr; | |
1107 const size_t map_addr = args->map_addr; | |
1108 const size_t size = args->size; | |
1109 | |
1110 // Relocate the given relocation. Because the r_addend field is ignored | |
1111 // in relocating RELA relocations we do not need to convert from REL to | |
1112 // RELA and supply alternative relocator functions; instead we can work | |
1113 // here directly on the RELA supplied by ForEachAndroidRelocation(), even | |
1114 // on REL architectures. | |
1115 relocations->RelocateAndroidReloc(relocation, | |
1116 src_addr, dst_addr, map_addr, size); | |
1117 return true; | |
1118 } | |
1119 | |
1120 void ElfRelocations::RelocateAndroidRelocations(size_t src_addr, | |
1121 size_t dst_addr, | |
1122 size_t map_addr, | |
1123 size_t size) { | |
1124 if (!android_relocations_) | |
1125 return; | |
1126 | |
1127 assert(IsValidAndroidPackedRelocations(android_relocations_, | |
1128 android_relocations_size_)); | |
1129 | |
1130 RelocateAndroidRelocationArgs args; | |
1131 args.src_addr = src_addr; | |
1132 args.dst_addr = dst_addr; | |
1133 args.map_addr = map_addr; | |
1134 args.size = size; | |
1135 ForEachAndroidRelocation(&RelocateAndroidRelocation, &args); | |
1136 } | |
1137 | |
913 void ElfRelocations::RelocateRela(size_t src_addr, | 1138 void ElfRelocations::RelocateRela(size_t src_addr, |
914 size_t dst_addr, | 1139 size_t dst_addr, |
915 size_t map_addr, | 1140 size_t map_addr, |
916 size_t size) { | 1141 size_t size) { |
917 // Add this value to each source address to get the corresponding | 1142 // Add this value to each source address to get the corresponding |
918 // destination address. | 1143 // destination address. |
919 const size_t dst_delta = dst_addr - src_addr; | 1144 const size_t dst_delta = dst_addr - src_addr; |
920 const size_t map_delta = map_addr - src_addr; | 1145 const size_t map_delta = map_addr - src_addr; |
921 | 1146 |
922 // Ignore PLT relocations, which all target symbols (ignored here). | 1147 // Ignore PLT relocations, which all target symbols (ignored here). |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
978 | 1203 |
979 void ElfRelocations::CopyAndRelocate(size_t src_addr, | 1204 void ElfRelocations::CopyAndRelocate(size_t src_addr, |
980 size_t dst_addr, | 1205 size_t dst_addr, |
981 size_t map_addr, | 1206 size_t map_addr, |
982 size_t size) { | 1207 size_t size) { |
983 // First, a straight copy. | 1208 // First, a straight copy. |
984 ::memcpy(reinterpret_cast<void*>(dst_addr), | 1209 ::memcpy(reinterpret_cast<void*>(dst_addr), |
985 reinterpret_cast<void*>(src_addr), | 1210 reinterpret_cast<void*>(src_addr), |
986 size); | 1211 size); |
987 | 1212 |
1213 // Relocate android relocations. | |
1214 RelocateAndroidRelocations(src_addr, dst_addr, map_addr, size); | |
1215 | |
988 // Relocate relocations. | 1216 // Relocate relocations. |
989 if (relocations_type_ == DT_REL) | 1217 if (relocations_type_ == DT_REL) |
990 RelocateRel(src_addr, dst_addr, map_addr, size); | 1218 RelocateRel(src_addr, dst_addr, map_addr, size); |
991 | 1219 |
992 if (relocations_type_ == DT_RELA) | 1220 if (relocations_type_ == DT_RELA) |
993 RelocateRela(src_addr, dst_addr, map_addr, size); | 1221 RelocateRela(src_addr, dst_addr, map_addr, size); |
994 | 1222 |
995 #ifdef __mips__ | 1223 #ifdef __mips__ |
996 // Add this value to each source address to get the corresponding | 1224 // Add this value to each source address to get the corresponding |
997 // destination address. | 1225 // destination address. |
998 const size_t dst_delta = dst_addr - src_addr; | 1226 const size_t dst_delta = dst_addr - src_addr; |
999 const size_t map_delta = map_addr - src_addr; | 1227 const size_t map_delta = map_addr - src_addr; |
1000 | 1228 |
1001 // Only relocate local GOT entries. | 1229 // Only relocate local GOT entries. |
1002 ELF::Addr* got = plt_got_; | 1230 ELF::Addr* got = plt_got_; |
1003 if (got) { | 1231 if (got) { |
1004 for (ELF::Addr n = 2; n < mips_local_got_count_; ++n) { | 1232 for (ELF::Addr n = 2; n < mips_local_got_count_; ++n) { |
1005 size_t got_addr = reinterpret_cast<size_t>(&got[n]); | 1233 size_t got_addr = reinterpret_cast<size_t>(&got[n]); |
1006 if (got_addr < src_addr || got_addr >= src_addr + size) | 1234 if (got_addr < src_addr || got_addr >= src_addr + size) |
1007 continue; | 1235 continue; |
1008 ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta); | 1236 ELF::Addr* dst_ptr = reinterpret_cast<ELF::Addr*>(got_addr + dst_delta); |
1009 *dst_ptr += map_delta; | 1237 *dst_ptr += map_delta; |
1010 } | 1238 } |
1011 } | 1239 } |
1012 #endif | 1240 #endif |
1013 } | 1241 } |
1014 | 1242 |
1015 } // namespace crazy | 1243 } // namespace crazy |
OLD | NEW |