[lld] r233383 - [ARM] Handle GOT relocations
Denis Protivensky
dprotivensky at accesssoftek.com
Fri Mar 27 09:29:09 PDT 2015
Author: denis-protivensky
Date: Fri Mar 27 11:29:08 2015
New Revision: 233383
URL: http://llvm.org/viewvc/llvm-project?rev=233383&view=rev
Log:
[ARM] Handle GOT relocations
This includes relocs needed to link against glibc:
R_ARM_BASE_PREL
R_ARM_GOT_BREL
Every reloc is accompanied with a test case.
Added:
lld/trunk/test/elf/ARM/rel-base-prel.test
lld/trunk/test/elf/ARM/rel-got-brel.test
Modified:
lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
Modified: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp?rev=233383&r1=233382&r2=233383&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp Fri Mar 27 11:29:08 2015
@@ -82,6 +82,8 @@ static Reference::Addend readAddend(cons
switch (kindValue) {
case R_ARM_ABS32:
case R_ARM_REL32:
+ case R_ARM_GOT_BREL:
+ case R_ARM_BASE_PREL:
case R_ARM_TLS_IE32:
case R_ARM_TLS_LE32:
return (int32_t)read32le(location);
@@ -257,6 +259,32 @@ static void relocR_ARM_THM_JUMP11(uint8_
applyThumb16Reloc(location, result, 0x7FF);
}
+/// \brief R_ARM_BASE_PREL - B(S) + A - P => S + A - P
+static void relocR_ARM_BASE_PREL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A) {
+ uint32_t result = (uint32_t)(S + A - P);
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
+/// \brief R_ARM_GOT_BREL - GOT(S) + A - GOT_ORG => S + A - GOT_ORG
+static void relocR_ARM_GOT_BREL(uint8_t *location, uint64_t P, uint64_t S,
+ int64_t A, uint64_t GOT_ORG) {
+ uint32_t result = (uint32_t)(S + A - GOT_ORG);
+ DEBUG_WITH_TYPE(
+ "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+ llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
+ llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
+ llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
+ llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
+ applyArmReloc(location, result);
+}
+
/// \brief R_ARM_CALL - ((S + A) | T) - P
static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
int64_t A, bool addressesThumb) {
@@ -561,6 +589,20 @@ std::error_code ARMTargetRelocationHandl
relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend,
_armLayout.getTPOffset());
break;
+ case R_ARM_GOT_BREL:
+ relocR_ARM_GOT_BREL(location, relocVAddress, targetVAddress, addend,
+ _armLayout.getGOTSymAddr());
+ break;
+ case R_ARM_BASE_PREL:
+ // GOT origin is used for NULL symbol and when explicitly specified
+ if (!targetVAddress ||
+ ref.target()->name().equals("_GLOBAL_OFFSET_TABLE_")) {
+ targetVAddress = _armLayout.getGOTSymAddr();
+ } else {
+ llvm_unreachable("Segment-base relative addressing is not supported");
+ }
+ relocR_ARM_BASE_PREL(location, relocVAddress, targetVAddress, addend);
+ break;
case R_ARM_ALU_PC_G0_NC:
relocR_ARM_ALU_PC_G0_NC(location, relocVAddress, targetVAddress, addend);
break;
Modified: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp?rev=233383&r1=233382&r2=233383&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp Fri Mar 27 11:29:08 2015
@@ -178,6 +178,11 @@ template <class Derived> class ARMReloca
case R_ARM_TLS_IE32:
static_cast<Derived *>(this)->handleTLSIE32(ref);
break;
+ case R_ARM_GOT_BREL:
+ static_cast<Derived *>(this)->handleGOT(ref);
+ break;
+ default:
+ break;
}
}
@@ -314,8 +319,35 @@ protected:
return std::error_code();
}
+ /// \brief Create a GOT entry containing 0.
+ const GOTAtom *getNullGOT() {
+ if (!_null) {
+ _null = new (_file._alloc) ARMGOTAtom(_file, ".got.plt");
+#ifndef NDEBUG
+ _null->_name = "__got_null";
+#endif
+ }
+ return _null;
+ }
+
+ const GOTAtom *getGOT(const DefinedAtom *da) {
+ auto got = _gotMap.find(da);
+ if (got != _gotMap.end())
+ return got->second;
+ auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
+ g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0);
+#ifndef NDEBUG
+ g->_name = "__got_";
+ g->_name += da->name();
+#endif
+ _gotMap[da] = g;
+ _gotVector.push_back(g);
+ return g;
+ }
+
public:
- ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
+ ARMRelocationPass(const ELFLinkingContext &ctx)
+ : _file(ctx), _ctx(ctx), _null(nullptr) {}
/// \brief Do the pass.
///
@@ -361,14 +393,18 @@ public:
// Add all created atoms to the link.
uint64_t ordinal = 0;
- for (auto &got : _gotVector) {
- got->setOrdinal(ordinal++);
- mf->addAtom(*got);
- }
for (auto &plt : _pltVector) {
plt->setOrdinal(ordinal++);
mf->addAtom(*plt);
}
+ if (_null) {
+ _null->setOrdinal(ordinal++);
+ mf->addAtom(*_null);
+ }
+ for (auto &got : _gotVector) {
+ got->setOrdinal(ordinal++);
+ mf->addAtom(*got);
+ }
for (auto &veneer : _veneerVector) {
veneer->setOrdinal(ordinal++);
mf->addAtom(*veneer);
@@ -395,6 +431,9 @@ protected:
/// \brief the list of veneer atoms.
std::vector<VeneerAtom *> _veneerVector;
+
+ /// \brief GOT entry that is always 0. Used for undefined weaks.
+ GOTAtom *_null;
};
/// This implements the static relocation model. Meaning GOT and PLT entries are
@@ -451,6 +490,14 @@ public:
const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
}
+
+ std::error_code handleGOT(const Reference &ref) {
+ if (isa<UndefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getNullGOT());
+ else if (const auto *da = dyn_cast<DefinedAtom>(ref.target()))
+ const_cast<Reference &>(ref).setTarget(getGOT(da));
+ return std::error_code();
+ }
};
} // end of anon namespace
Modified: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h?rev=233383&r1=233382&r2=233383&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h Fri Mar 27 11:29:08 2015
@@ -15,20 +15,26 @@
#include "ARMRelocationHandler.h"
#include "DefaultTargetHandler.h"
#include "TargetLayout.h"
-
-#include "lld/Core/Simple.h"
#include "llvm/ADT/Optional.h"
-#include <map>
namespace lld {
namespace elf {
-typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
class ARMLinkingContext;
template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
public:
ARMTargetLayout(ARMLinkingContext &ctx) : TargetLayout<ELFT>(ctx) {}
+ uint64_t getGOTSymAddr() {
+ if (!_gotSymAddr.hasValue()) {
+ auto gotAtomIter = this->findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
+ _gotSymAddr = (gotAtomIter != this->absoluteAtoms().end())
+ ? (*gotAtomIter)->_virtualAddr
+ : 0;
+ }
+ return *_gotSymAddr;
+ }
+
uint64_t getTPOffset() {
if (_tpOff.hasValue())
return *_tpOff;
@@ -46,6 +52,10 @@ private:
// TCB block size of the TLS.
enum { TCB_SIZE = 0x8 };
+private:
+ // Cached value of the GOT origin symbol address.
+ llvm::Optional<uint64_t> _gotSymAddr;
+
// Cached value of the TLS offset from the $tp pointer.
llvm::Optional<uint64_t> _tpOff;
};
Added: lld/trunk/test/elf/ARM/rel-base-prel.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/ARM/rel-base-prel.test?rev=233383&view=auto
==============================================================================
--- lld/trunk/test/elf/ARM/rel-base-prel.test (added)
+++ lld/trunk/test/elf/ARM/rel-base-prel.test Fri Mar 27 11:29:08 2015
@@ -0,0 +1,62 @@
+# Check handling of R_ARM_BASE_PREL relocation.
+# It only works for _GLOBAL_OFFSET_TABLE_ symbol, and returns error
+# for other cases.
+
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 401004 fcffffff
+# offset = -0x4 ^^
+# addr site offset _GOT_
+# 0x401004 + (-0x4) = 0x401000
+# CHECK: SYMBOL TABLE:
+# CHECK: 00401000 g *ABS* {{[0-9a-f]+}} _GLOBAL_OFFSET_TABLE_
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF00231846BD465DF8047B7047
+ - Name: .got
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '00000000'
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '00000000'
+ - Name: .rel.data
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .data
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: _GLOBAL_OFFSET_TABLE_
+ Type: R_ARM_BASE_PREL
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: _GLOBAL_OFFSET_TABLE_
+...
Added: lld/trunk/test/elf/ARM/rel-got-brel.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/ARM/rel-got-brel.test?rev=233383&view=auto
==============================================================================
--- lld/trunk/test/elf/ARM/rel-got-brel.test (added)
+++ lld/trunk/test/elf/ARM/rel-got-brel.test Fri Mar 27 11:29:08 2015
@@ -0,0 +1,64 @@
+# Check handling of R_ARM_GOT_BREL relocation.
+
+# RUN: yaml2obj -format=elf %s > %t-o.o
+# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
+# RUN: --noinhibit-exec %t-o.o -o %t
+# RUN: llvm-objdump -s -t %t | FileCheck %s
+
+# CHECK: Contents of section .got:
+# CHECK-NEXT: 401000 75004000 81004000
+# f_thumb = 0x400075 ^^ ^^ main_thumb = 0x400081
+# CHECK: Contents of section .data:
+# CHECK-NEXT: 401008 00000000 04000000
+# GOT[0] offset = 0x0 ^^ ^^ GOT[1] offset = 0x4
+# CHECK: SYMBOL TABLE:
+# CHECK: 00400074 g F .text {{[0-9a-f]+}} f
+# CHECK: 00400080 g F .text {{[0-9a-f]+}} main
+
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AFBD465DF8047B704780B400AF00231846BD465DF8047B7047
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: '0000000000000000'
+ - Name: .rel.data
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .data
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: f
+ Type: R_ARM_GOT_BREL
+ - Offset: 0x0000000000000004
+ Symbol: main
+ Type: R_ARM_GOT_BREL
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: f
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x000000000000000D
+ - Name: _GLOBAL_OFFSET_TABLE_
+...
More information about the llvm-commits
mailing list