diff options
author | Adhemerval Zanella <azanella@linux.vnet.ibm.com> | 2015-06-17 14:00:12 +0000 |
---|---|---|
committer | Adhemerval Zanella <azanella@linux.vnet.ibm.com> | 2015-06-17 14:00:12 +0000 |
commit | b19f5cfee6cef30eed9d6b384dba8294c53690e5 (patch) | |
tree | 309e5043404ee394c2c643a99b2c92b13b68528c | |
parent | f27e441373dde31ac86f7f11280c357c30c7c243 (diff) | |
download | bcm5719-llvm-b19f5cfee6cef30eed9d6b384dba8294c53690e5.tar.gz bcm5719-llvm-b19f5cfee6cef30eed9d6b384dba8294c53690e5.zip |
[ELF/x86_64] Fix initial-exec TLS access
Current approach for initial-exec in ELF/x86_64 is to create a GOT entry
and change the relocation to R_X86_64_PC32 to be handled as a GOT offfset.
However there are two issues with this approach: 1. the R_X86_64_PC32 is
not really required since the GOT relocation will be handle dynamically and
2. the TLS symbols are not being exported externally and then correct
realocation are not being applied.
This patch fixes the R_X86_64_GOTTPOFF handling by just emitting a
R_X86_64_TPOFF64 dynamically one; it also sets R_X86_64_TPOFF64 to be
handled by runtime one. For second part, the patches uses a similar
strategy used for aarch64, by reimplementing buildDynamicSymbolTable
from X86_64ExecutableWriter and adding the TLS symbols in the dynamic
symbol table.
Some tests had to be adjusted due the now missing R_X86_64_PC32 relocation.
With this test the simple testcase:
* t1.c:
__thread int t0;
__thread int t1;
__thread int t2;
__thread int t3;
* t0.c:
extern __thread int t0;
extern __thread int t1;
extern __thread int t2;
extern __thread int t3;
__thread int t4;
__thread int t5;
__thread int t6;
__thread int t7;
int main ()
{
t0 = 1;
t1 = 2;
t2 = 3;
t3 = 4;
t4 = 5;
t5 = 6;
t6 = 7;
t7 = 8;
printf ("%i %i %i %i\n", t0, t1, t2, t3);
printf ("%i %i %i %i\n", t4, t5, t6, t7);
return 0;
}
Shows correct output for x86_64.
llvm-svn: 239908
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h | 19 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp | 15 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp | 11 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp | 37 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h | 36 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h | 19 | ||||
-rw-r--r-- | lld/test/elf/X86_64/extern-tls.test | 16 | ||||
-rw-r--r-- | lld/test/elf/gottpoff.test | 2 | ||||
-rw-r--r-- | lld/test/elf/tls.test | 2 |
10 files changed, 132 insertions, 26 deletions
diff --git a/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt b/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt index a85d2b50463..36ea839aa67 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt +++ b/lld/lib/ReaderWriter/ELF/X86_64/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_library(lldX86_64ELFTarget X86_64TargetHandler.cpp X86_64RelocationHandler.cpp X86_64RelocationPass.cpp + X86_64SectionChunks.cpp LINK_LIBS lldELF lldReaderWriter diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h index 4cea8945fba..930a2de2a9e 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64ExecutableWriter.h @@ -18,7 +18,7 @@ namespace elf { class X86_64ExecutableWriter : public ExecutableWriter<ELF64LE> { public: X86_64ExecutableWriter(X86_64LinkingContext &ctx, X86_64TargetLayout &layout) - : ExecutableWriter(ctx, layout) {} + : ExecutableWriter(ctx, layout), _targetLayout(layout) {} protected: // Add any runtime files and their atoms to the output @@ -32,6 +32,23 @@ protected: gotFile->addAtom(*new (gotFile->allocator()) DynamicAtom(*gotFile)); result.push_back(std::move(gotFile)); } + + void buildDynamicSymbolTable(const File &file) override { + for (auto sec : this->_layout.sections()) { + if (auto section = dyn_cast<AtomSection<ELF64LE>>(sec)) { + for (const auto &atom : section->atoms()) { + if (_targetLayout.getGOTSection().hasGlobalGOTEntry(atom->_atom)) { + this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(), + atom->_virtualAddr, atom); + } + } + } + } + + ExecutableWriter<ELF64LE>::buildDynamicSymbolTable(file); + } + + X86_64TargetLayout &_targetLayout; }; } // namespace elf diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp index b5f64936aae..d56983d1e38 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp @@ -94,18 +94,14 @@ std::error_code X86_64TargetRelocationHandler::applyRelocation( case R_X86_64_PC16: relocPC16(loc, reloc, target, ref.addend()); break; - case R_X86_64_TPOFF64: case R_X86_64_DTPOFF32: - case R_X86_64_TPOFF32: { + case R_X86_64_TPOFF32: _tlsSize = _layout.getTLSSize(); - if (ref.kindValue() == R_X86_64_TPOFF32 || - ref.kindValue() == R_X86_64_DTPOFF32) { - write32le(loc, target - _tlsSize); - } else { - write64le(loc, target - _tlsSize); - } + write32le(loc, target - _tlsSize); + break; + case R_X86_64_GOTTPOFF: + relocPC32(loc, reloc, target, ref.addend()); break; - } case R_X86_64_TLSGD: { relocPC32(loc, reloc, target, ref.addend()); break; @@ -141,6 +137,7 @@ std::error_code X86_64TargetRelocationHandler::applyRelocation( case R_X86_64_GLOB_DAT: case R_X86_64_DTPMOD64: case R_X86_64_DTPOFF64: + case R_X86_64_TPOFF64: break; default: return make_unhandled_reloc_error(); diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp index 64d46f912d5..1be4b9587dc 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64RelocationPass.cpp @@ -188,11 +188,12 @@ protected: return got->second; } - /// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to - /// the GOT. - void handleGOTTPOFF(const Reference &ref) { - const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target())); - const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32); + /// \brief Create a TPOFF64 GOT entry. + std::error_code handleGOTTPOFF(const Reference &ref) { + if (isa<DefinedAtom>(ref.target())) { + const_cast<Reference &>(ref).setTarget(getGOTTPOFF(ref.target())); + } + return std::error_code(); } /// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations. diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp new file mode 100644 index 00000000000..28eb3e4244b --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp @@ -0,0 +1,37 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.cpp --------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "X86_64SectionChunks.h" +#include "TargetLayout.h" + +namespace lld { +namespace elf { + +X86_64GOTSection::X86_64GOTSection(const ELFLinkingContext &ctx) + : AtomSection<ELF64LE>(ctx, ".got", DefinedAtom::typeGOT, DefinedAtom::permRW_, + TargetLayout<ELF64LE>::ORDER_GOT) { + this->_alignment = 8; +} + +const AtomLayout *X86_64GOTSection::appendAtom(const Atom *atom) { + const DefinedAtom *da = dyn_cast<DefinedAtom>(atom); + + for (const auto &r : *da) { + if (r->kindNamespace() != Reference::KindNamespace::ELF) + continue; + assert(r->kindArch() == Reference::KindArch::x86_64); + if (r->kindValue() == R_X86_64_TPOFF64) + _tlsMap[r->target()] = _tlsMap.size(); + } + + return AtomSection<ELF64LE>::appendAtom(atom); +} + +} // elf +} // lld diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h new file mode 100644 index 00000000000..5208491eee5 --- /dev/null +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h @@ -0,0 +1,36 @@ +//===- lib/ReaderWriter/ELF/X86_64/X86_64SectionChunks.h ----------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_READER_WRITER_ELF_X86_64_X86_64_SECTION_CHUNKS_H +#define LLD_READER_WRITER_ELF_X86_64_X86_64_SECTION_CHUNKS_H + +#include "TargetLayout.h" + +namespace lld { +namespace elf { + +class X86_64GOTSection : public AtomSection<ELF64LE> { +public: + X86_64GOTSection(const ELFLinkingContext &ctx); + + bool hasGlobalGOTEntry(const Atom *a) const { + return _tlsMap.count(a); + } + + const AtomLayout *appendAtom(const Atom *atom) override; + +private: + /// \brief Map TLS Atoms to their GOT entry index. + llvm::DenseMap<const Atom *, std::size_t> _tlsMap; +}; + +} // elf +} // lld + +#endif diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h index 53fc15ff023..6e3e58f8aed 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h @@ -14,20 +14,34 @@ #include "TargetLayout.h" #include "X86_64LinkingContext.h" #include "X86_64RelocationHandler.h" +#include "X86_64SectionChunks.h" #include "lld/Core/Simple.h" namespace lld { namespace elf { + class X86_64TargetLayout : public TargetLayout<ELF64LE> { public: - X86_64TargetLayout(X86_64LinkingContext &ctx) : TargetLayout(ctx) {} + X86_64TargetLayout(X86_64LinkingContext &ctx) : TargetLayout(ctx), + _gotSection(new (this->_allocator) X86_64GOTSection(ctx)) {} + + AtomSection<ELF64LE> * + createSection(StringRef name, int32_t type, + DefinedAtom::ContentPermissions permissions, + TargetLayout<ELF64LE>::SectionOrder order) override { + if (type == DefinedAtom::typeGOT && name == ".got") + return _gotSection; + return TargetLayout<ELF64LE>::createSection(name, type, permissions, order); + } void finalizeOutputSectionLayout() override { sortOutputSectionByPriority<ELF64LE>(".init_array"); sortOutputSectionByPriority<ELF64LE>(".fini_array"); } + const X86_64GOTSection &getGOTSection() const { return *_gotSection; } + private: uint32_t getPriority(StringRef sectionName) const { StringRef priority = sectionName.drop_front().rsplit('.').second; @@ -55,6 +69,9 @@ private: return getPriority(lhsName) < getPriority(rhsName); }); } + +private: + X86_64GOTSection *_gotSection; }; class X86_64TargetHandler : public TargetHandler { diff --git a/lld/test/elf/X86_64/extern-tls.test b/lld/test/elf/X86_64/extern-tls.test index 022e86866f8..16a0d5544aa 100644 --- a/lld/test/elf/X86_64/extern-tls.test +++ b/lld/test/elf/X86_64/extern-tls.test @@ -3,14 +3,14 @@ RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/externtls.x86-64 -static \ RUN: --output-filetype=yaml --noinhibit-exec | FileCheck %s -check-prefix=CHECKGOT +# Currently x86_64 relocation pass handles the R_X86_64_GOTTPOFF by +# creatng R_X86_64_TPOFF64 dynamic ones. For output yaml, this is +# not changed. - name: __got_tls_extern_tls -CHECKGOT: type: got -CHECKGOT: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ] -CHECKGOT: alignment: 8 -CHECKGOT: section-choice: custom-required -CHECKGOT: section-name: .got -CHECKGOT: permissions: rw- +CHECKGOT: alignment: 4 +CHECKGOT: section-name: .text CHECKGOT: references: -CHECKGOT: - kind: R_X86_64_TPOFF64 -CHECKGOT: offset: 0 +CHECKGOT: - kind: R_X86_64_GOTTPOFF +CHECKGOT: offset: 7 CHECKGOT: target: extern_tls +CHECKGOT: addend: -4 diff --git a/lld/test/elf/gottpoff.test b/lld/test/elf/gottpoff.test index 9841ee1453d..4a109504dc8 100644 --- a/lld/test/elf/gottpoff.test +++ b/lld/test/elf/gottpoff.test @@ -7,7 +7,7 @@ #RUN: llvm-readobj -r %t | FileCheck %s # #CHECK: Section (5) .rela.dyn { -#CHECK: 0x401098 R_X86_64_TPOFF64 - 0x0 +#CHECK: 0x401098 R_X86_64_TPOFF64 tls2 0x0 #CHECK: } --- diff --git a/lld/test/elf/tls.test b/lld/test/elf/tls.test index 038889406b6..ff37cadd3d8 100644 --- a/lld/test/elf/tls.test +++ b/lld/test/elf/tls.test @@ -22,7 +22,7 @@ YAML: offset: 25 YAML: target: tls2 YAML: name: GOTTPOFF -YAML: kind: R_X86_64_PC32 +YAML: kind: R_X86_64_GOTTPOFF YAML: target: [[GOTNAME:[a-zA-Z0-9_]+]] YAML: type: got |