1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
11 #include "CustomElf.h"
15 #include "mozilla/IntegerPrintfMacros.h"
19 /* TODO: Fill ElfLoader::Singleton.lastError on errors. */
21 const Ehdr
* Ehdr::validate(const void* buf
) {
22 if (!buf
|| buf
== MAP_FAILED
) return nullptr;
24 const Ehdr
* ehdr
= reinterpret_cast<const Ehdr
*>(buf
);
26 /* Only support ELF executables or libraries for the host system */
27 if (memcmp(ELFMAG
, &ehdr
->e_ident
, SELFMAG
) ||
28 ehdr
->e_ident
[EI_CLASS
] != ELFCLASS
||
29 ehdr
->e_ident
[EI_DATA
] != ELFDATA
|| ehdr
->e_ident
[EI_VERSION
] != 1 ||
30 (ehdr
->e_ident
[EI_OSABI
] != ELFOSABI
&&
31 ehdr
->e_ident
[EI_OSABI
] != ELFOSABI_NONE
) ||
33 ehdr
->e_ident
[EI_ABIVERSION
] != ELFABIVERSION
||
35 (ehdr
->e_type
!= ET_EXEC
&& ehdr
->e_type
!= ET_DYN
) ||
36 ehdr
->e_machine
!= ELFMACHINE
|| ehdr
->e_version
!= 1 ||
37 ehdr
->e_phentsize
!= sizeof(Phdr
))
45 void debug_phdr(const char* type
, const Phdr
* phdr
) {
46 DEBUG_LOG("%s @0x%08" PRIxPTR
48 "filesz: 0x%08" PRIxPTR
50 "memsz: 0x%08" PRIxPTR
52 "offset: 0x%08" PRIxPTR
55 type
, uintptr_t(phdr
->p_vaddr
), uintptr_t(phdr
->p_filesz
),
56 uintptr_t(phdr
->p_memsz
), uintptr_t(phdr
->p_offset
),
57 phdr
->p_flags
& PF_R
? 'r' : '-', phdr
->p_flags
& PF_W
? 'w' : '-',
58 phdr
->p_flags
& PF_X
? 'x' : '-');
61 static int p_flags_to_mprot(Word flags
) {
62 return ((flags
& PF_X
) ? PROT_EXEC
: 0) | ((flags
& PF_W
) ? PROT_WRITE
: 0) |
63 ((flags
& PF_R
) ? PROT_READ
: 0);
66 } /* anonymous namespace */
69 * RAII wrapper for a mapping of the first page off a Mappable object.
70 * This calls Mappable::munmap instead of system munmap.
72 class Mappable1stPagePtr
: public GenericMappedPtr
<Mappable1stPagePtr
> {
74 explicit Mappable1stPagePtr(Mappable
* mappable
)
75 : GenericMappedPtr
<Mappable1stPagePtr
>(
76 mappable
->mmap(nullptr, PageSize(), PROT_READ
, MAP_PRIVATE
, 0)),
80 friend class GenericMappedPtr
<Mappable1stPagePtr
>;
81 void munmap(void* buf
, size_t length
) { mappable
->munmap(buf
, length
); }
83 RefPtr
<Mappable
> mappable
;
86 already_AddRefed
<LibHandle
> CustomElf::Load(Mappable
* mappable
,
87 const char* path
, int flags
) {
88 DEBUG_LOG("CustomElf::Load(\"%s\", 0x%x) = ...", path
, flags
);
89 if (!mappable
) return nullptr;
90 /* Keeping a RefPtr of the CustomElf is going to free the appropriate
91 * resources when returning nullptr */
92 RefPtr
<CustomElf
> elf
= new CustomElf(mappable
, path
);
93 /* Map the first page of the Elf object to access Elf and program headers */
94 Mappable1stPagePtr
ehdr_raw(mappable
);
95 if (ehdr_raw
== MAP_FAILED
) return nullptr;
97 const Ehdr
* ehdr
= Ehdr::validate(ehdr_raw
);
98 if (!ehdr
) return nullptr;
100 /* Scan Elf Program Headers and gather some information about them */
101 std::vector
<const Phdr
*> pt_loads
;
102 Addr min_vaddr
= (Addr
)-1; // We want to find the lowest and biggest
103 Addr max_vaddr
= 0; // virtual address used by this Elf.
104 const Phdr
* dyn
= nullptr;
106 const Phdr
* first_phdr
= reinterpret_cast<const Phdr
*>(
107 reinterpret_cast<const char*>(ehdr
) + ehdr
->e_phoff
);
108 const Phdr
* end_phdr
= &first_phdr
[ehdr
->e_phnum
];
110 const Phdr
* arm_exidx_phdr
= nullptr;
113 for (const Phdr
* phdr
= first_phdr
; phdr
< end_phdr
; phdr
++) {
114 switch (phdr
->p_type
) {
116 debug_phdr("PT_LOAD", phdr
);
117 pt_loads
.push_back(phdr
);
118 if (phdr
->p_vaddr
< min_vaddr
) min_vaddr
= phdr
->p_vaddr
;
119 if (max_vaddr
< phdr
->p_vaddr
+ phdr
->p_memsz
)
120 max_vaddr
= phdr
->p_vaddr
+ phdr
->p_memsz
;
123 debug_phdr("PT_DYNAMIC", phdr
);
127 ERROR("%s: Multiple PT_DYNAMIC segments detected", elf
->GetPath());
132 debug_phdr("PT_TLS", phdr
);
134 ERROR("%s: TLS is not supported", elf
->GetPath());
139 debug_phdr("PT_GNU_STACK", phdr
);
140 // Skip on Android until bug 706116 is fixed
142 if (phdr
->p_flags
& PF_X
) {
143 ERROR("%s: Executable stack is not supported", elf
->GetPath());
150 /* We cannot initialize arm_exidx here
151 because we don't have a base yet */
152 arm_exidx_phdr
= phdr
;
156 DEBUG_LOG("%s: Program header type #%d not handled", elf
->GetPath(),
161 if (min_vaddr
!= 0) {
162 ERROR("%s: Unsupported minimal virtual address: 0x%08" PRIxPTR
,
163 elf
->GetPath(), uintptr_t(min_vaddr
));
167 ERROR("%s: No PT_DYNAMIC segment found", elf
->GetPath());
171 /* Reserve enough memory to map the complete virtual address space for this
173 * As we are using the base address from here to mmap something else with
174 * MAP_FIXED | MAP_SHARED, we need to make sure these mmaps will work. For
175 * instance, on armv6, MAP_SHARED mappings require a 16k alignment, but mmap
176 * MAP_PRIVATE only returns a 4k aligned address. So we first get a base
177 * address with MAP_SHARED, which guarantees the kernel returns an address
178 * that we'll be able to use with MAP_FIXED, and then remap MAP_PRIVATE at
179 * the same address, because of some bad side effects of keeping it as
181 elf
->base
.Assign(MemoryRange::mmap(nullptr, max_vaddr
, PROT_NONE
,
182 MAP_SHARED
| MAP_ANONYMOUS
, -1, 0));
183 if ((elf
->base
== MAP_FAILED
) ||
184 (mmap(elf
->base
, max_vaddr
, PROT_NONE
,
185 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_FIXED
, -1, 0) != elf
->base
)) {
186 ERROR("%s: Failed to mmap", elf
->GetPath());
190 /* Load and initialize library */
191 for (std::vector
<const Phdr
*>::iterator it
= pt_loads
.begin();
192 it
< pt_loads
.end(); ++it
)
193 if (!elf
->LoadSegment(*it
)) return nullptr;
195 /* We're not going to mmap anymore */
196 mappable
->finalize();
198 elf
->l_addr
= elf
->base
;
199 elf
->l_name
= elf
->GetPath();
200 elf
->l_ld
= elf
->GetPtr
<Dyn
>(dyn
->p_vaddr
);
201 ElfLoader::Singleton
.Register(elf
);
203 if (!elf
->InitDyn(dyn
)) return nullptr;
205 if (elf
->has_text_relocs
) {
206 for (std::vector
<const Phdr
*>::iterator it
= pt_loads
.begin();
207 it
< pt_loads
.end(); ++it
)
208 mprotect(PageAlignedPtr(elf
->GetPtr((*it
)->p_vaddr
)),
209 PageAlignedEndPtr((*it
)->p_memsz
),
210 p_flags_to_mprot((*it
)->p_flags
) | PROT_WRITE
);
213 if (!elf
->Relocate() || !elf
->RelocateJumps()) return nullptr;
215 if (elf
->has_text_relocs
) {
216 for (std::vector
<const Phdr
*>::iterator it
= pt_loads
.begin();
217 it
< pt_loads
.end(); ++it
)
218 mprotect(PageAlignedPtr(elf
->GetPtr((*it
)->p_vaddr
)),
219 PageAlignedEndPtr((*it
)->p_memsz
),
220 p_flags_to_mprot((*it
)->p_flags
));
223 if (!elf
->CallInit()) return nullptr;
227 elf
->arm_exidx
.InitSize(elf
->GetPtr(arm_exidx_phdr
->p_vaddr
),
228 arm_exidx_phdr
->p_memsz
);
231 DEBUG_LOG("CustomElf::Load(\"%s\", 0x%x) = %p", path
, flags
,
232 static_cast<void*>(elf
));
236 CustomElf::~CustomElf() {
237 DEBUG_LOG("CustomElf::~CustomElf(%p [\"%s\"])", reinterpret_cast<void*>(this),
240 /* Normally, __cxa_finalize is called by the .fini function. However,
241 * Android NDK before r6b doesn't do that. Our wrapped cxa_finalize only
242 * calls destructors once, so call it in all cases. */
243 ElfLoader::__wrap_cxa_finalize(this);
244 ElfLoader::Singleton
.Forget(this);
247 void* CustomElf::GetSymbolPtrInDeps(const char* symbol
) const {
248 /* Resolve dlopen and related functions to point to ours */
249 if (symbol
[0] == 'd' && symbol
[1] == 'l') {
250 if (strcmp(symbol
+ 2, "open") == 0) return FunctionPtr(__wrap_dlopen
);
251 if (strcmp(symbol
+ 2, "error") == 0) return FunctionPtr(__wrap_dlerror
);
252 if (strcmp(symbol
+ 2, "close") == 0) return FunctionPtr(__wrap_dlclose
);
253 if (strcmp(symbol
+ 2, "sym") == 0) return FunctionPtr(__wrap_dlsym
);
254 if (strcmp(symbol
+ 2, "addr") == 0) return FunctionPtr(__wrap_dladdr
);
255 if (strcmp(symbol
+ 2, "_iterate_phdr") == 0)
256 return FunctionPtr(__wrap_dl_iterate_phdr
);
257 } else if (symbol
[0] == '_' && symbol
[1] == '_') {
258 /* Resolve a few C++ ABI specific functions to point to ours */
260 if (strcmp(symbol
+ 2, "aeabi_atexit") == 0)
261 return FunctionPtr(&ElfLoader::__wrap_aeabi_atexit
);
263 if (strcmp(symbol
+ 2, "cxa_atexit") == 0)
264 return FunctionPtr(&ElfLoader::__wrap_cxa_atexit
);
266 if (strcmp(symbol
+ 2, "cxa_finalize") == 0)
267 return FunctionPtr(&ElfLoader::__wrap_cxa_finalize
);
268 if (strcmp(symbol
+ 2, "dso_handle") == 0)
269 return const_cast<CustomElf
*>(this);
271 if (strcmp(symbol
+ 2, "gnu_Unwind_Find_exidx") == 0)
272 return FunctionPtr(__wrap___gnu_Unwind_Find_exidx
);
274 } else if (symbol
[0] == 's' && symbol
[1] == 'i') {
275 if (strcmp(symbol
+ 2, "gnal") == 0) return FunctionPtr(signal
);
276 if (strcmp(symbol
+ 2, "gaction") == 0) return FunctionPtr(sigaction
);
281 unsigned long hash
= Hash(symbol
);
283 /* self_elf should never be NULL, but better safe than sorry. */
284 if (ElfLoader::Singleton
.self_elf
) {
285 /* We consider the library containing this code a permanent LD_PRELOAD,
286 * so, check if the symbol exists here first. */
287 sym
= static_cast<BaseElf
*>(ElfLoader::Singleton
.self_elf
.get())
288 ->GetSymbolPtr(symbol
, hash
);
292 /* Then search the symbol in our dependencies. Since we already searched in
293 * libraries the system linker loaded, skip those (on glibc systems). We
294 * also assume the symbol is to be found in one of the dependent libraries
295 * directly, not in their own dependent libraries. Building libraries with
296 * --no-allow-shlib-undefined ensures such indirect symbol dependency don't
298 for (std::vector
<RefPtr
<LibHandle
> >::const_iterator it
=
299 dependencies
.begin();
300 it
< dependencies
.end(); ++it
) {
301 /* Skip if it's the library containing this code, since we've already
302 * looked at it above. */
303 if (*it
== ElfLoader::Singleton
.self_elf
) continue;
304 if (BaseElf
* be
= (*it
)->AsBaseElf()) {
305 sym
= be
->GetSymbolPtr(symbol
, hash
);
307 sym
= (*it
)->GetSymbolPtr(symbol
);
314 bool CustomElf::LoadSegment(const Phdr
* pt_load
) const {
315 if (pt_load
->p_type
!= PT_LOAD
) {
316 DEBUG_LOG("%s: Elf::LoadSegment only takes PT_LOAD program headers",
322 int prot
= p_flags_to_mprot(pt_load
->p_flags
);
324 /* Mmap at page boundary */
325 Addr align
= PageSize();
327 void *mapped
, *where
;
329 align_offset
= pt_load
->p_vaddr
- AlignedPtr(pt_load
->p_vaddr
, align
);
330 where
= GetPtr(pt_load
->p_vaddr
- align_offset
);
331 DEBUG_LOG("%s: Loading segment @%p %c%c%c", GetPath(), where
,
332 prot
& PROT_READ
? 'r' : '-', prot
& PROT_WRITE
? 'w' : '-',
333 prot
& PROT_EXEC
? 'x' : '-');
334 mapped
= mappable
->mmap(where
, pt_load
->p_filesz
+ align_offset
, prot
,
335 MAP_PRIVATE
| MAP_FIXED
,
336 pt_load
->p_offset
- align_offset
);
337 if ((mapped
!= MAP_FAILED
) || (pt_load
->p_vaddr
== 0) ||
338 (pt_load
->p_align
== align
))
340 /* The virtual address space for the library is properly aligned at
341 * 16k on ARMv6 (see CustomElf::Load), and so is the first segment
342 * (p_vaddr == 0). But subsequent segments may not be 16k aligned
343 * and fail to mmap. In such case, try to mmap again at the p_align
344 * boundary instead of page boundary. */
345 DEBUG_LOG("%s: Failed to mmap, retrying", GetPath());
346 align
= pt_load
->p_align
;
349 if (mapped
!= where
) {
350 if (mapped
== MAP_FAILED
) {
351 ERROR("%s: Failed to mmap", GetPath());
353 ERROR("%s: Didn't map at the expected location (wanted: %p, got: %p)",
354 GetPath(), where
, mapped
);
359 /* When p_memsz is greater than p_filesz, we need to have nulled out memory
360 * after p_filesz and before p_memsz.
361 * Above the end of the last page, and up to p_memsz, we already have nulled
362 * out memory because we mapped anonymous memory on the whole library virtual
363 * address space. We just need to adjust this anonymous memory protection
365 if (pt_load
->p_memsz
> pt_load
->p_filesz
) {
366 Addr file_end
= pt_load
->p_vaddr
+ pt_load
->p_filesz
;
367 Addr mem_end
= pt_load
->p_vaddr
+ pt_load
->p_memsz
;
368 Addr next_page
= PageAlignedEndPtr(file_end
);
369 if (next_page
> file_end
) {
370 void* ptr
= GetPtr(file_end
);
371 memset(ptr
, 0, next_page
- file_end
);
373 if (mem_end
> next_page
) {
374 if (mprotect(GetPtr(next_page
), mem_end
- next_page
, prot
) < 0) {
375 ERROR("%s: Failed to mprotect", GetPath());
385 void debug_dyn(const char* type
, const Dyn
* dyn
) {
386 DEBUG_LOG("%s 0x%08" PRIxPTR
, type
, uintptr_t(dyn
->d_un
.d_val
));
389 } /* anonymous namespace */
391 bool CustomElf::InitDyn(const Phdr
* pt_dyn
) {
392 /* Scan PT_DYNAMIC segment and gather some information */
393 const Dyn
* first_dyn
= GetPtr
<Dyn
>(pt_dyn
->p_vaddr
);
394 const Dyn
* end_dyn
= GetPtr
<Dyn
>(pt_dyn
->p_vaddr
+ pt_dyn
->p_filesz
);
395 std::vector
<Word
> dt_needed
;
397 for (const Dyn
* dyn
= first_dyn
; dyn
< end_dyn
&& dyn
->d_tag
; dyn
++) {
398 switch (dyn
->d_tag
) {
400 debug_dyn("DT_NEEDED", dyn
);
401 dt_needed
.push_back(dyn
->d_un
.d_val
);
404 debug_dyn("DT_HASH", dyn
);
405 const Word
* hash_table_header
= GetPtr
<Word
>(dyn
->d_un
.d_ptr
);
406 symnum
= hash_table_header
[1];
407 buckets
.Init(&hash_table_header
[2], hash_table_header
[0]);
408 chains
.Init(&*buckets
.end());
411 debug_dyn("DT_STRTAB", dyn
);
412 strtab
.Init(GetPtr(dyn
->d_un
.d_ptr
));
415 debug_dyn("DT_SYMTAB", dyn
);
416 symtab
.Init(GetPtr(dyn
->d_un
.d_ptr
));
419 debug_dyn("DT_SYMENT", dyn
);
420 if (dyn
->d_un
.d_val
!= sizeof(Sym
)) {
421 ERROR("%s: Unsupported DT_SYMENT", GetPath());
426 if (strcmp("libflashplayer.so", GetName()) == 0) {
427 has_text_relocs
= true;
429 ERROR("%s: Text relocations are not supported", GetPath());
433 case DT_STRSZ
: /* Ignored */
434 debug_dyn("DT_STRSZ", dyn
);
436 case UNSUPPORTED_RELOC():
437 case UNSUPPORTED_RELOC(SZ
):
438 case UNSUPPORTED_RELOC(ENT
):
439 ERROR("%s: Unsupported relocations", GetPath());
442 debug_dyn(STR_RELOC(), dyn
);
443 relocations
.Init(GetPtr(dyn
->d_un
.d_ptr
));
446 debug_dyn(STR_RELOC(SZ
), dyn
);
447 relocations
.InitSize(dyn
->d_un
.d_val
);
450 debug_dyn(STR_RELOC(ENT
), dyn
);
451 if (dyn
->d_un
.d_val
!= sizeof(Reloc
)) {
452 ERROR("%s: Unsupported DT_RELENT", GetPath());
457 debug_dyn("DT_JMPREL", dyn
);
458 jumprels
.Init(GetPtr(dyn
->d_un
.d_ptr
));
461 debug_dyn("DT_PLTRELSZ", dyn
);
462 jumprels
.InitSize(dyn
->d_un
.d_val
);
465 debug_dyn("DT_PLTGOT", dyn
);
468 debug_dyn("DT_INIT", dyn
);
469 init
= dyn
->d_un
.d_ptr
;
472 debug_dyn("DT_INIT_ARRAY", dyn
);
473 init_array
.Init(GetPtr(dyn
->d_un
.d_ptr
));
475 case DT_INIT_ARRAYSZ
:
476 debug_dyn("DT_INIT_ARRAYSZ", dyn
);
477 init_array
.InitSize(dyn
->d_un
.d_val
);
480 debug_dyn("DT_FINI", dyn
);
481 fini
= dyn
->d_un
.d_ptr
;
484 debug_dyn("DT_FINI_ARRAY", dyn
);
485 fini_array
.Init(GetPtr(dyn
->d_un
.d_ptr
));
487 case DT_FINI_ARRAYSZ
:
488 debug_dyn("DT_FINI_ARRAYSZ", dyn
);
489 fini_array
.InitSize(dyn
->d_un
.d_val
);
492 if (dyn
->d_un
.d_val
!= RELOC()) {
493 ERROR("%s: Error: DT_PLTREL is not " STR_RELOC(), GetPath());
498 Addr flags
= dyn
->d_un
.d_val
;
499 /* Treat as a DT_TEXTREL tag */
500 if (flags
& DF_TEXTREL
) {
501 if (strcmp("libflashplayer.so", GetName()) == 0) {
502 has_text_relocs
= true;
504 ERROR("%s: Text relocations are not supported", GetPath());
508 /* we can treat this like having a DT_SYMBOLIC tag */
509 flags
&= ~DF_SYMBOLIC
;
511 WARN("%s: unhandled flags #%" PRIxPTR
" not handled", GetPath(),
514 case DT_SONAME
: /* Should match GetName(), but doesn't matter */
515 case DT_SYMBOLIC
: /* Indicates internal symbols should be looked up in
516 * the library itself first instead of the executable,
517 * which is actually what this linker does by default */
518 case RELOC(COUNT
): /* Indicates how many relocations are relative, which
519 * is usually used to skip relocations on prelinked
520 * libraries. They are not supported anyways. */
521 case UNSUPPORTED_RELOC(COUNT
): /* This should error out, but it doesn't
523 case DT_FLAGS_1
: /* Additional linker-internal flags that we don't care
524 * about. See DF_1_* values in src/include/elf/common.h
526 case DT_VERSYM
: /* DT_VER* entries are used for symbol versioning, which
528 case DT_VERDEF
: /* this linker doesn't support yet. */
535 WARN("%s: dynamic header type #%" PRIxPTR
" not handled", GetPath(),
536 uintptr_t(dyn
->d_tag
));
540 if (!buckets
|| !symnum
) {
541 ERROR("%s: Missing or broken DT_HASH", GetPath());
545 ERROR("%s: Missing DT_STRTAB", GetPath());
549 ERROR("%s: Missing DT_SYMTAB", GetPath());
553 /* Load dependent libraries */
554 for (size_t i
= 0; i
< dt_needed
.size(); i
++) {
555 const char* name
= strtab
.GetStringAt(dt_needed
[i
]);
556 RefPtr
<LibHandle
> handle
=
557 ElfLoader::Singleton
.Load(name
, RTLD_GLOBAL
| RTLD_LAZY
, this);
558 if (!handle
) return false;
559 dependencies
.push_back(handle
);
565 bool CustomElf::Relocate() {
566 DEBUG_LOG("Relocate %s @%p", GetPath(), static_cast<void*>(base
));
567 uint32_t symtab_index
= (uint32_t)-1;
568 void* symptr
= nullptr;
569 for (Array
<Reloc
>::iterator rel
= relocations
.begin();
570 rel
< relocations
.end(); ++rel
) {
571 /* Location of the relocation */
572 void* ptr
= GetPtr(rel
->r_offset
);
574 /* R_*_RELATIVE relocations apply directly at the given location */
575 if (ELF_R_TYPE(rel
->r_info
) == R_RELATIVE
) {
576 *(void**)ptr
= GetPtr(rel
->GetAddend(base
));
579 /* Other relocation types need a symbol resolution */
580 /* Avoid symbol resolution when it's the same symbol as last iteration */
581 if (symtab_index
!= ELF_R_SYM(rel
->r_info
)) {
582 symtab_index
= ELF_R_SYM(rel
->r_info
);
583 const Sym sym
= symtab
[symtab_index
];
584 if (sym
.st_shndx
!= SHN_UNDEF
) {
585 symptr
= GetPtr(sym
.st_value
);
587 /* TODO: handle symbol resolving to nullptr vs. being undefined. */
588 symptr
= GetSymbolPtrInDeps(strtab
.GetStringAt(sym
.st_name
));
592 if (symptr
== nullptr)
593 WARN("%s: Relocation to NULL @0x%08" PRIxPTR
, GetPath(),
594 uintptr_t(rel
->r_offset
));
596 /* Apply relocation */
597 switch (ELF_R_TYPE(rel
->r_info
)) {
599 /* R_*_GLOB_DAT relocations simply use the symbol value */
600 *(void**)ptr
= symptr
;
603 /* R_*_ABS* relocations add the relocation added to the symbol value */
604 *(const char**)ptr
= (const char*)symptr
+ rel
->GetAddend(base
);
607 ERROR("%s: Unsupported relocation type: 0x%" PRIxPTR
, GetPath(),
608 uintptr_t(ELF_R_TYPE(rel
->r_info
)));
615 bool CustomElf::RelocateJumps() {
616 /* TODO: Dynamic symbol resolution */
617 for (Array
<Reloc
>::iterator rel
= jumprels
.begin(); rel
< jumprels
.end();
619 /* Location of the relocation */
620 void* ptr
= GetPtr(rel
->r_offset
);
622 /* Only R_*_JMP_SLOT relocations are expected */
623 if (ELF_R_TYPE(rel
->r_info
) != R_JMP_SLOT
) {
624 ERROR("%s: Jump relocation type mismatch", GetPath());
628 /* TODO: Avoid code duplication with the relocations above */
629 const Sym sym
= symtab
[ELF_R_SYM(rel
->r_info
)];
631 if (sym
.st_shndx
!= SHN_UNDEF
)
632 symptr
= GetPtr(sym
.st_value
);
634 symptr
= GetSymbolPtrInDeps(strtab
.GetStringAt(sym
.st_name
));
636 if (symptr
== nullptr) {
637 if (ELF_ST_BIND(sym
.st_info
) == STB_WEAK
) {
638 WARN("%s: Relocation to NULL @0x%08" PRIxPTR
" for symbol \"%s\"",
639 GetPath(), uintptr_t(rel
->r_offset
),
640 strtab
.GetStringAt(sym
.st_name
));
642 ERROR("%s: Relocation to NULL @0x%08" PRIxPTR
" for symbol \"%s\"",
643 GetPath(), uintptr_t(rel
->r_offset
),
644 strtab
.GetStringAt(sym
.st_name
));
648 /* Apply relocation */
649 *(void**)ptr
= symptr
;
654 bool CustomElf::CallInit() {
655 if (init
) CallFunction(init
);
657 for (Array
<void*>::iterator it
= init_array
.begin(); it
< init_array
.end();
659 /* Android x86 NDK wrongly puts 0xffffffff in INIT_ARRAY */
660 if (*it
&& *it
!= reinterpret_cast<void*>(-1)) CallFunction(*it
);
666 void CustomElf::CallFini() {
667 if (!initialized
) return;
668 for (Array
<void*>::reverse_iterator it
= fini_array
.rbegin();
669 it
< fini_array
.rend(); ++it
) {
670 /* Android x86 NDK wrongly puts 0xffffffff in FINI_ARRAY */
671 if (*it
&& *it
!= reinterpret_cast<void*>(-1)) CallFunction(*it
);
673 if (fini
) CallFunction(fini
);