[ELF/x86] Implemented R_386_TLS_LE_32, R_386_TLS_LE relocations.

This patch implements next relocations:
R_386_TLS_LE - Negative offset relative to static TLS (GNU version).
R_386_TLS_LE_32 - Offset relative to static TLS block.

These ones are created when using next code sequences:
* @tpoff - The operator must be used to compute an immediate value. The linker will report
an error if the referenced variable is not defined or it is not code for the executable
itself. No GOT entry is created in this case.
* @ntpoff Calculate the negative offset of the variable it is added to relative to the static TLS block.
The operator must be used to compute an immediate value. The linker will report
an error if the referenced variable is not defined or it is not code for the executable
itself. No GOT entry is created in this case.

Information was found in Ulrich Drepper, ELF Handling For Thread-Local Storage, http://www.akkadia.org/drepper/tls.pdf, (6.2, p76)

Differential revision: http://reviews.llvm.org/D14930

llvm-svn: 254090
This commit is contained in:
George Rimar 2015-11-25 20:41:53 +00:00
parent 207c13f254
commit d23970f778
6 changed files with 103 additions and 5 deletions

View File

@ -151,6 +151,8 @@ void InputSectionBase<ELFT>::relocate(
} else if (!Target->relocNeedsCopy(Type, Body) &&
isa<SharedSymbol<ELFT>>(Body)) {
continue;
} else if (Target->isTlsDynReloc(Type)) {
continue;
}
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
SymVA + getAddend<ELFT>(RI));

View File

