[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:
Adhemerval Zanella 2015-06-17 14:00:12 +00:00
parent f27e441373
commit b19f5cfee6
10 changed files with 132 additions and 26 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}
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();

View File

@ -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) {
/// \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()));
const_cast<Reference &>(ref).setKindValue(R_X86_64_PC32);
}
return std::error_code();
}
/// \brief Create a TLS GOT entry with DTPMOD64/DTPOFF64 dynamic relocations.

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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: }
---

View File

@ -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