[ELF] Replace local dynamic tls access with direct access.

llvm-svn: 174425
This commit is contained in:
Michael J. Spencer 2013-02-05 19:14:07 +00:00
parent a5a9ec5755
commit e6ab9f80a7
5 changed files with 58 additions and 3 deletions

View File

@ -61,6 +61,8 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom(); uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
switch (ref.kind()) { switch (ref.kind()) {
case R_X86_64_NONE:
break;
case R_X86_64_64: case R_X86_64_64:
reloc64(location, relocVAddress, targetVAddress, ref.addend()); reloc64(location, relocVAddress, targetVAddress, ref.addend());
break; break;
@ -74,6 +76,7 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
reloc32S(location, relocVAddress, targetVAddress, ref.addend()); reloc32S(location, relocVAddress, targetVAddress, ref.addend());
break; break;
case R_X86_64_TPOFF64: case R_X86_64_TPOFF64:
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32: { case R_X86_64_TPOFF32: {
// Get the start and end of the TLS segment. // Get the start and end of the TLS segment.
if (_tlsSize == 0) { if (_tlsSize == 0) {
@ -88,7 +91,7 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
if (tbss) if (tbss)
_tlsSize += tbss->memSize(); _tlsSize += tbss->memSize();
} }
if (ref.kind() == R_X86_64_TPOFF32) { if (ref.kind() == R_X86_64_TPOFF32 || ref.kind() == R_X86_64_DTPOFF32) {
int32_t result = (int32_t)(targetVAddress - _tlsSize); int32_t result = (int32_t)(targetVAddress - _tlsSize);
*reinterpret_cast<llvm::support::little32_t *>(location) = result; *reinterpret_cast<llvm::support::little32_t *>(location) = result;
} else { } else {
@ -96,6 +99,13 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
*reinterpret_cast<llvm::support::little64_t *>(location) = result; *reinterpret_cast<llvm::support::little64_t *>(location) = result;
} }
break; break;
case R_X86_64_TLSLD:
// Rewrite to move %fs:0 into %rax. Technically we should verify that the
// next relocation is a PC32 to __tls_get_addr...
static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
0x00, 0x00, 0x00, 0x00 };
std::memcpy(location - 3, instr, sizeof(instr));
break;
} }
// Runtime only relocations. Ignore here. // Runtime only relocations. Ignore here.
case R_X86_64_IRELATIVE: case R_X86_64_IRELATIVE:
@ -143,9 +153,35 @@ public:
return ArrayRef<uint8_t>(); return ArrayRef<uint8_t>();
} }
}; };
class TLSGETADDRAtom : public SimpleDefinedAtom {
public:
TLSGETADDRAtom(const File &f) : SimpleDefinedAtom(f) {}
virtual StringRef name() const { return "__tls_get_addr"; }
virtual Scope scope() const { return scopeGlobal; }
virtual Merge merge() const { return mergeAsWeak; }
virtual SectionChoice sectionChoice() const { return sectionCustomRequired; }
virtual StringRef customSectionName() const { return ".text"; }
virtual ContentType contentType() const { return typeCode; }
virtual uint64_t size() const { return 0; }
virtual ContentPermissions permissions() const { return permR_X; }
virtual Alignment alignment() const { return Alignment(0); }
virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
};
} // end anon namespace } // end anon namespace
void X86_64TargetHandler::addFiles(InputFiles &f) { void X86_64TargetHandler::addFiles(InputFiles &f) {
_gotFile.addAtom(*new (_gotFile._alloc) GLOBAL_OFFSET_TABLEAtom(_gotFile)); _gotFile.addAtom(*new (_gotFile._alloc) GLOBAL_OFFSET_TABLEAtom(_gotFile));
_gotFile.addAtom(*new (_gotFile._alloc) TLSGETADDRAtom(_gotFile));
f.appendFile(_gotFile); f.appendFile(_gotFile);
} }

View File

@ -137,8 +137,12 @@ class GOTPLTPass LLVM_FINAL : public Pass {
const DefinedAtom *da = dyn_cast_or_null<const DefinedAtom>(ref.target()); const DefinedAtom *da = dyn_cast_or_null<const DefinedAtom>(ref.target());
switch (ref.kind()) { switch (ref.kind()) {
case R_X86_64_PLT32: case R_X86_64_PLT32:
// Static code doesn't need PLTs. // __tls_get_addr is handled elsewhere.
const_cast<Reference &>(ref).setKind(R_X86_64_PC32); if (ref.target() && ref.target()->name() == "__tls_get_addr")
const_cast<Reference &>(ref).setKind(R_X86_64_NONE);
else
// Static code doesn't need PLTs.
const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
break; break;
case R_X86_64_PC32: // IFUNC case R_X86_64_PC32: // IFUNC
if (da && da->contentType() == DefinedAtom::typeResolver) if (da && da->contentType() == DefinedAtom::typeResolver)

View File

@ -17,6 +17,15 @@ GOTTPOFF:
movl %fs:0(%rax), %eax movl %fs:0(%rax), %eax
ret ret
.text
.globl TLSLD
.type TLSLD,@function
TLSLD:
leaq tls0@tlsld(%rip), %rdi
call __tls_get_addr@plt
leaq tls0@dtpoff(%rax), %rax
ret
.type tls0,@object # @tls0 .type tls0,@object # @tls0
.section .tbss,"awT",@nobits .section .tbss,"awT",@nobits
.globl tls0 .globl tls0

Binary file not shown.

View File

@ -26,8 +26,14 @@ YAML: type: got
YAML: kind: R_X86_64_TPOFF64 YAML: kind: R_X86_64_TPOFF64
YAML: target: tls2 YAML: target: tls2
// main
CHECK: addl %fs:-4 CHECK: addl %fs:-4
CHECK: addl %fs:-8 CHECK: addl %fs:-8
CHECK: addl %fs:-12 CHECK: addl %fs:-12
// GOTTPOFF
CHECK: movq {{[0-9]+}}(%rip) CHECK: movq {{[0-9]+}}(%rip)
// TLSLD
CHECK: movq %fs:0, %rax
CHECK: leaq -8(%rax), %rax