parent
fa4fab77d4
commit
b0ed8e80d8
|
@ -253,6 +253,12 @@ public:
|
||||||
return elfAtomHandler.contentType(this);
|
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)
|
if (_symbol->getType() == llvm::ELF::STT_GNU_IFUNC)
|
||||||
return typeResolver;
|
return typeResolver;
|
||||||
|
|
||||||
|
|
|
@ -291,7 +291,11 @@ Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder(
|
||||||
return ORDER_GOT;
|
return ORDER_GOT;
|
||||||
case DefinedAtom::typeStub:
|
case DefinedAtom::typeStub:
|
||||||
return ORDER_PLT;
|
return ORDER_PLT;
|
||||||
|
|
||||||
|
case DefinedAtom::typeTLVInitialData:
|
||||||
|
return ORDER_TDATA;
|
||||||
|
case DefinedAtom::typeTLVInitialZeroFill:
|
||||||
|
return ORDER_TBSS;
|
||||||
default:
|
default:
|
||||||
// If we get passed in a section push it to OTHER
|
// If we get passed in a section push it to OTHER
|
||||||
if (contentPermissions == DefinedAtom::perm___)
|
if (contentPermissions == DefinedAtom::perm___)
|
||||||
|
|
|
@ -231,7 +231,8 @@ public:
|
||||||
TargetHandler.targetAtomHandler();
|
TargetHandler.targetAtomHandler();
|
||||||
c = elfAtomHandler.contentType(*si);
|
c = elfAtomHandler.contentType(*si);
|
||||||
|
|
||||||
if (c == DefinedAtom::typeZeroFill)
|
if (c == DefinedAtom::typeZeroFill ||
|
||||||
|
c == DefinedAtom::typeTLVInitialZeroFill)
|
||||||
isCommon = true;
|
isCommon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,20 +156,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Elf_Phdr *> _ph;
|
std::pair<Elf_Phdr *, bool> allocateProgramHeader() {
|
||||||
PhIterT _phi;
|
Elf_Phdr *phdr;
|
||||||
llvm::BumpPtrAllocator _allocator;
|
bool ret = false;
|
||||||
};
|
|
||||||
|
|
||||||
template<class ELFT>
|
|
||||||
bool
|
|
||||||
ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
|
|
||||||
Elf_Phdr *phdr = nullptr;
|
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
for (auto slice : segment->slices()) {
|
|
||||||
if (_phi == _ph.end()) {
|
if (_phi == _ph.end()) {
|
||||||
phdr = new(_allocator.Allocate<Elf_Phdr>()) Elf_Phdr;
|
phdr = new (_allocator) Elf_Phdr;
|
||||||
_ph.push_back(phdr);
|
_ph.push_back(phdr);
|
||||||
_phi = _ph.end();
|
_phi = _ph.end();
|
||||||
ret = true;
|
ret = true;
|
||||||
|
@ -177,20 +168,50 @@ ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
|
||||||
phdr = (*_phi);
|
phdr = (*_phi);
|
||||||
++_phi;
|
++_phi;
|
||||||
}
|
}
|
||||||
phdr->p_type = segment->segmentType();
|
|
||||||
phdr->p_offset = slice->fileOffset();
|
return std::make_pair(phdr, ret);
|
||||||
phdr->p_vaddr = slice->virtualAddr();
|
}
|
||||||
phdr->p_paddr = slice->virtualAddr();
|
|
||||||
phdr->p_filesz = slice->fileSize();
|
std::vector<Elf_Phdr *> _ph;
|
||||||
phdr->p_memsz = slice->memSize();
|
PhIterT _phi;
|
||||||
phdr->p_flags = segment->flags();
|
llvm::BumpPtrAllocator _allocator;
|
||||||
phdr->p_align = (phdr->p_type == llvm::ELF::PT_LOAD) ?
|
};
|
||||||
segment->pageSize() : slice->align2();
|
|
||||||
|
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->_fsize = fileSize();
|
||||||
this->_msize = this->_fsize;
|
this->_msize = this->_fsize;
|
||||||
|
|
||||||
return ret;
|
return allocatedNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|
|
@ -240,6 +240,7 @@ const AtomLayout &Section<ELFT>::appendAtom(const Atom *atom) {
|
||||||
case DefinedAtom::typeGOT:
|
case DefinedAtom::typeGOT:
|
||||||
case DefinedAtom::typeStub:
|
case DefinedAtom::typeStub:
|
||||||
case DefinedAtom::typeResolver:
|
case DefinedAtom::typeResolver:
|
||||||
|
case DefinedAtom::typeTLVInitialData:
|
||||||
_atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
|
_atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
|
||||||
this->_fsize = fOffset + definedAtom->size();
|
this->_fsize = fOffset + definedAtom->size();
|
||||||
this->_msize = mOffset + definedAtom->size();
|
this->_msize = mOffset + definedAtom->size();
|
||||||
|
@ -249,6 +250,7 @@ const AtomLayout &Section<ELFT>::appendAtom(const Atom *atom) {
|
||||||
<< fOffset << "\n");
|
<< fOffset << "\n");
|
||||||
break;
|
break;
|
||||||
case DefinedAtom::typeZeroFill:
|
case DefinedAtom::typeZeroFill:
|
||||||
|
case DefinedAtom::typeTLVInitialZeroFill:
|
||||||
_atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0));
|
_atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0));
|
||||||
this->_msize = mOffset + definedAtom->size();
|
this->_msize = mOffset + definedAtom->size();
|
||||||
break;
|
break;
|
||||||
|
@ -285,7 +287,10 @@ Section<ELFT>::flags() {
|
||||||
|
|
||||||
case DefinedAtom::permRW_:
|
case DefinedAtom::permRW_:
|
||||||
case DefinedAtom::permRW_L:
|
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:
|
case DefinedAtom::permRWX:
|
||||||
return llvm::ELF::SHF_ALLOC |
|
return llvm::ELF::SHF_ALLOC |
|
||||||
|
@ -314,9 +319,11 @@ Section<ELFT>::type() {
|
||||||
case DefinedAtom::typeGOT:
|
case DefinedAtom::typeGOT:
|
||||||
case DefinedAtom::typeStub:
|
case DefinedAtom::typeStub:
|
||||||
case DefinedAtom::typeResolver:
|
case DefinedAtom::typeResolver:
|
||||||
|
case DefinedAtom::typeTLVInitialData:
|
||||||
return llvm::ELF::SHT_PROGBITS;
|
return llvm::ELF::SHT_PROGBITS;
|
||||||
|
|
||||||
case DefinedAtom::typeZeroFill:
|
case DefinedAtom::typeZeroFill:
|
||||||
|
case DefinedAtom::typeTLVInitialZeroFill:
|
||||||
return llvm::ELF::SHT_NOBITS;
|
return llvm::ELF::SHT_NOBITS;
|
||||||
|
|
||||||
// Case to handle section types
|
// Case to handle section types
|
||||||
|
@ -638,6 +645,11 @@ SymbolTable<ELFT>::addSymbol(const Atom *atom,
|
||||||
type = llvm::ELF::STT_OBJECT;
|
type = llvm::ELF::STT_OBJECT;
|
||||||
symbol->st_value = addr;
|
symbol->st_value = addr;
|
||||||
break;
|
break;
|
||||||
|
case DefinedAtom::typeTLVInitialData:
|
||||||
|
case DefinedAtom::typeTLVInitialZeroFill:
|
||||||
|
type = llvm::ELF::STT_TLS;
|
||||||
|
symbol->st_value = addr;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
type = llvm::ELF::STT_NOTYPE;
|
type = llvm::ELF::STT_NOTYPE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -348,6 +348,8 @@ template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t &addr) {
|
||||||
else
|
else
|
||||||
s->assignVirtualAddress(addr);
|
s->assignVirtualAddress(addr);
|
||||||
}
|
}
|
||||||
|
if (isTLSSegment)
|
||||||
|
tlsStartAddr += section->memSize();
|
||||||
addr += section->memSize();
|
addr += section->memSize();
|
||||||
section->setMemSize(addr - section->virtualAddr());
|
section->setMemSize(addr - section->virtualAddr());
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,24 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
|
||||||
case R_X86_64_32S:
|
case R_X86_64_32S:
|
||||||
reloc32S(location, relocVAddress, targetVAddress, ref.addend());
|
reloc32S(location, relocVAddress, targetVAddress, ref.addend());
|
||||||
break;
|
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.
|
// Runtime only relocations. Ignore here.
|
||||||
case R_X86_64_IRELATIVE:
|
case R_X86_64_IRELATIVE:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -23,13 +23,16 @@ class X86_64TargetInfo;
|
||||||
class X86_64TargetRelocationHandler LLVM_FINAL
|
class X86_64TargetRelocationHandler LLVM_FINAL
|
||||||
: public TargetRelocationHandler<X86_64ELFType> {
|
: public TargetRelocationHandler<X86_64ELFType> {
|
||||||
public:
|
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 &,
|
virtual ErrorOr<void> applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
|
||||||
const AtomLayout &,
|
const AtomLayout &,
|
||||||
const Reference &)const;
|
const Reference &)const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Cached size of the TLS segment.
|
||||||
|
mutable uint64_t _tlsSize;
|
||||||
const X86_64TargetInfo &_targetInfo;
|
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