Bug 1401005 - Handle the case where the relocation addend is not found at the relocation location. r?froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 21 Sep 2017 11:37:30 +0900
changeset 668021 dbe669a18cb8752a608d27509e5a53ec016d5275
parent 667608 a20de99fa3c1ba6287fe47d493a859a4e95120b0
child 732584 414d9f9038b3cba117e79a6341f3622c339288b3
push id80922
push userbmo:mh+mozilla@glandium.org
push dateThu, 21 Sep 2017 02:38:54 +0000
reviewersfroydnj
bugs1401005
milestone57.0a1
Bug 1401005 - Handle the case where the relocation addend is not found at the relocation location. r?froydnj
build/unix/elfhack/elfhack.cpp
--- a/build/unix/elfhack/elfhack.cpp
+++ b/build/unix/elfhack/elfhack.cpp
@@ -619,17 +619,31 @@ int do_relocation_section(Elf *elf, unsi
             }
             new_rels.push_back(*i);
             init_array_reloc = new_rels.size();
         } else if (!(loc.getSection()->getFlags() & SHF_WRITE) || (ELF32_R_TYPE(i->r_info) != rel_type)) {
             // Don't pack relocations happening in non writable sections.
             // Our injected code is likely not to be allowed to write there.
             new_rels.push_back(*i);
         } else {
-            // TODO: check that i->r_addend == *i->r_offset
+            // With Elf_Rel, the value pointed by the relocation offset is the addend.
+            // With Elf_Rela, the addend is in the relocation entry, but the elfhacked
+            // relocation info doesn't contain it. Elfhack relies on the value pointed
+            // by the relocation offset to also contain the addend. Which is true with
+            // BFD ld and gold, but not lld, which leaves that nulled out. So if that
+            // value is nulled out, we update it to the addend.
+            Elf_Addr addr(loc.getBuffer(), entry_sz, elf->getClass(), elf->getData());
+            unsigned int addend = get_addend(&*i, elf);
+            if (addr.value == 0) {
+                addr.value = addend;
+                addr.serialize(const_cast<char*>(loc.getBuffer()), entry_sz, elf->getClass(), elf->getData());
+            } else if (addr.value != addend) {
+                fprintf(stderr, "Relocation addend inconsistent with content. Skipping\n");
+                return -1;
+            }
             if (i->r_offset == relhack_entry.r_offset + relhack_entry.r_info * entry_sz) {
                 relhack_entry.r_info++;
             } else {
                 if (relhack_entry.r_offset)
                     relhack->push_back(relhack_entry);
                 relhack_entry.r_offset = i->r_offset;
                 relhack_entry.r_info = 1;
             }