Bug 956398 - Support text relocations in the custom linker. r=nfroyd, a=bajaj
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -59,16 +59,23 @@ void debug_phdr(const char *type, const
"memsz: 0x%08" PRIxAddr ", "
"offset: 0x%08" PRIxAddr ", "
"flags: %c%c%c)",
type, phdr->p_vaddr, phdr->p_filesz, phdr->p_memsz,
phdr->p_offset, phdr->p_flags & PF_R ? 'r' : '-',
phdr->p_flags & PF_W ? 'w' : '-', phdr->p_flags & PF_X ? 'x' : '-');
}
+static int p_flags_to_mprot(Word flags)
+{
+ return ((flags & PF_X) ? PROT_EXEC : 0) |
+ ((flags & PF_W) ? PROT_WRITE : 0) |
+ ((flags & PF_R) ? PROT_READ : 0);
+}
+
void
__void_stub(void)
{
}
} /* anonymous namespace */
/**
@@ -220,16 +227,38 @@ CustomElf::Load(Mappable *mappable, cons
elf->l_addr = elf->base;
elf->l_name = elf->GetPath();
elf->l_ld = elf->GetPtr<Dyn>(dyn->p_vaddr);
ElfLoader::Singleton.Register(elf);
if (!elf->InitDyn(dyn))
return nullptr;
+ if (elf->has_text_relocs) {
+ for (std::vector<const Phdr *>::iterator it = pt_loads.begin();
+ it < pt_loads.end(); ++it)
+ mprotect(PageAlignedPtr(elf->GetPtr((*it)->p_vaddr)),
+ PageAlignedEndPtr((*it)->p_memsz),
+ p_flags_to_mprot((*it)->p_flags) | PROT_WRITE);
+ }
+
+ if (!elf->Relocate() || !elf->RelocateJumps())
+ return nullptr;
+
+ if (elf->has_text_relocs) {
+ for (std::vector<const Phdr *>::iterator it = pt_loads.begin();
+ it < pt_loads.end(); ++it)
+ mprotect(PageAlignedPtr(elf->GetPtr((*it)->p_vaddr)),
+ PageAlignedEndPtr((*it)->p_memsz),
+ p_flags_to_mprot((*it)->p_flags));
+ }
+
+ if (!elf->CallInit())
+ 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
elf->stats("oneLibLoaded");
DEBUG_LOG("CustomElf::Load(\"%s\", 0x%x) = %p", path, flags,
@@ -418,19 +447,17 @@ CustomElf::stats(const char *when) const
bool
CustomElf::LoadSegment(const Phdr *pt_load) const
{
if (pt_load->p_type != PT_LOAD) {
DEBUG_LOG("%s: Elf::LoadSegment only takes PT_LOAD program headers", GetPath());
return false;;
}
- int prot = ((pt_load->p_flags & PF_X) ? PROT_EXEC : 0) |
- ((pt_load->p_flags & PF_W) ? PROT_WRITE : 0) |
- ((pt_load->p_flags & PF_R) ? PROT_READ : 0);
+ int prot = p_flags_to_mprot(pt_load->p_flags);
/* Mmap at page boundary */
Addr align = PageSize();
Addr align_offset;
void *mapped, *where;
do {
align_offset = pt_load->p_vaddr - AlignedPtr(pt_load->p_vaddr, align);
where = GetPtr(pt_load->p_vaddr - align_offset);
@@ -544,18 +571,18 @@ CustomElf::InitDyn(const Phdr *pt_dyn)
case DT_SYMENT:
debug_dyn("DT_SYMENT", dyn);
if (dyn->d_un.d_val != sizeof(Sym)) {
LOG("%s: Unsupported DT_SYMENT", GetPath());
return false;
}
break;
case DT_TEXTREL:
- LOG("%s: Text relocations are not supported", GetPath());
- return false;
+ has_text_relocs = true;
+ break;
case DT_STRSZ: /* Ignored */
debug_dyn("DT_STRSZ", dyn);
break;
case UNSUPPORTED_RELOC():
case UNSUPPORTED_RELOC(SZ):
case UNSUPPORTED_RELOC(ENT):
LOG("%s: Unsupported relocations", GetPath());
return false;
@@ -615,18 +642,17 @@ CustomElf::InitDyn(const Phdr *pt_dyn)
return false;
}
break;
case DT_FLAGS:
{
Addr flags = dyn->d_un.d_val;
/* Treat as a DT_TEXTREL tag */
if (flags & DF_TEXTREL) {
- LOG("%s: Text relocations are not supported", GetPath());
- return false;
+ has_text_relocs = true;
}
/* we can treat this like having a DT_SYMBOLIC tag */
flags &= ~DF_SYMBOLIC;
if (flags)
LOG("%s: Warning: unhandled flags #%" PRIxAddr" not handled",
GetPath(), flags);
}
break;
@@ -672,18 +698,17 @@ CustomElf::InitDyn(const Phdr *pt_dyn)
const char *name = strtab.GetStringAt(dt_needed[i]);
RefPtr<LibHandle> handle =
ElfLoader::Singleton.Load(name, RTLD_GLOBAL | RTLD_LAZY, this);
if (!handle)
return false;
dependencies.push_back(handle);
}
- /* Finish initialization */
- return Relocate() && RelocateJumps() && CallInit();
+ return true;
}
bool
CustomElf::Relocate()
{
DEBUG_LOG("Relocate %s @%p", GetPath(), static_cast<void *>(base));
uint32_t symtab_index = (uint32_t) -1;
void *symptr = nullptr;
--- a/mozglue/linker/CustomElf.h
+++ b/mozglue/linker/CustomElf.h
@@ -71,17 +71,22 @@ private:
* in the Elf object.
*/
void *GetSymbolPtrInDeps(const char *symbol) const;
/**
* Private constructor
*/
CustomElf(Mappable *mappable, const char *path)
- : LibHandle(path), mappable(mappable), init(0), fini(0), initialized(false)
+ : LibHandle(path)
+ , mappable(mappable)
+ , init(0)
+ , fini(0)
+ , initialized(false)
+ , has_text_relocs(false)
{ }
/**
* Returns a pointer relative to the base address where the library is
* loaded.
*/
void *GetPtr(const Elf::Addr offset) const
{
@@ -188,15 +193,17 @@ private:
Elf::Addr init, fini;
/* List of initialization and destruction functions
* (.init_array/.fini_array) */
Array<void *> init_array, fini_array;
bool initialized;
+ bool has_text_relocs;
+
#ifdef __ARM_EABI__
/* ARM.exidx information used by FindExidx */
Array<uint32_t[2]> arm_exidx;
#endif
};
#endif /* CustomElf_h */