mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1081034 part 2 - Move initialization of self_elf to its own separate class. r=nfroyd
The new class is kind of like SystemElf, but using our linker's own symbol resolution. This also adds some initialization from ELF program headers that weren't done previously for self_elf, as well as registration as for CustomElf instances.
This commit is contained in:
parent
c745a94ef5
commit
8751066e3e
@ -5,8 +5,10 @@
|
||||
#include "BaseElf.h"
|
||||
#include "Elfxx.h"
|
||||
#include "Logging.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
using namespace Elf;
|
||||
using namespace mozilla;
|
||||
|
||||
unsigned long
|
||||
BaseElf::Hash(const char *symbol)
|
||||
@ -78,3 +80,136 @@ BaseElf::FindExidx(int *pcount) const
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
mozilla::TemporaryRef<LibHandle>
|
||||
LoadedElf::Create(const char *path, void *base_addr)
|
||||
{
|
||||
DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = ...", path, base_addr);
|
||||
|
||||
uint8_t mapped;
|
||||
/* If the page is not mapped, mincore returns an error. If base_addr is
|
||||
* nullptr, as would happen if the corresponding binary is prelinked with
|
||||
* the prelink look (but not with the android apriori tool), no page being
|
||||
* mapped there (right?), mincore returns an error, too, which makes
|
||||
* prelinked libraries on glibc unsupported. This is not an interesting
|
||||
* use case for now, so don't try supporting that case.
|
||||
*/
|
||||
if (mincore(const_cast<void*>(base_addr), PageSize(), &mapped))
|
||||
return nullptr;
|
||||
|
||||
RefPtr<LoadedElf> elf = new LoadedElf(path);
|
||||
|
||||
const Ehdr *ehdr = Ehdr::validate(base_addr);
|
||||
if (!ehdr)
|
||||
return nullptr;
|
||||
|
||||
Addr min_vaddr = (Addr) -1; // We want to find the lowest and biggest
|
||||
Addr max_vaddr = 0; // virtual address used by this Elf.
|
||||
const Phdr *dyn = nullptr;
|
||||
#ifdef __ARM_EABI__
|
||||
const Phdr *arm_exidx_phdr = nullptr;
|
||||
#endif
|
||||
|
||||
Array<Phdr> phdrs(reinterpret_cast<const char *>(ehdr) + ehdr->e_phoff,
|
||||
ehdr->e_phnum);
|
||||
for (auto phdr = phdrs.begin(); phdr < phdrs.end(); ++phdr) {
|
||||
switch (phdr->p_type) {
|
||||
case PT_LOAD:
|
||||
if (phdr->p_vaddr < min_vaddr)
|
||||
min_vaddr = phdr->p_vaddr;
|
||||
if (max_vaddr < phdr->p_vaddr + phdr->p_memsz)
|
||||
max_vaddr = phdr->p_vaddr + phdr->p_memsz;
|
||||
break;
|
||||
case PT_DYNAMIC:
|
||||
dyn = &*phdr;
|
||||
break;
|
||||
#ifdef __ARM_EABI__
|
||||
case PT_ARM_EXIDX:
|
||||
/* We cannot initialize arm_exidx here
|
||||
because we don't have a base yet */
|
||||
arm_exidx_phdr = &*phdr;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* If the lowest PT_LOAD virtual address in headers is not 0, then the ELF
|
||||
* is either prelinked or a non-PIE executable. The former case is not
|
||||
* possible, because base_addr would be nullptr and the mincore test above
|
||||
* would already have made us return.
|
||||
* For a non-PIE executable, PT_LOADs contain absolute addresses, so in
|
||||
* practice, this means min_vaddr should be equal to base_addr. max_vaddr
|
||||
* can thus be adjusted accordingly.
|
||||
*/
|
||||
if (min_vaddr != 0) {
|
||||
void *min_vaddr_ptr = reinterpret_cast<void *>(
|
||||
static_cast<uintptr_t>(min_vaddr));
|
||||
if (min_vaddr_ptr != base_addr) {
|
||||
LOG("%s: %p != %p", elf->GetPath(), min_vaddr_ptr, base_addr);
|
||||
return nullptr;
|
||||
}
|
||||
max_vaddr -= min_vaddr;
|
||||
}
|
||||
if (!dyn) {
|
||||
LOG("%s: No PT_DYNAMIC segment found", elf->GetPath());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
elf->base.Assign(base_addr, max_vaddr);
|
||||
|
||||
if (!elf->InitDyn(dyn))
|
||||
return nullptr;
|
||||
|
||||
#ifdef __ARM_EABI__
|
||||
if (arm_exidx_phdr)
|
||||
elf->arm_exidx.InitSize(elf->GetPtr(arm_exidx_phdr->p_vaddr),
|
||||
arm_exidx_phdr->p_memsz);
|
||||
#endif
|
||||
|
||||
DEBUG_LOG("LoadedElf::Create(\"%s\", %p) = %p", path, base_addr,
|
||||
static_cast<void *>(elf));
|
||||
|
||||
ElfLoader::Singleton.Register(elf);
|
||||
return elf;
|
||||
}
|
||||
|
||||
bool
|
||||
LoadedElf::InitDyn(const Phdr *pt_dyn)
|
||||
{
|
||||
Array<Dyn> dyns;
|
||||
dyns.InitSize(GetPtr<Dyn>(pt_dyn->p_vaddr), pt_dyn->p_filesz);
|
||||
|
||||
size_t symnum = 0;
|
||||
for (auto dyn = dyns.begin(); dyn < dyns.end() && dyn->d_tag; ++dyn) {
|
||||
switch (dyn->d_tag) {
|
||||
case DT_HASH:
|
||||
{
|
||||
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
|
||||
const Elf::Word *hash_table_header = \
|
||||
GetPtr<Elf::Word>(dyn->d_un.d_ptr);
|
||||
symnum = hash_table_header[1];
|
||||
buckets.Init(&hash_table_header[2], hash_table_header[0]);
|
||||
chains.Init(&*buckets.end());
|
||||
}
|
||||
break;
|
||||
case DT_STRTAB:
|
||||
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
|
||||
strtab.Init(GetPtr(dyn->d_un.d_ptr));
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
|
||||
symtab.Init(GetPtr(dyn->d_un.d_ptr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!buckets || !symnum) {
|
||||
ERROR("%s: Missing or broken DT_HASH", GetPath());
|
||||
} else if (!strtab) {
|
||||
ERROR("%s: Missing DT_STRTAB", GetPath());
|
||||
} else if (!symtab) {
|
||||
ERROR("%s: Missing DT_SYMTAB", GetPath());
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -103,4 +103,39 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class for ELF libraries that already loaded in memory.
|
||||
*/
|
||||
class LoadedElf: public BaseElf
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Returns a LoadedElf corresponding to the already loaded ELF
|
||||
* at the given base address.
|
||||
*/
|
||||
static mozilla::TemporaryRef<LibHandle> Create(const char *path,
|
||||
void *base_addr);
|
||||
|
||||
private:
|
||||
LoadedElf(const char *path)
|
||||
: BaseElf(path) { }
|
||||
|
||||
~LoadedElf()
|
||||
{
|
||||
/* Avoid base's destructor unmapping something that doesn't actually
|
||||
* belong to it. */
|
||||
base.release();
|
||||
ElfLoader::Singleton.Forget(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the library according to information found in the given
|
||||
* PT_DYNAMIC header.
|
||||
* Returns whether this succeeded or failed.
|
||||
*/
|
||||
bool InitDyn(const Elf::Phdr *pt_dyn);
|
||||
};
|
||||
|
||||
|
||||
#endif /* BaseElf_h */
|
||||
|
@ -329,7 +329,8 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
|
||||
if (ElfLoader::Singleton.self_elf) {
|
||||
/* We consider the library containing this code a permanent LD_PRELOAD,
|
||||
* so, check if the symbol exists here first. */
|
||||
sym = ElfLoader::Singleton.self_elf->GetSymbolPtr(symbol, hash);
|
||||
sym = static_cast<BaseElf *>(
|
||||
ElfLoader::Singleton.self_elf.get())->GetSymbolPtr(symbol, hash);
|
||||
if (sym)
|
||||
return sym;
|
||||
}
|
||||
@ -342,6 +343,10 @@ CustomElf::GetSymbolPtrInDeps(const char *symbol) const
|
||||
* happen. */
|
||||
for (std::vector<RefPtr<LibHandle> >::const_iterator it = dependencies.begin();
|
||||
it < dependencies.end(); ++it) {
|
||||
/* Skip if it's the library containing this code, since we've already
|
||||
* looked at it above. */
|
||||
if (*it == ElfLoader::Singleton.self_elf)
|
||||
continue;
|
||||
if (BaseElf *be = (*it)->AsBaseElf()) {
|
||||
sym = be->GetSymbolPtr(symbol, hash);
|
||||
} else {
|
||||
|
@ -497,49 +497,17 @@ ElfLoader::Init()
|
||||
* containing this code is dlopen()ed, it can't call dladdr from a
|
||||
* static initializer. */
|
||||
if (dladdr(_DYNAMIC, &info) != 0) {
|
||||
/* Ideally, we wouldn't be initializing self_elf this way, but until
|
||||
* SystemElf actually inherits from BaseElf, we'll just do it this
|
||||
* (gross) way. */
|
||||
UniquePtr<BaseElf> elf = mozilla::MakeUnique<BaseElf>(info.dli_fname);
|
||||
elf->base.Assign(info.dli_fbase, -1);
|
||||
size_t symnum = 0;
|
||||
for (const Elf::Dyn *dyn = _DYNAMIC; dyn->d_tag; dyn++) {
|
||||
switch (dyn->d_tag) {
|
||||
case DT_HASH:
|
||||
{
|
||||
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_HASH", dyn->d_un.d_val);
|
||||
const Elf::Word *hash_table_header = \
|
||||
elf->GetPtr<Elf::Word>(dyn->d_un.d_ptr);
|
||||
symnum = hash_table_header[1];
|
||||
elf->buckets.Init(&hash_table_header[2], hash_table_header[0]);
|
||||
elf->chains.Init(&*elf->buckets.end());
|
||||
}
|
||||
break;
|
||||
case DT_STRTAB:
|
||||
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_STRTAB", dyn->d_un.d_val);
|
||||
elf->strtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
DEBUG_LOG("%s 0x%08" PRIxAddr, "DT_SYMTAB", dyn->d_un.d_val);
|
||||
elf->symtab.Init(elf->GetPtr(dyn->d_un.d_ptr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!elf->buckets || !symnum) {
|
||||
ERROR("%s: Missing or broken DT_HASH", info.dli_fname);
|
||||
} else if (!elf->strtab) {
|
||||
ERROR("%s: Missing DT_STRTAB", info.dli_fname);
|
||||
} else if (!elf->symtab) {
|
||||
ERROR("%s: Missing DT_SYMTAB", info.dli_fname);
|
||||
} else {
|
||||
self_elf = Move(elf);
|
||||
}
|
||||
self_elf = LoadedElf::Create(info.dli_fname, info.dli_fbase);
|
||||
}
|
||||
}
|
||||
|
||||
ElfLoader::~ElfLoader()
|
||||
{
|
||||
LibHandleList list;
|
||||
|
||||
/* Release self_elf */
|
||||
self_elf = nullptr;
|
||||
|
||||
/* Build up a list of all library handles with direct (external) references.
|
||||
* We actually skip system library handles because we want to keep at least
|
||||
* some of these open. Most notably, Mozilla codebase keeps a few libgnome
|
||||
@ -578,10 +546,6 @@ ElfLoader::~ElfLoader()
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Avoid self_elf->base destructor unmapping something that doesn't actually
|
||||
* belong to it. */
|
||||
if (self_elf)
|
||||
self_elf->base.release();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -461,7 +461,7 @@ private:
|
||||
|
||||
/* System loader handle for the library/program containing our code. This
|
||||
* is used to resolve wrapped functions. */
|
||||
mozilla::UniquePtr<BaseElf> self_elf;
|
||||
mozilla::RefPtr<LibHandle> self_elf;
|
||||
|
||||
/* Bookkeeping */
|
||||
typedef std::vector<LibHandle *> LibHandleList;
|
||||
@ -469,6 +469,7 @@ private:
|
||||
|
||||
protected:
|
||||
friend class CustomElf;
|
||||
friend class LoadedElf;
|
||||
/**
|
||||
* Show some stats about Mappables in CustomElfs. The when argument is to
|
||||
* be used by the caller to give an identifier of the when the stats call
|
||||
|
Loading…
Reference in New Issue
Block a user