Bug 956398 - Support text relocations in the custom linker. r=nfroyd, a=bajaj
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 16 Jan 2014 09:13:42 +0900
changeset 175948 a57e9a4224f2b628d0fe3b6a86ceca2fccddbe96
parent 175947 243d1045401aa255d0588f13d8c78586ea361cf0
child 175949 37f5ef8394b12b17a81001255bd83b244f894bd7
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnfroyd, bajaj
bugs956398
milestone28.0a2
Bug 956398 - Support text relocations in the custom linker. r=nfroyd, a=bajaj
mozglue/linker/CustomElf.cpp
mozglue/linker/CustomElf.h
--- 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 */