forked from OSchip/llvm-project
[ARM] Implement static (initial exec) TLS model
This includes handling of R_ARM_TLS_IE32 and R_ARM_TLS_LE32 relocs. Differential Revision: http://reviews.llvm.org/D8353 llvm-svn: 232708
This commit is contained in:
parent
14afb83952
commit
91141e87b1
|
@ -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_TLS_IE32:
|
||||
case R_ARM_TLS_LE32:
|
||||
return (int32_t)read32le(location);
|
||||
case R_ARM_PREL31:
|
||||
return (int32_t)(read32le(location) & 0x7FFFFFFF);
|
||||
|
@ -382,6 +384,34 @@ static void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S,
|
|||
return relocR_ARM_THM_MOV(location, arg);
|
||||
}
|
||||
|
||||
/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P => S + A - P
|
||||
static void relocR_ARM_TLS_IE32(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_TLS_LE32 - S + A - tp => S + A + tpoff
|
||||
static void relocR_ARM_TLS_LE32(uint8_t *location, uint64_t P, uint64_t S,
|
||||
int64_t A, uint64_t tpoff) {
|
||||
uint32_t result = (uint32_t)(S + A + tpoff);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::error_code ARMTargetRelocationHandler::applyRelocation(
|
||||
ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::AtomLayout &atom,
|
||||
const Reference &ref) const {
|
||||
|
@ -455,6 +485,13 @@ std::error_code ARMTargetRelocationHandler::applyRelocation(
|
|||
relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend,
|
||||
addressesThumb);
|
||||
break;
|
||||
case R_ARM_TLS_IE32:
|
||||
relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend);
|
||||
break;
|
||||
case R_ARM_TLS_LE32:
|
||||
relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend,
|
||||
_armLayout.getTPOffset());
|
||||
break;
|
||||
default:
|
||||
return make_unhandled_reloc_error();
|
||||
}
|
||||
|
|
|
@ -21,9 +21,15 @@ template <class ELFT> class ARMTargetLayout;
|
|||
class ARMTargetRelocationHandler final
|
||||
: public TargetRelocationHandler {
|
||||
public:
|
||||
ARMTargetRelocationHandler(ARMTargetLayout<ARMELFType> &layout)
|
||||
: _armLayout(layout) {}
|
||||
|
||||
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
|
||||
const lld::AtomLayout &,
|
||||
const Reference &) const override;
|
||||
|
||||
private:
|
||||
ARMTargetLayout<ARMELFType> &_armLayout;
|
||||
};
|
||||
|
||||
} // end namespace elf
|
||||
|
|
|
@ -28,11 +28,10 @@ using namespace lld;
|
|||
using namespace lld::elf;
|
||||
using namespace llvm::ELF;
|
||||
|
||||
namespace {
|
||||
// ARM B/BL instructions of static relocation veneer.
|
||||
// TODO: consider different instruction set for archs below ARMv5
|
||||
// (one as for Thumb may be used though it's less optimal).
|
||||
const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = {
|
||||
static const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = {
|
||||
0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4]
|
||||
0x00, 0x00, 0x00, 0x00 // <target_symbol_address>
|
||||
};
|
||||
|
@ -40,12 +39,16 @@ const uint8_t Veneer_ARM_B_BL_StaticAtomContent[8] = {
|
|||
// Thumb B/BL instructions of static relocation veneer.
|
||||
// TODO: consider different instruction set for archs above ARMv5
|
||||
// (one as for ARM may be used since it's more optimal).
|
||||
const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = {
|
||||
static const uint8_t Veneer_THM_B_BL_StaticAtomContent[8] = {
|
||||
0x78, 0x47, // bx pc
|
||||
0x00, 0x00, // nop
|
||||
0xfe, 0xff, 0xff, 0xea // b <target_symbol_address>
|
||||
};
|
||||
|
||||
// .got values
|
||||
static const uint8_t ARMGotAtomContent[4] = {0};
|
||||
|
||||
namespace {
|
||||
/// \brief Atoms that hold veneer code.
|
||||
class VeneerAtom : public SimpleELFDefinedAtom {
|
||||
StringRef _section;
|
||||
|
@ -104,6 +107,18 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Atoms that are used by ARM dynamic linking
|
||||
class ARMGOTAtom : public GOTAtom {
|
||||
public:
|
||||
ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
|
||||
|
||||
ArrayRef<uint8_t> rawContent() const override {
|
||||
return llvm::makeArrayRef(ARMGotAtomContent);
|
||||
}
|
||||
|
||||
Alignment alignment() const override { return Alignment(2); }
|
||||
};
|
||||
|
||||
class ELFPassFile : public SimpleFile {
|
||||
public:
|
||||
ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
|
||||
|
@ -129,6 +144,9 @@ template <class Derived> class ARMRelocationPass : public Pass {
|
|||
case R_ARM_THM_JUMP24:
|
||||
static_cast<Derived *>(this)->handleVeneer(atom, ref);
|
||||
break;
|
||||
case R_ARM_TLS_IE32:
|
||||
static_cast<Derived *>(this)->handleTLSIE32(ref);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,7 +154,7 @@ protected:
|
|||
std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) {
|
||||
// Target symbol and relocated place should have different
|
||||
// instruction sets in order a veneer to be generated in between.
|
||||
const auto *target = dyn_cast_or_null<DefinedAtom>(ref.target());
|
||||
const auto *target = dyn_cast<DefinedAtom>(ref.target());
|
||||
if (!target || target->codeModel() == atom.codeModel())
|
||||
return std::error_code();
|
||||
|
||||
|
@ -183,6 +201,32 @@ protected:
|
|||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code handleTLSIE32(const Reference &ref) {
|
||||
if (const auto *target = dyn_cast<DefinedAtom>(ref.target())) {
|
||||
const_cast<Reference &>(ref).setTarget(
|
||||
static_cast<Derived *>(this)->getTLSTPOFF32(target));
|
||||
return std::error_code();
|
||||
}
|
||||
llvm_unreachable("R_ARM_TLS_IE32 reloc targets wrong atom type");
|
||||
}
|
||||
|
||||
/// \brief Create a GOT entry for TLS with reloc type and addend specified.
|
||||
template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0>
|
||||
const GOTAtom *getGOTTLSEntry(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_TLS, 0, da, A);
|
||||
#ifndef NDEBUG
|
||||
g->_name = "__got_tls_";
|
||||
g->_name += da->name();
|
||||
#endif
|
||||
_gotMap[da] = g;
|
||||
_gotVector.push_back(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
public:
|
||||
ARMRelocationPass(const ELFLinkingContext &ctx) : _file(ctx), _ctx(ctx) {}
|
||||
|
||||
|
@ -230,6 +274,10 @@ public:
|
|||
|
||||
// Add all created atoms to the link.
|
||||
uint64_t ordinal = 0;
|
||||
for (auto &got : _gotVector) {
|
||||
got->setOrdinal(ordinal++);
|
||||
mf->addAtom(*got);
|
||||
}
|
||||
for (auto &veneer : _veneerVector) {
|
||||
veneer->setOrdinal(ordinal++);
|
||||
mf->addAtom(*veneer);
|
||||
|
@ -241,9 +289,15 @@ protected:
|
|||
ELFPassFile _file;
|
||||
const ELFLinkingContext &_ctx;
|
||||
|
||||
/// \brief Map Atoms to their GOT entries.
|
||||
llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
|
||||
|
||||
/// \brief Map Atoms to their veneers.
|
||||
llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap;
|
||||
|
||||
/// \brief the list of GOT/PLT atoms
|
||||
std::vector<GOTAtom *> _gotVector;
|
||||
|
||||
/// \brief the list of veneer atoms.
|
||||
std::vector<VeneerAtom *> _veneerVector;
|
||||
};
|
||||
|
@ -297,6 +351,11 @@ public:
|
|||
_veneerVector.push_back(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
/// \brief Create a GOT entry for R_ARM_TLS_TPOFF32 reloc.
|
||||
const GOTAtom *getTLSTPOFF32(const DefinedAtom *da) {
|
||||
return getGOTTLSEntry<R_ARM_TLS_LE32>(da);
|
||||
}
|
||||
};
|
||||
|
||||
} // end of anon namespace
|
||||
|
|
|
@ -18,7 +18,8 @@ using namespace elf;
|
|||
ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context)
|
||||
: _context(context), _armTargetLayout(
|
||||
new ARMTargetLayout<ARMELFType>(context)),
|
||||
_armRelocationHandler(new ARMTargetRelocationHandler()) {}
|
||||
_armRelocationHandler(new ARMTargetRelocationHandler(
|
||||
*_armTargetLayout.get())) {}
|
||||
|
||||
void ARMTargetHandler::registerRelocationNames(Registry ®istry) {
|
||||
registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
|
||||
|
|
|
@ -29,6 +29,26 @@ template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
|
|||
public:
|
||||
ARMTargetLayout(ARMLinkingContext &context)
|
||||
: TargetLayout<ELFT>(context) {}
|
||||
|
||||
uint64_t getTPOffset() {
|
||||
if (_tpOff.hasValue())
|
||||
return *_tpOff;
|
||||
|
||||
for (const auto &phdr : *this->_programHeader) {
|
||||
if (phdr->p_type == llvm::ELF::PT_TLS) {
|
||||
_tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
|
||||
return *_tpOff;
|
||||
}
|
||||
}
|
||||
llvm_unreachable("TLS segment not found");
|
||||
}
|
||||
|
||||
private:
|
||||
// TCB block size of the TLS.
|
||||
enum { TCB_SIZE = 0x8 };
|
||||
|
||||
// Cached value of the TLS offset from the $tp pointer.
|
||||
llvm::Optional<uint64_t> _tpOff;
|
||||
};
|
||||
|
||||
class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> {
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
# Check handling of R_ARM_TLS_IE32 relocation.
|
||||
# RUN: yaml2obj -format=elf -docnum 1 %s > %t-tls.o
|
||||
# RUN: yaml2obj -format=elf -docnum 2 %s > %t-tlsv.o
|
||||
# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
|
||||
# RUN: --noinhibit-exec %t-tls.o %t-tlsv.o -o %t
|
||||
# RUN: llvm-objdump -s -t %t | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .got:
|
||||
# CHECK: 401008 08000000 0c000000
|
||||
# tp_off(i) = 0x08 ^^ ^^ tp_off(j) = 0x0c
|
||||
# tp_off(i) + sizeof(i) = tp_off(j)
|
||||
# 0x08 + 0x04 = 0x0c
|
||||
# CHECK: SYMBOL TABLE:
|
||||
# CHECK: 00400094 g F .text {{[0-9a-f]+}} main
|
||||
# CHECK: 00000000 g .tdata 00000004 i
|
||||
# sizeof(i) = 0x04 ^^
|
||||
# CHECK: 00000004 g .tdata 00000004 j
|
||||
|
||||
# tls.o
|
||||
---
|
||||
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: 80B400AF0C4B7B441B681DEE702FD2580A4B7B441B681DEE701FCB581A44084B7B441B681DEE701FCB585B0013441846BD465DF8047B70472E000000260000001C000000
|
||||
- Name: .rel.text
|
||||
Type: SHT_REL
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000004
|
||||
Info: .text
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000038
|
||||
Symbol: i
|
||||
Type: R_ARM_TLS_IE32
|
||||
- Offset: 0x000000000000003C
|
||||
Symbol: i
|
||||
Type: R_ARM_TLS_IE32
|
||||
- Offset: 0x0000000000000040
|
||||
Symbol: j
|
||||
Type: R_ARM_TLS_IE32
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- 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: i
|
||||
Type: STT_TLS
|
||||
- Name: j
|
||||
Type: STT_TLS
|
||||
|
||||
# tlsv.o
|
||||
---
|
||||
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: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .tdata
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: 05000000FBFFFFFF
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: i
|
||||
Type: STT_TLS
|
||||
Section: .tdata
|
||||
Size: 0x0000000000000004
|
||||
- Name: j
|
||||
Type: STT_TLS
|
||||
Section: .tdata
|
||||
Value: 0x0000000000000004
|
||||
Size: 0x0000000000000004
|
||||
...
|
|
@ -0,0 +1,61 @@
|
|||
# Check handling of R_ARM_TLS_LE32 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 .text:
|
||||
# CHECK: 4000b4 {{[0-9a-f]+}} 08000000
|
||||
# tp_off = 0x000008 ^^
|
||||
# CHECK: SYMBOL TABLE:
|
||||
# CHECK: 00400094 g F .text {{[0-9a-f]+}} main
|
||||
# CHECK: 00000000 g .tdata 00000004 i
|
||||
|
||||
---
|
||||
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: 04B02DE500B08DE2703F1DEE10209FE5023093E70300A0E100D04BE204B09DE41EFF2FE100000000
|
||||
- Name: .rel.text
|
||||
Type: SHT_REL
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000004
|
||||
Info: .text
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000024
|
||||
Symbol: i
|
||||
Type: R_ARM_TLS_LE32
|
||||
Addend: 0
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .tdata
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: '05000000'
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: i
|
||||
Type: STT_TLS
|
||||
Section: .tdata
|
||||
Size: 0x0000000000000004
|
||||
- Name: main
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
...
|
Loading…
Reference in New Issue