[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
This commit is contained in:
parent
f27e441373
commit
b19f5cfee6
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: }
|
||||
|
||||
---
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue