Bug 1401005 - Handle the case where the relocation addend is not found at the relocation location. r?froydnj
--- 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;
}