This is an archive of the discontinued LLVM Phabricator instance.

ELF/ARM: Ignore R_ARM_V4BX for ARMv4 but allow linking
AbandonedPublic

Authored by zatrazz on Apr 21 2015, 11:22 AM.

Details

Summary

This patch allow the ARM relocation R_ARM_V4BX to be processed by lld,
although it is not really handled in the static relocation code. The
relocation is in the form:

Relocation section '.rel.text' at offset 0x428 contains 4 entries:
Offset Info Type Sym.Value Sym. Name
00000014 00000028 R_ARM_V4BX

Meaning it does have a direct target, but rather references to an absolute
section *ABS* (in this exemple to the .text segment itself). It makes the
target Atom after file parse to not have a associated pointer and thus
generating a derrefence NULL point in ELFFile<ELFT>::findAtom. Current
approach is just ignore and return nullptr in such cases.

The problem relies that default GCC configuration
for arm-linux-gnueabi{hf} emits the relocation for the asm:

.syntax unified
.arm

.p2align 2
.type fn, %function
fn:

ldr r3, .LGOT
ldr r2, .LGOT+4

.LPIC:

add r3, pc, r3
ldr r2, [r3, r2]
cmp r2, #0
bxeq lr
b __start__

.LGOT:
.word _GLOBAL_OFFSET_TABLE_-(.LPIC+8)

.word start(GOT)

But only with the option -march=armv4 (which is the default GCC configuration).
For arm5 and forward the relocation is not created. This a special relocation
(defined miscellaneous for ARM) that instruct the linker to replace the bx
instruction into a mov. GNU linker has some options related to which substitution
it can create for such cases.

With this patch I can dynamically link an application against a GLIBC
arm-linux-gnueabi system configured with default GCC.

Diff Detail

Event Timeline

zatrazz updated this revision to Diff 24150.Apr 21 2015, 11:22 AM
zatrazz retitled this revision from to ELF/ARM: Ignore R_ARM_V4BX for ARMv4 but allow linking.
zatrazz updated this object.
zatrazz edited the test plan for this revision. (Show Details)
zatrazz added reviewers: ruiu, shankar.easwaran.
zatrazz added a project: lld.
zatrazz added subscribers: Unknown Object (MLST), lld.
ruiu added inline comments.Apr 21 2015, 12:47 PM
lib/ReaderWriter/ELF/ELFFile.cpp
41
if (Atom *target = _symbolToAtomMapping.lookup(targetSym)) {
52

When it reaches here, target can be null, no?

Indeed, I though the testcase should catch the same case I was originally testing, but seems it is not stressing correctly this code path. I see the best approach is in fact to make the target Atom reference to point to itself instead to an undefined one (which will trigger an assert of nameless undefined Atom and later failure of linking):

diff --git a/lib/ReaderWriter/ELF/ELFFile.cpp b/lib/ReaderWriter/ELF/ELFFile.cpp
index ab2ec60..8fe2d30 100644

  • a/lib/ReaderWriter/ELF/ELFFile.cpp

+++ b/lib/ReaderWriter/ELF/ELFFile.cpp
@@ -36,8 +36,15 @@ std::error_code ELFFile<ELFT>::isCompatible(const MemoryBuffer &mb,
template <typename ELFT>
Atom *ELFFile<ELFT>::findAtom(const Elf_Sym *sourceSym,

const Elf_Sym *targetSym) {

+ StringRef targetName;
+

// Return the atom for targetSym if we can do so.
Atom *target = _symbolToAtomMapping.lookup(targetSym);

+ if (!target)
+ Some realocations (R_ARM_V4BX) do not have a defined
+
target. For this cases make it points to itself.
+ target = _symbolToAtomMapping.lookup(sourceSym);
+

if (target->definition() != Atom::definitionRegular)
  return target;
Atom::Scope scope = llvm::cast<DefinedAtom>(target)->scope();

@@ -47,7 +54,7 @@ Atom *ELFFile<ELFT>::findAtom(const Elf_Sym *sourceSym,

  return target;

// Otherwise, create a new undefined symbol and returns it.
  • StringRef targetName = target->name();

+ targetName = target->name();

auto it = _undefAtomsForGroupChild.find(targetName);
if (it != _undefAtomsForGroupChild.end())
  return it->getValue();

What do you think?

zatrazz abandoned this revision.Apr 24 2015, 10:11 AM

I will repost with the previous changes.