parent
fa4fab77d4
commit
b0ed8e80d8
|
@ -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;
|
||||
|
||||
|
|
|
@ -292,6 +292,10 @@ Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder(
|
|||
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___)
|
||||
|
|
|
@ -231,7 +231,8 @@ public:
|
|||
TargetHandler.targetAtomHandler();
|
||||
c = elfAtomHandler.contentType(*si);
|
||||
|
||||
if (c == DefinedAtom::typeZeroFill)
|
||||
if (c == DefinedAtom::typeZeroFill ||
|
||||
c == DefinedAtom::typeTLVInitialZeroFill)
|
||||
isCommon = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
std::pair<Elf_Phdr *, bool> allocateProgramHeader() {
|
||||
Elf_Phdr *phdr;
|
||||
bool ret = false;
|
||||
|
||||
for (auto slice : segment->slices()) {
|
||||
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) ?
|
||||
|
||||
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>
|
||||
|
|
|
@ -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,6 +287,9 @@ Section<ELFT>::flags() {
|
|||
|
||||
case DefinedAtom::permRW_:
|
||||
case DefinedAtom::permRW_L:
|
||||
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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
Binary file not shown.
|
@ -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
|
Loading…
Reference in New Issue