@ -241,7 +241,8 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
Config->Mips64EL);
else
P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
NeedsCopy ? Target->getCopyReloc() : Type,
NeedsCopy ? Target->getCopyReloc()
: Target->getDynReloc(Type),
Config->Mips64EL);
} else {
P->setSymbolAndType(0, Target->getRelativeReloc(), Config->Mips64EL);

View File

@ -46,6 +46,8 @@ namespace {
class X86TargetInfo final : public TargetInfo {
public:
X86TargetInfo();
unsigned getDynReloc(unsigned Type) const override;
bool isTlsDynReloc(unsigned Type) const override;
void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr) const override;
@ -62,6 +64,7 @@ class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
unsigned getPltRefReloc(unsigned Type) const override;
bool isTlsDynReloc(unsigned Type) const override;
void writeGotPltHeaderEntries(uint8_t *Buf) const override;
void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
@ -182,6 +185,20 @@ X86TargetInfo::X86TargetInfo() {
PltReloc = R_386_JUMP_SLOT;
}
unsigned X86TargetInfo::getDynReloc(unsigned Type) const {
if (Type == R_386_TLS_LE)
return R_386_TLS_TPOFF;
if (Type == R_386_TLS_LE_32)
return R_386_TLS_TPOFF32;
return Type;
}
bool X86TargetInfo::isTlsDynReloc(unsigned Type) const {
if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32)
return Config->Shared;
return false;
}
void X86TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr) const {}
@ -225,6 +242,12 @@ void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
case R_386_32:
add32le(Loc, SA);
break;
case R_386_TLS_LE:
write32le(Loc, SA - Out<ELF32LE>::TlsPhdr->p_memsz);
break;
case R_386_TLS_LE_32:
write32le(Loc, Out<ELF32LE>::TlsPhdr->p_memsz - SA);
break;
default:
error("unrecognized reloc " + Twine(Type));
}
@ -242,7 +265,6 @@ X86_64TargetInfo::X86_64TargetInfo() {
TlsGlobalDynamicReloc = R_X86_64_TLSGD;
TlsModuleIndexReloc = R_X86_64_DTPMOD64;
TlsOffsetReloc = R_X86_64_DTPOFF64;
TlsPcRelGotReloc = R_X86_64_GOTTPOFF;
LazyRelocations = true;
PltEntrySize = 16;
PltZeroEntrySize = 16;
@ -300,6 +322,10 @@ bool X86_64TargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
relocNeedsPlt(Type, S);
}
bool X86_64TargetInfo::isTlsDynReloc(unsigned Type) const {
return Type == R_X86_64_GOTTPOFF;
}
unsigned X86_64TargetInfo::getPltRefReloc(unsigned Type) const {
if (Type == R_X86_64_PLT32)
return R_X86_64_PC32;

View File

@ -28,7 +28,6 @@ public:
unsigned getPltReloc() const { return PltReloc; }
unsigned getRelativeReloc() const { return RelativeReloc; }
unsigned getTlsGotReloc() const { return TlsGotReloc; }
unsigned getTlsPcRelGotReloc() const { return TlsPcRelGotReloc; }
bool isTlsLocalDynamicReloc(unsigned Type) const {
return Type == TlsLocalDynamicReloc;
}
@ -42,6 +41,8 @@ public:
bool supportsLazyRelocations() const { return LazyRelocations; }
unsigned getGotHeaderEntriesNum() const { return GotHeaderEntriesNum; }
unsigned getGotPltHeaderEntriesNum() const { return GotPltHeaderEntriesNum; }
virtual unsigned getDynReloc(unsigned Type) const { return Type; }
virtual bool isTlsDynReloc(unsigned Type) const { return false; }
virtual unsigned getGotRefReloc(unsigned Type) const;
virtual unsigned getPltRefReloc(unsigned Type) const;
virtual void writeGotHeaderEntries(uint8_t *Buf) const;
@ -84,7 +85,6 @@ protected:
unsigned TlsGlobalDynamicReloc = 0;
unsigned TlsModuleIndexReloc;
unsigned TlsOffsetReloc;
unsigned TlsPcRelGotReloc = 0;
unsigned PltEntrySize = 8;
unsigned PltZeroEntrySize = 0;
unsigned GotHeaderEntriesNum = 0;

View File

@ -229,7 +229,7 @@ void Writer<ELFT>::scanRelocs(
continue;
}
if ((Body && Body->isTLS()) && Type != Target->getTlsPcRelGotReloc())
if ((Body && Body->isTLS()) && !Target->isTlsDynReloc(Type))
continue;
bool NeedsGot = false;

69
lld/test/ELF/tls-i686.s Normal file
View File

@ -0,0 +1,69 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t
// RUN: ld.lld %t -o %tout
// RUN: ld.lld %t -shared -o %tsharedout
// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
// RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC
// RUN: llvm-objdump -d %tsharedout | FileCheck %s --check-prefix=DISSHARED
// RUN: llvm-readobj -r %tsharedout | FileCheck %s --check-prefix=RELOCSHARED
.section ".tdata", "awT", @progbits
.globl var
.globl var1
var:
.long 0
var1:
.long 1
.text
.global _start
_start:
movl $var@tpoff, %edx
movl %gs:0, %ecx
subl %edx, %eax
movl $var1@tpoff, %edx
movl %gs:0, %ecx
subl %edx, %eax
movl %gs:0, %ecx
leal var@ntpoff(%ecx), %eax
movl %gs:0, %ecx
leal var1@ntpoff(%ecx), %eax
// DIS: Disassembly of section .text:
// DIS-NEXT: _start:
// DIS-NEXT: 11000: ba 08 00 00 00 movl $8, %edx
// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DIS-NEXT: 1100c: 29 d0 subl %edx, %eax
// DIS-NEXT: 1100e: ba 04 00 00 00 movl $4, %edx
// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DIS-NEXT: 1101a: 29 d0 subl %edx, %eax
// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DIS-NEXT: 11023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax
// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DIS-NEXT: 11030: 8d 81 fc ff ff ff leal -4(%ecx), %eax
// RELOC: Relocations [
// RELOC-NEXT: ]
// DISSHARED: Disassembly of section .text:
// DISSHARED-NEXT: _start:
// DISSHARED-NEXT: 1000: ba 00 00 00 00 movl $0, %edx
// DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DISSHARED-NEXT: 100c: 29 d0 subl %edx, %eax
// DISSHARED-NEXT: 100e: ba 00 00 00 00 movl $0, %edx
// DISSHARED-NEXT: 1013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DISSHARED-NEXT: 101a: 29 d0 subl %edx, %eax
// DISSHARED-NEXT: 101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DISSHARED-NEXT: 1023: 8d 81 00 00 00 00 leal (%ecx), %eax
// DISSHARED-NEXT: 1029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
// DISSHARED-NEXT: 1030: 8d 81 00 00 00 00 leal (%ecx), %eax
// RELOCSHARED: Relocations [
// RELOCSHARED-NEXT: Section (4) .rel.dyn {
// RELOCSHARED-NEXT: 0x1001 R_386_TLS_TPOFF32 var 0x0
// RELOCSHARED-NEXT: 0x100F R_386_TLS_TPOFF32 var1 0x0
// RELOCSHARED-NEXT: 0x1025 R_386_TLS_TPOFF var 0x0
// RELOCSHARED-NEXT: 0x1032 R_386_TLS_TPOFF var1 0x0
// RELOCSHARED-NEXT: }
// RELOCSHARED-NEXT: ]