diff options
author | Denis Protivensky <dprotivensky@accesssoftek.com> | 2015-03-27 16:29:08 +0000 |
---|---|---|
committer | Denis Protivensky <dprotivensky@accesssoftek.com> | 2015-03-27 16:29:08 +0000 |
commit | 7eda0225214097f2ca8628dfdbb52213843bb8da (patch) | |
tree | 4ba70dafeacf5da51efd2d6a7d76b588a3da2103 | |
parent | bfbc7b9c41ae8befab24acd9c05c3f9f27e594b6 (diff) | |
download | bcm5719-llvm-7eda0225214097f2ca8628dfdbb52213843bb8da.tar.gz bcm5719-llvm-7eda0225214097f2ca8628dfdbb52213843bb8da.zip |
[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.
llvm-svn: 233383
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp | 42 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp | 57 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h | 18 | ||||
-rw-r--r-- | lld/test/elf/ARM/rel-base-prel.test | 62 | ||||
-rw-r--r-- | lld/test/elf/ARM/rel-got-brel.test | 64 |
5 files changed, 234 insertions, 9 deletions
diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp index 4f436727094..9a96a93f040 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -82,6 +82,8 @@ static Reference::Addend readAddend(const uint8_t *location, 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_t *location, uint64_t P, uint64_t S, 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 ARMTargetRelocationHandler::applyRelocation( 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; diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp index 02bcb559117..c1b5e73dc87 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -178,6 +178,11 @@ template <class Derived> class ARMRelocationPass : public Pass { 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 diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h index 518779984ab..57d24f2bbdb 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -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; }; diff --git a/lld/test/elf/ARM/rel-base-prel.test b/lld/test/elf/ARM/rel-base-prel.test new file mode 100644 index 00000000000..a0111b21969 --- /dev/null +++ b/lld/test/elf/ARM/rel-base-prel.test @@ -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_ +... diff --git a/lld/test/elf/ARM/rel-got-brel.test b/lld/test/elf/ARM/rel-got-brel.test new file mode 100644 index 00000000000..5ad9ec09d15 --- /dev/null +++ b/lld/test/elf/ARM/rel-got-brel.test @@ -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_ +... |