summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp2
-rw-r--r--lld/ELF/OutputSections.cpp3
-rw-r--r--lld/ELF/Target.cpp28
-rw-r--r--lld/ELF/Target.h4
-rw-r--r--lld/ELF/Writer.cpp2
-rw-r--r--lld/test/ELF/tls-i686.s69
6 files changed, 103 insertions, 5 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index dd5eb310387..8fafec3211a 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -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));
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index f8ea29f068d..6563b1a61ca 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -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);
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 33cea220a37..6c0a2224cd5 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -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;
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index c8b75425a6c..34b95e98625 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -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;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index fba35fbb0ce..626f29f5d73 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -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;
diff --git a/lld/test/ELF/tls-i686.s b/lld/test/ELF/tls-i686.s
new file mode 100644
index 00000000000..62940d6cd16
--- /dev/null
+++ b/lld/test/ELF/tls-i686.s
@@ -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: ]
OpenPOWER on IntegriCloud