forked from OSchip/llvm-project
[PECOFF] Support TLS callbacks.
The contents from section .CRT$XLA to .CRT$XLZ is an array of function pointers. They are called by the runtime when a new thread is created or (gracefully) terminated. You can make your own initialization function to be called by that mechanism. All you have to do is: - Define a pointer to a function in a .CRT$XL* section using pragma - Make an external reference to "__tls_used" symbol That technique is used in many projects. This patch is to support that. What this patch does is to set the relative virtual address of "__tls_used" to the PECOFF directory table. __tls_used is actually a struct containing pointers to a symbol in .CRT$XLA and another symbol in .CRT$XLZ. The runtime looks at the directory table, gets the address of the struct, and call the function pointers between XLA and XLZ. llvm-svn: 218007
This commit is contained in:
parent
d8e366ba19
commit
9f1215b2d8
|
@ -885,6 +885,9 @@ private:
|
||||||
// The size of the image on disk. This is basically the sum of all chunks in
|
// The size of the image on disk. This is basically the sum of all chunks in
|
||||||
// the output file with paddings between them.
|
// the output file with paddings between them.
|
||||||
uint32_t _imageSizeOnDisk;
|
uint32_t _imageSizeOnDisk;
|
||||||
|
|
||||||
|
// The map from atom to its relative virtual address.
|
||||||
|
std::map<const Atom *, uint64_t> _atomRva;
|
||||||
};
|
};
|
||||||
|
|
||||||
StringRef customSectionName(const DefinedAtom *atom) {
|
StringRef customSectionName(const DefinedAtom *atom) {
|
||||||
|
@ -933,6 +936,13 @@ void groupAtoms(const PECOFFLinkingContext &ctx, const File &file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const DefinedAtom *findTLSUsedSymbol(const File &file) {
|
||||||
|
for (const DefinedAtom *atom : file.defined())
|
||||||
|
if (atom->name() == "__tls_used")
|
||||||
|
return atom;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Create all chunks that consist of the output file.
|
// Create all chunks that consist of the output file.
|
||||||
template <class PEHeader>
|
template <class PEHeader>
|
||||||
void PECOFFWriter::build(const File &linkedFile) {
|
void PECOFFWriter::build(const File &linkedFile) {
|
||||||
|
@ -949,6 +959,7 @@ void PECOFFWriter::build(const File &linkedFile) {
|
||||||
addChunk(dataDirectory);
|
addChunk(dataDirectory);
|
||||||
addChunk(sectionTable);
|
addChunk(sectionTable);
|
||||||
|
|
||||||
|
// Create sections and add the atoms to them.
|
||||||
for (auto i : atoms) {
|
for (auto i : atoms) {
|
||||||
StringRef sectionName = i.first;
|
StringRef sectionName = i.first;
|
||||||
std::vector<const DefinedAtom *> &contents = i.second;
|
std::vector<const DefinedAtom *> &contents = i.second;
|
||||||
|
@ -957,9 +968,14 @@ void PECOFFWriter::build(const File &linkedFile) {
|
||||||
addSectionChunk(section, sectionTable);
|
addSectionChunk(section, sectionTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we know the addresses of all defined atoms that needs to be
|
// Build atom to its RVA map.
|
||||||
// relocated. So we can create the ".reloc" section which contains all the
|
for (std::unique_ptr<Chunk> &cp : _chunks)
|
||||||
// relocation sites.
|
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
|
||||||
|
chunk->buildAtomRvaMap(_atomRva);
|
||||||
|
|
||||||
|
// We know the addresses of all defined atoms that needs to be
|
||||||
|
// relocated. So we can create the ".reloc" section which contains
|
||||||
|
// all the relocation sites.
|
||||||
if (_ctx.getBaseRelocationEnabled()) {
|
if (_ctx.getBaseRelocationEnabled()) {
|
||||||
BaseRelocChunk *baseReloc = new BaseRelocChunk(_chunks, _ctx);
|
BaseRelocChunk *baseReloc = new BaseRelocChunk(_chunks, _ctx);
|
||||||
if (baseReloc->size()) {
|
if (baseReloc->size()) {
|
||||||
|
@ -1014,6 +1030,11 @@ void PECOFFWriter::build(const File &linkedFile) {
|
||||||
section->getVirtualAddress(), section->size());
|
section->getVirtualAddress(), section->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const DefinedAtom *atom = findTLSUsedSymbol(linkedFile)) {
|
||||||
|
dataDirectory->setField(DataDirectoryIndex::TLS_TABLE,
|
||||||
|
_atomRva[atom], 0x18);
|
||||||
|
}
|
||||||
|
|
||||||
// Now that we know the size and file offset of sections. Set the file
|
// Now that we know the size and file offset of sections. Set the file
|
||||||
// header accordingly.
|
// header accordingly.
|
||||||
peHeader->setSizeOfCode(calcSizeOfCode());
|
peHeader->setSizeOfCode(calcSizeOfCode());
|
||||||
|
@ -1057,27 +1078,20 @@ std::error_code PECOFFWriter::writeFile(const File &linkedFile,
|
||||||
/// address. In the second pass, we visit all relocation references to fix
|
/// address. In the second pass, we visit all relocation references to fix
|
||||||
/// up addresses in the buffer.
|
/// up addresses in the buffer.
|
||||||
void PECOFFWriter::applyAllRelocations(uint8_t *bufferStart) {
|
void PECOFFWriter::applyAllRelocations(uint8_t *bufferStart) {
|
||||||
std::map<const Atom *, uint64_t> atomRva;
|
// Create the list of section start addresses. It's needed for
|
||||||
|
// relocations of SECREL type.
|
||||||
std::vector<uint64_t> sectionRva;
|
std::vector<uint64_t> sectionRva;
|
||||||
|
|
||||||
// Create the list of section start addresses.
|
|
||||||
for (auto &cp : _chunks)
|
for (auto &cp : _chunks)
|
||||||
if (SectionChunk *section = dyn_cast<SectionChunk>(&*cp))
|
if (SectionChunk *section = dyn_cast<SectionChunk>(&*cp))
|
||||||
sectionRva.push_back(section->getVirtualAddress());
|
sectionRva.push_back(section->getVirtualAddress());
|
||||||
|
|
||||||
// Pass 1
|
|
||||||
for (auto &cp : _chunks)
|
|
||||||
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp))
|
|
||||||
chunk->buildAtomRvaMap(atomRva);
|
|
||||||
|
|
||||||
// Pass 2
|
|
||||||
uint64_t base = _ctx.getBaseAddress();
|
uint64_t base = _ctx.getBaseAddress();
|
||||||
for (auto &cp : _chunks) {
|
for (auto &cp : _chunks) {
|
||||||
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) {
|
if (AtomChunk *chunk = dyn_cast<AtomChunk>(&*cp)) {
|
||||||
if (_ctx.is64Bit()) {
|
if (_ctx.is64Bit()) {
|
||||||
chunk->applyRelocations64(bufferStart, atomRva, sectionRva, base);
|
chunk->applyRelocations64(bufferStart, _atomRva, sectionRva, base);
|
||||||
} else {
|
} else {
|
||||||
chunk->applyRelocations32(bufferStart, atomRva, sectionRva, base);
|
chunk->applyRelocations32(bufferStart, _atomRva, sectionRva, base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
header:
|
||||||
|
Machine: IMAGE_FILE_MACHINE_I386
|
||||||
|
Characteristics: []
|
||||||
|
sections:
|
||||||
|
- Name: .data
|
||||||
|
Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
|
||||||
|
Alignment: 4
|
||||||
|
SectionData: "0000000000000000"
|
||||||
|
symbols:
|
||||||
|
- Name: .data
|
||||||
|
Value: 0
|
||||||
|
SectionNumber: 1
|
||||||
|
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||||
|
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||||
|
StorageClass: IMAGE_SYM_CLASS_STATIC
|
||||||
|
SectionDefinition:
|
||||||
|
Length: 8
|
||||||
|
NumberOfRelocations: 0
|
||||||
|
NumberOfLinenumbers: 0
|
||||||
|
CheckSum: 0
|
||||||
|
Number: 0
|
||||||
|
- Name: __tls_used
|
||||||
|
Value: 0
|
||||||
|
SectionNumber: 1
|
||||||
|
SimpleType: IMAGE_SYM_TYPE_NULL
|
||||||
|
ComplexType: IMAGE_SYM_DTYPE_NULL
|
||||||
|
StorageClass: IMAGE_SYM_CLASS_EXTERNAL
|
||||||
|
...
|
|
@ -0,0 +1,14 @@
|
||||||
|
# RUN: yaml2obj %p/Inputs/hello.obj.yaml > %t1.obj
|
||||||
|
# RUN: yaml2obj %p/Inputs/tlsused.obj.yaml > %t2.obj
|
||||||
|
|
||||||
|
# RUN: lld -flavor link /out:%t1.exe /subsystem:console /force -- %t1.obj
|
||||||
|
# RUN: llvm-readobj -file-headers %t1.exe | FileCheck -check-prefix=NOTLS %s
|
||||||
|
|
||||||
|
# RUN: lld -flavor link /out:%t2.exe /subsystem:console /force -- %t1.obj %t2.obj
|
||||||
|
# RUN: llvm-readobj -file-headers %t2.exe | FileCheck -check-prefix=TLS %s
|
||||||
|
|
||||||
|
NOTLS: TLSTableRVA: 0x0
|
||||||
|
NOTLS: TLSTableSize: 0x0
|
||||||
|
|
||||||
|
TLS: TLSTableRVA: 0x1014
|
||||||
|
TLS: TLSTableSize: 0x18
|
Loading…
Reference in New Issue