From d23970f7782d122e7a85cf18c5b37a3e96203c0e Mon Sep 17 00:00:00 2001 From: George Rimar Date: Wed, 25 Nov 2015 20:41:53 +0000 Subject: [PATCH] [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 --- lld/ELF/InputSection.cpp | 2 ++ lld/ELF/OutputSections.cpp | 3 +- lld/ELF/Target.cpp | 28 +++++++++++++++- lld/ELF/Target.h | 4 +-- lld/ELF/Writer.cpp | 2 +- lld/test/ELF/tls-i686.s | 69 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 lld/test/ELF/tls-i686.s diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index dd5eb3103876..8fafec3211a3 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -151,6 +151,8 @@ void InputSectionBase::relocate( } else if (!Target->relocNeedsCopy(Type, Body) && isa>(Body)) { continue; + } else if (Target->isTlsDynReloc(Type)) { + continue; } Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA + getAddend(RI)); diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index f8ea29f068d2..6563b1a61cac 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -241,7 +241,8 @@ template void RelocationSection::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 33cea220a377..6c0a2224cd58 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::TlsPhdr->p_memsz); + break; + case R_386_TLS_LE_32: + write32le(Loc, Out::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 c8b75425a6ca..34b95e986256 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 fba35fbb0ce2..626f29f5d739 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -229,7 +229,7 @@ void Writer::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 000000000000..62940d6cd164 --- /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: ]