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/. */
8 #include "mozilla/IntegerPrintfMacros.h"
9 #include "mozilla/RefPtr.h"
13 unsigned long BaseElf::Hash(const char* symbol
) {
14 const unsigned char* sym
= reinterpret_cast<const unsigned char*>(symbol
);
15 unsigned long h
= 0, g
;
17 h
= (h
<< 4) + *sym
++;
25 void* BaseElf::GetSymbolPtr(const char* symbol
) const {
26 return GetSymbolPtr(symbol
, Hash(symbol
));
29 void* BaseElf::GetSymbolPtr(const char* symbol
, unsigned long hash
) const {
30 const Sym
* sym
= GetSymbol(symbol
, hash
);
32 if (sym
&& sym
->st_shndx
!= SHN_UNDEF
) ptr
= GetPtr(sym
->st_value
);
33 DEBUG_LOG("BaseElf::GetSymbolPtr(%p [\"%s\"], \"%s\") = %p",
34 reinterpret_cast<const void*>(this), GetPath(), symbol
, ptr
);
38 const Sym
* BaseElf::GetSymbol(const char* symbol
, unsigned long hash
) const {
39 /* Search symbol with the buckets and chains tables.
40 * The hash computed from the symbol name gives an index in the buckets
41 * table. The corresponding value in the bucket table is an index in the
42 * symbols table and in the chains table.
43 * If the corresponding symbol in the symbols table matches, we're done.
44 * Otherwise, the corresponding value in the chains table is a new index
45 * in both tables, which corresponding symbol is tested and so on and so
47 size_t bucket
= hash
% buckets
.numElements();
48 for (size_t y
= buckets
[bucket
]; y
!= STN_UNDEF
; y
= chains
[y
]) {
49 if (strcmp(symbol
, strtab
.GetStringAt(symtab
[y
].st_name
))) continue;
55 bool BaseElf::Contains(void* addr
) const { return base
.Contains(addr
); }
58 const void* BaseElf::FindExidx(int* pcount
) const {
60 *pcount
= arm_exidx
.numElements();
68 already_AddRefed
<LibHandle
> LoadedElf::Create(const char* path
,
70 DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = ...", path
, base_addr
);
73 /* If the page is not mapped, mincore returns an error. If base_addr is
74 * nullptr, as would happen if the corresponding binary is prelinked with
75 * the prelink look (but not with the android apriori tool), no page being
76 * mapped there (right?), mincore returns an error, too, which makes
77 * prelinked libraries on glibc unsupported. This is not an interesting
78 * use case for now, so don't try supporting that case.
80 if (mincore(const_cast<void*>(base_addr
), PageSize(), &mapped
))
83 RefPtr
<LoadedElf
> elf
= new LoadedElf(path
);
85 const Ehdr
* ehdr
= Ehdr::validate(base_addr
);
86 if (!ehdr
) return nullptr;
88 Addr min_vaddr
= (Addr
)-1; // We want to find the lowest and biggest
89 Addr max_vaddr
= 0; // virtual address used by this Elf.
90 const Phdr
* dyn
= nullptr;
92 const Phdr
* arm_exidx_phdr
= nullptr;
95 Array
<Phdr
> phdrs(reinterpret_cast<const char*>(ehdr
) + ehdr
->e_phoff
,
97 for (auto phdr
= phdrs
.begin(); phdr
< phdrs
.end(); ++phdr
) {
98 switch (phdr
->p_type
) {
100 if (phdr
->p_vaddr
< min_vaddr
) min_vaddr
= phdr
->p_vaddr
;
101 if (max_vaddr
< phdr
->p_vaddr
+ phdr
->p_memsz
)
102 max_vaddr
= phdr
->p_vaddr
+ phdr
->p_memsz
;
109 /* We cannot initialize arm_exidx here
110 because we don't have a base yet */
111 arm_exidx_phdr
= &*phdr
;
117 /* If the lowest PT_LOAD virtual address in headers is not 0, then the ELF
118 * is either prelinked or a non-PIE executable. The former case is not
119 * possible, because base_addr would be nullptr and the mincore test above
120 * would already have made us return.
121 * For a non-PIE executable, PT_LOADs contain absolute addresses, so in
122 * practice, this means min_vaddr should be equal to base_addr. max_vaddr
123 * can thus be adjusted accordingly.
125 if (min_vaddr
!= 0) {
126 void* min_vaddr_ptr
=
127 reinterpret_cast<void*>(static_cast<uintptr_t>(min_vaddr
));
128 if (min_vaddr_ptr
!= base_addr
) {
129 LOG("%s: %p != %p", elf
->GetPath(), min_vaddr_ptr
, base_addr
);
132 max_vaddr
-= min_vaddr
;
135 LOG("%s: No PT_DYNAMIC segment found", elf
->GetPath());
139 elf
->base
.Assign(base_addr
, max_vaddr
);
141 if (!elf
->InitDyn(dyn
)) return nullptr;
145 elf
->arm_exidx
.InitSize(elf
->GetPtr(arm_exidx_phdr
->p_vaddr
),
146 arm_exidx_phdr
->p_memsz
);
149 DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = %p", path
, base_addr
,
150 static_cast<void*>(elf
));
152 ElfLoader::Singleton
.Register(elf
);
156 bool LoadedElf::InitDyn(const Phdr
* pt_dyn
) {
158 dyns
.InitSize(GetPtr
<Dyn
>(pt_dyn
->p_vaddr
), pt_dyn
->p_filesz
);
161 for (auto dyn
= dyns
.begin(); dyn
< dyns
.end() && dyn
->d_tag
; ++dyn
) {
162 switch (dyn
->d_tag
) {
164 DEBUG_LOG("%s 0x%08" PRIxPTR
, "DT_HASH", uintptr_t(dyn
->d_un
.d_val
));
165 const Elf::Word
* hash_table_header
= GetPtr
<Elf::Word
>(dyn
->d_un
.d_ptr
);
166 symnum
= hash_table_header
[1];
167 buckets
.Init(&hash_table_header
[2], hash_table_header
[0]);
168 chains
.Init(&*buckets
.end());
171 DEBUG_LOG("%s 0x%08" PRIxPTR
, "DT_STRTAB", uintptr_t(dyn
->d_un
.d_val
));
172 strtab
.Init(GetPtr(dyn
->d_un
.d_ptr
));
175 DEBUG_LOG("%s 0x%08" PRIxPTR
, "DT_SYMTAB", uintptr_t(dyn
->d_un
.d_val
));
176 symtab
.Init(GetPtr(dyn
->d_un
.d_ptr
));
180 if (!buckets
|| !symnum
) {
181 ERROR("%s: Missing or broken DT_HASH", GetPath());
182 } else if (!strtab
) {
183 ERROR("%s: Missing DT_STRTAB", GetPath());
184 } else if (!symtab
) {
185 ERROR("%s: Missing DT_SYMTAB", GetPath());