diff options
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Atoms.h | 6 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/DefaultLayout.h | 6 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/File.h | 3 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/HeaderChunks.h | 67 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/SectionChunks.h | 14 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/SegmentChunks.h | 2 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp | 18 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h | 5 | ||||
| -rw-r--r-- | lld/test/elf/Inputs/tls.c | 11 | ||||
| -rw-r--r-- | lld/test/elf/Inputs/tls.x86-64 | bin | 0 -> 1600 bytes | |||
| -rw-r--r-- | lld/test/elf/tls.test | 8 |
11 files changed, 113 insertions, 27 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Atoms.h b/lld/lib/ReaderWriter/ELF/Atoms.h index cd6a1c9275f..a7534e37f50 100644 --- a/lld/lib/ReaderWriter/ELF/Atoms.h +++ b/lld/lib/ReaderWriter/ELF/Atoms.h @@ -253,6 +253,12 @@ public: return elfAtomHandler.contentType(this); } + if (_section->sh_flags == + (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_TLS)) { + return _section->sh_type == llvm::ELF::SHT_NOBITS ? typeTLVInitialZeroFill + : typeTLVInitialData; + } + if (_symbol->getType() == llvm::ELF::STT_GNU_IFUNC) return typeResolver; diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h index 326019f9a31..76e55e2c9d8 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ b/lld/lib/ReaderWriter/ELF/DefaultLayout.h @@ -291,7 +291,11 @@ Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder( return ORDER_GOT; case DefinedAtom::typeStub: return ORDER_PLT; - + + case DefinedAtom::typeTLVInitialData: + return ORDER_TDATA; + case DefinedAtom::typeTLVInitialZeroFill: + return ORDER_TBSS; default: // If we get passed in a section push it to OTHER if (contentPermissions == DefinedAtom::perm___) diff --git a/lld/lib/ReaderWriter/ELF/File.h b/lld/lib/ReaderWriter/ELF/File.h index 15abec8eea7..6d297ed46f5 100644 --- a/lld/lib/ReaderWriter/ELF/File.h +++ b/lld/lib/ReaderWriter/ELF/File.h @@ -231,7 +231,8 @@ public: TargetHandler.targetAtomHandler(); c = elfAtomHandler.contentType(*si); - if (c == DefinedAtom::typeZeroFill) + if (c == DefinedAtom::typeZeroFill || + c == DefinedAtom::typeTLVInitialZeroFill) isCommon = true; } diff --git a/lld/lib/ReaderWriter/ELF/HeaderChunks.h b/lld/lib/ReaderWriter/ELF/HeaderChunks.h index e2512b55e74..f3660e8b03f 100644 --- a/lld/lib/ReaderWriter/ELF/HeaderChunks.h +++ b/lld/lib/ReaderWriter/ELF/HeaderChunks.h @@ -156,20 +156,11 @@ public: } private: - std::vector<Elf_Phdr *> _ph; - PhIterT _phi; - llvm::BumpPtrAllocator _allocator; -}; - -template<class ELFT> -bool -ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) { - Elf_Phdr *phdr = nullptr; - bool ret = false; - - for (auto slice : segment->slices()) { + std::pair<Elf_Phdr *, bool> allocateProgramHeader() { + Elf_Phdr *phdr; + bool ret = false; if (_phi == _ph.end()) { - phdr = new(_allocator.Allocate<Elf_Phdr>()) Elf_Phdr; + phdr = new (_allocator) Elf_Phdr; _ph.push_back(phdr); _phi = _ph.end(); ret = true; @@ -177,20 +168,50 @@ ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) { phdr = (*_phi); ++_phi; } - phdr->p_type = segment->segmentType(); - phdr->p_offset = slice->fileOffset(); - phdr->p_vaddr = slice->virtualAddr(); - phdr->p_paddr = slice->virtualAddr(); - phdr->p_filesz = slice->fileSize(); - phdr->p_memsz = slice->memSize(); - phdr->p_flags = segment->flags(); - phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ? - segment->pageSize() : slice->align2(); + + return std::make_pair(phdr, ret); + } + + std::vector<Elf_Phdr *> _ph; + PhIterT _phi; + llvm::BumpPtrAllocator _allocator; +}; + +template <class ELFT> +bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) { + bool allocatedNew = false; + for (auto slice : segment->slices()) { + // If we have a TLS segment, emit a LOAD first. + if (segment->segmentType() == llvm::ELF::PT_TLS) { + auto phdr = allocateProgramHeader(); + if (phdr.second) + allocatedNew = true; + phdr.first->p_type = llvm::ELF::PT_LOAD; + phdr.first->p_offset = slice->fileOffset(); + phdr.first->p_vaddr = slice->virtualAddr(); + phdr.first->p_paddr = slice->virtualAddr(); + phdr.first->p_filesz = slice->fileSize(); + phdr.first->p_memsz = slice->memSize(); + phdr.first->p_flags = segment->flags(); + phdr.first->p_align = slice->align2(); + } + auto phdr = allocateProgramHeader(); + if (phdr.second) + allocatedNew = true; + phdr.first->p_type = segment->segmentType(); + phdr.first->p_offset = slice->fileOffset(); + phdr.first->p_vaddr = slice->virtualAddr(); + phdr.first->p_paddr = slice->virtualAddr(); + phdr.first->p_filesz = slice->fileSize(); + phdr.first->p_memsz = slice->memSize(); + phdr.first->p_flags = segment->flags(); + phdr.first->p_align = (phdr.first->p_type == llvm::ELF::PT_LOAD) ? + segment->pageSize() : slice->align2(); } this->_fsize = fileSize(); this->_msize = this->_fsize; - return ret; + return allocatedNew; } template <class ELFT> diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 101089dec22..6fea1bc0d26 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -240,6 +240,7 @@ const AtomLayout &Section<ELFT>::appendAtom(const Atom *atom) { case DefinedAtom::typeGOT: case DefinedAtom::typeStub: case DefinedAtom::typeResolver: + case DefinedAtom::typeTLVInitialData: _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); this->_fsize = fOffset + definedAtom->size(); this->_msize = mOffset + definedAtom->size(); @@ -249,6 +250,7 @@ const AtomLayout &Section<ELFT>::appendAtom(const Atom *atom) { << fOffset << "\n"); break; case DefinedAtom::typeZeroFill: + case DefinedAtom::typeTLVInitialZeroFill: _atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0)); this->_msize = mOffset + definedAtom->size(); break; @@ -285,7 +287,10 @@ Section<ELFT>::flags() { case DefinedAtom::permRW_: case DefinedAtom::permRW_L: - return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE; + if (_contentType == DefinedAtom::typeTLVInitialData || + _contentType == DefinedAtom::typeTLVInitialZeroFill) + return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE | llvm::ELF::SHF_TLS; + return llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE; case DefinedAtom::permRWX: return llvm::ELF::SHF_ALLOC | @@ -314,9 +319,11 @@ Section<ELFT>::type() { case DefinedAtom::typeGOT: case DefinedAtom::typeStub: case DefinedAtom::typeResolver: + case DefinedAtom::typeTLVInitialData: return llvm::ELF::SHT_PROGBITS; case DefinedAtom::typeZeroFill: + case DefinedAtom::typeTLVInitialZeroFill: return llvm::ELF::SHT_NOBITS; // Case to handle section types @@ -638,6 +645,11 @@ SymbolTable<ELFT>::addSymbol(const Atom *atom, type = llvm::ELF::STT_OBJECT; symbol->st_value = addr; break; + case DefinedAtom::typeTLVInitialData: + case DefinedAtom::typeTLVInitialZeroFill: + type = llvm::ELF::STT_TLS; + symbol->st_value = addr; + break; default: type = llvm::ELF::STT_NOTYPE; } diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index efdfc655fd9..7db4913aba9 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -348,6 +348,8 @@ template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t &addr) { else s->assignVirtualAddress(addr); } + if (isTLSSegment) + tlsStartAddr += section->memSize(); addr += section->memSize(); section->setMemSize(addr - section->virtualAddr()); } diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp index 398ff5fa281..ddd1a6525cc 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp @@ -73,6 +73,24 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation( case R_X86_64_32S: reloc32S(location, relocVAddress, targetVAddress, ref.addend()); break; + case R_X86_64_TPOFF32: { + // Get the start and end of the TLS segment. + if (_tlsSize == 0) { + auto tdata = _targetInfo.getTargetHandler<X86_64ELFType>().targetLayout() + .findOutputSection(".tdata"); + auto tbss = _targetInfo.getTargetHandler<X86_64ELFType>().targetLayout() + .findOutputSection(".tbss"); + // HACK: The tdata and tbss sections end up together to from the TLS + // segment. This should actually use the TLS program header entry. + if (tdata) + _tlsSize = tdata->memSize(); + if (tbss) + _tlsSize += tbss->memSize(); + } + int32_t result = (int32_t)(targetVAddress - _tlsSize); + *reinterpret_cast<llvm::support::little32_t *>(location) = result; + break; + } // Runtime only relocations. Ignore here. case R_X86_64_IRELATIVE: break; diff --git a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h index 9428478a152..c18e8f9c9c1 100644 --- a/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h @@ -23,13 +23,16 @@ class X86_64TargetInfo; class X86_64TargetRelocationHandler LLVM_FINAL : public TargetRelocationHandler<X86_64ELFType> { public: - X86_64TargetRelocationHandler(const X86_64TargetInfo &ti) : _targetInfo(ti) {} + X86_64TargetRelocationHandler(const X86_64TargetInfo &ti) + : _tlsSize(0), _targetInfo(ti) {} virtual ErrorOr<void> applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const AtomLayout &, const Reference &)const; private: + // Cached size of the TLS segment. + mutable uint64_t _tlsSize; const X86_64TargetInfo &_targetInfo; }; diff --git a/lld/test/elf/Inputs/tls.c b/lld/test/elf/Inputs/tls.c new file mode 100644 index 00000000000..67235075656 --- /dev/null +++ b/lld/test/elf/Inputs/tls.c @@ -0,0 +1,11 @@ +extern __thread int tls0; +extern __thread int tls1; +extern __thread int tls2; + +__thread int tls0 = 0; +__thread int tls1 = 0; +__thread int tls2 = 1; + +int main() { + return tls0 + tls1 + tls2; +} diff --git a/lld/test/elf/Inputs/tls.x86-64 b/lld/test/elf/Inputs/tls.x86-64 Binary files differnew file mode 100644 index 00000000000..dba3907e1ba --- /dev/null +++ b/lld/test/elf/Inputs/tls.x86-64 diff --git a/lld/test/elf/tls.test b/lld/test/elf/tls.test new file mode 100644 index 00000000000..7a1281a6a50 --- /dev/null +++ b/lld/test/elf/tls.test @@ -0,0 +1,8 @@ +RUN: lld -core -target x86_64-linux %p/Inputs/tls.x86-64 -output=%t \ +RUN: -noinhibit-exec -entry=main && llvm-objdump -d %t | FileCheck %s + +// Verify that the TLS accesses have the correct offsets. + +CHECK: movl %fs:-8 +CHECK: movl %fs:-4 +CHECK: movl %fs:-12 |

