forked from OSchip/llvm-project
Start creating dynamic relocations.
For now we don't create got/plt and only Elf_Rela is supported. llvm-svn: 247811
This commit is contained in:
parent
509300d94c
commit
19e3889dba
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
StringRef getSectionName() const;
|
||||
const Elf_Shdr *getSectionHdr() const { return Header; }
|
||||
ObjectFile<ELFT> *getFile() { return File; }
|
||||
const ObjectFile<ELFT> *getFile() const { return File; }
|
||||
|
||||
// The writer sets and uses the addresses.
|
||||
uintX_t getOutputSectionOff() const { return OutputSectionOff; }
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ public:
|
|||
|
||||
ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
|
||||
|
||||
SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
|
||||
const SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
|
||||
uint32_t FirstNonLocal = this->Symtab->sh_info;
|
||||
if (SymbolIndex < FirstNonLocal)
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ public:
|
|||
return MostConstrainingVisibility;
|
||||
}
|
||||
|
||||
unsigned getDynamicSymbolTableIndex() const {
|
||||
return DynamicSymbolTableIndex;
|
||||
}
|
||||
void setDynamicSymbolTableIndex(unsigned V) { DynamicSymbolTableIndex = V; }
|
||||
|
||||
// A SymbolBody has a backreference to a Symbol. Originally they are
|
||||
// doubly-linked. A backreference will never change. But the pointer
|
||||
// in the Symbol may be mutated by the resolver. If you have a
|
||||
|
|
@ -90,6 +95,7 @@ protected:
|
|||
const unsigned IsWeak : 1;
|
||||
unsigned MostConstrainingVisibility : 2;
|
||||
unsigned IsUsedInRegularObj : 1;
|
||||
unsigned DynamicSymbolTableIndex = 0;
|
||||
StringRef Name;
|
||||
Symbol *Backref = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -90,6 +90,55 @@ protected:
|
|||
unsigned SectionIndex;
|
||||
~OutputSectionBase() = default;
|
||||
};
|
||||
template <class ELFT> class SymbolTableSection;
|
||||
|
||||
template <class ELFT> struct DynamicReloc {
|
||||
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
const SectionChunk<ELFT> &C;
|
||||
const Elf_Rela &RI;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
class RelocationSection final : public OutputSectionBase<ELFT::Is64Bits> {
|
||||
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
|
||||
public:
|
||||
RelocationSection(SymbolTableSection<ELFT> &DynSymSec)
|
||||
: OutputSectionBase<ELFT::Is64Bits>(".rela.dyn", SHT_RELA, SHF_ALLOC),
|
||||
DynSymSec(DynSymSec) {
|
||||
this->Header.sh_entsize = sizeof(Elf_Rela);
|
||||
this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
|
||||
}
|
||||
|
||||
void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
|
||||
void finalize() override {
|
||||
this->Header.sh_link = DynSymSec.getSectionIndex();
|
||||
this->Header.sh_size = Relocs.size() * sizeof(Elf_Rela);
|
||||
}
|
||||
void writeTo(uint8_t *Buf) override {
|
||||
auto *P = reinterpret_cast<Elf_Rela *>(Buf);
|
||||
bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL();
|
||||
for (const DynamicReloc<ELFT> &Rel : Relocs) {
|
||||
const SectionChunk<ELFT> &C = Rel.C;
|
||||
const Elf_Rela &RI = Rel.RI;
|
||||
OutputSection<ELFT> *Out = C.getOutputSection();
|
||||
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
|
||||
const SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex);
|
||||
|
||||
P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA();
|
||||
P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
|
||||
RI.getType(IsMips64EL), IsMips64EL);
|
||||
P->r_addend = RI.r_addend;
|
||||
|
||||
++P;
|
||||
}
|
||||
}
|
||||
bool hasReocs() const { return !Relocs.empty(); }
|
||||
|
||||
private:
|
||||
std::vector<DynamicReloc<ELFT>> Relocs;
|
||||
SymbolTableSection<ELFT> &DynSymSec;
|
||||
};
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
|
|
@ -99,14 +148,17 @@ public:
|
|||
typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
|
||||
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
|
||||
: OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags) {}
|
||||
OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags,
|
||||
RelocationSection<ELFT> &RelaDynSec)
|
||||
: OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
|
||||
RelaDynSec(RelaDynSec) {}
|
||||
|
||||
void addChunk(SectionChunk<ELFT> *C);
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
|
||||
private:
|
||||
std::vector<SectionChunk<ELFT> *> Chunks;
|
||||
RelocationSection<ELFT> &RelaDynSec;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
|
@ -212,9 +264,11 @@ public:
|
|||
this->Header.sh_addralign = sizeof(Elf_Word);
|
||||
}
|
||||
|
||||
void addSymbol(StringRef Name) {
|
||||
void addSymbol(SymbolBody *S) {
|
||||
StringRef Name = S->getName();
|
||||
DynSymSec.addSymbol(Name);
|
||||
Hashes.push_back(hash(Name));
|
||||
S->setDynamicSymbolTableIndex(Hashes.size());
|
||||
}
|
||||
|
||||
void finalize() override {
|
||||
|
|
@ -363,9 +417,10 @@ public:
|
|||
typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
|
||||
typedef typename ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
|
||||
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
Writer(SymbolTable *T)
|
||||
: SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
|
||||
HashSec(DynSymSec), DynamicSec(*T, HashSec) {}
|
||||
RelaDynSec(DynSymSec), HashSec(DynSymSec), DynamicSec(*T, HashSec) {}
|
||||
void run();
|
||||
|
||||
const OutputSection<ELFT> &getBSS() const {
|
||||
|
|
@ -375,6 +430,7 @@ public:
|
|||
|
||||
private:
|
||||
void createSections();
|
||||
void scanRelocs(const SectionChunk<ELFT> &C);
|
||||
void assignAddresses();
|
||||
void openFile(StringRef OutputPath);
|
||||
void writeHeader();
|
||||
|
|
@ -404,6 +460,8 @@ private:
|
|||
SymbolTableSection<ELFT> SymTabSec;
|
||||
SymbolTableSection<ELFT> DynSymSec;
|
||||
|
||||
RelocationSection<ELFT> RelaDynSec;
|
||||
|
||||
HashTableSection<ELFT> HashSec;
|
||||
|
||||
DynamicSection<ELFT> DynamicSec;
|
||||
|
|
@ -454,7 +512,8 @@ void OutputSection<ELFT>::addChunk(SectionChunk<ELFT> *C) {
|
|||
}
|
||||
|
||||
template <class ELFT>
|
||||
static typename ELFFile<ELFT>::uintX_t getSymVA(DefinedRegular<ELFT> *DR) {
|
||||
static typename ELFFile<ELFT>::uintX_t
|
||||
getSymVA(const DefinedRegular<ELFT> *DR) {
|
||||
const SectionChunk<ELFT> *SC = &DR->Section;
|
||||
OutputSection<ELFT> *OS = SC->getOutputSection();
|
||||
return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value;
|
||||
|
|
@ -463,7 +522,7 @@ static typename ELFFile<ELFT>::uintX_t getSymVA(DefinedRegular<ELFT> *DR) {
|
|||
template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
for (SectionChunk<ELFT> *C : Chunks) {
|
||||
C->writeTo(Buf);
|
||||
ObjectFile<ELFT> *File = C->getFile();
|
||||
const ObjectFile<ELFT> *File = C->getFile();
|
||||
ELFFile<ELFT> *EObj = File->getObj();
|
||||
uint8_t *Base = Buf + C->getOutputSectionOff();
|
||||
|
||||
|
|
@ -474,7 +533,7 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
continue;
|
||||
for (const Elf_Rela &RI : EObj->relas(RelSec)) {
|
||||
uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL());
|
||||
SymbolBody *Body = File->getSymbolBody(SymIndex);
|
||||
const SymbolBody *Body = File->getSymbolBody(SymIndex);
|
||||
if (!Body)
|
||||
continue;
|
||||
|
||||
|
|
@ -671,6 +730,38 @@ static bool compSec(OutputSectionBase<Is64Bits> *A,
|
|||
return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
|
||||
}
|
||||
|
||||
// The reason we have to do this early scan is as follows
|
||||
// * To mmap the output file, we need to know the size
|
||||
// * For that, we need to know how many dynamic relocs we will have.
|
||||
// It might be possible to avoid this by outputting the file with write:
|
||||
// * Write the allocated output sections, computing addresses.
|
||||
// * Apply relocations, recording which ones require a dynamic reloc.
|
||||
// * Write the dynamic relocations.
|
||||
// * Write the rest of the file.
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::scanRelocs(const SectionChunk<ELFT> &C) {
|
||||
const ObjectFile<ELFT> *File = C.getFile();
|
||||
ELFFile<ELFT> *EObj = File->getObj();
|
||||
|
||||
if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
|
||||
return;
|
||||
|
||||
for (const Elf_Shdr *RelSec : C.RelocSections) {
|
||||
if (RelSec->sh_type != SHT_RELA)
|
||||
continue;
|
||||
for (const Elf_Rela &RI : EObj->relas(RelSec)) {
|
||||
uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL());
|
||||
const SymbolBody *Body = File->getSymbolBody(SymIndex);
|
||||
if (!Body)
|
||||
continue;
|
||||
auto *S = dyn_cast<SharedSymbol<ELFT>>(Body);
|
||||
if (!S)
|
||||
continue;
|
||||
RelaDynSec.addReloc({C, RI});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create output section objects and add them to OutputSections.
|
||||
template <class ELFT> void Writer<ELFT>::createSections() {
|
||||
SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
|
||||
|
|
@ -680,27 +771,14 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
|||
OutputSection<ELFT> *&Sec = Map[Key];
|
||||
if (!Sec) {
|
||||
Sec = new (CAlloc.Allocate())
|
||||
OutputSection<ELFT>(Key.Name, Key.sh_type, Key.sh_flags);
|
||||
OutputSection<ELFT>(Key.Name, Key.sh_type, Key.sh_flags, RelaDynSec);
|
||||
OutputSections.push_back(Sec);
|
||||
}
|
||||
return Sec;
|
||||
};
|
||||
|
||||
const SymbolTable &Symtab = SymTabSec.getSymTable();
|
||||
for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
|
||||
auto &File = cast<ObjectFile<ELFT>>(*FileB);
|
||||
for (SectionChunk<ELFT> *C : File.getChunks()) {
|
||||
if (!C)
|
||||
continue;
|
||||
const Elf_Shdr *H = C->getSectionHdr();
|
||||
OutputSection<ELFT> *Sec =
|
||||
getSection(C->getSectionName(), H->sh_type, H->sh_flags);
|
||||
Sec->addChunk(C);
|
||||
}
|
||||
}
|
||||
|
||||
BSSSec = getSection(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
||||
// FIXME: Try to avoid the extra walk over all global symbols.
|
||||
const SymbolTable &Symtab = SymTabSec.getSymTable();
|
||||
std::vector<DefinedCommon<ELFT> *> CommonSymbols;
|
||||
for (auto &P : Symtab.getSymbols()) {
|
||||
StringRef Name = P.first;
|
||||
|
|
@ -718,9 +796,23 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
|||
// need to add the symbols use by dynamic relocations when producing
|
||||
// an executable (ignoring --export-dynamic).
|
||||
if (needsDynamicSections())
|
||||
HashSec.addSymbol(Name);
|
||||
HashSec.addSymbol(Body);
|
||||
}
|
||||
|
||||
for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
|
||||
auto &File = cast<ObjectFile<ELFT>>(*FileB);
|
||||
for (SectionChunk<ELFT> *C : File.getChunks()) {
|
||||
if (!C)
|
||||
continue;
|
||||
const Elf_Shdr *H = C->getSectionHdr();
|
||||
OutputSection<ELFT> *Sec =
|
||||
getSection(C->getSectionName(), H->sh_type, H->sh_flags);
|
||||
Sec->addChunk(C);
|
||||
scanRelocs(*C);
|
||||
}
|
||||
}
|
||||
|
||||
BSSSec = getSection(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
||||
// Sort the common symbols by alignment as an heuristic to pack them better.
|
||||
std::stable_sort(CommonSymbols.begin(), CommonSymbols.end(), cmpAlign<ELFT>);
|
||||
uintX_t Off = BSSSec->getSize();
|
||||
|
|
@ -744,6 +836,8 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
|||
OutputSections.push_back(&HashSec);
|
||||
OutputSections.push_back(&DynamicSec);
|
||||
OutputSections.push_back(&DynStrSec);
|
||||
if (RelaDynSec.hasReocs())
|
||||
OutputSections.push_back(&RelaDynSec);
|
||||
}
|
||||
|
||||
std::stable_sort(OutputSections.begin(), OutputSections.end(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
|
||||
// RUN: lld -flavor gnu2 -shared %t2.o -o %t2.so
|
||||
// RUN: lld -flavor gnu2 %t.o %t2.so -o %t
|
||||
// RUN: llvm-readobj -r --expand-relocs -s %t | FileCheck %s
|
||||
// REQUIRES: x86
|
||||
|
||||
// CHECK: Name: .text
|
||||
// CHECK-NEXT: Type: SHT_PROGBITS
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: SHF_EXECINSTR
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: [[ADDR:.*]]
|
||||
|
||||
// CHECK: Index: 4
|
||||
// CHECK-NEXT: Name: .dynsym
|
||||
|
||||
// CHECK: Name: .rela.dyn
|
||||
// CHECK-NEXT: Type: SHT_RELA
|
||||
// CHECK-NEXT: Flags [
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x16000
|
||||
// CHECK-NEXT: Offset: 0x6000
|
||||
// CHECK-NEXT: Size: 24
|
||||
// CHECK-NEXT: Link: 4
|
||||
// CHECK-NEXT: Info: 0
|
||||
// CHECK-NEXT: AddressAlignment: 8
|
||||
// CHECK-NEXT: EntrySize: 24
|
||||
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
|
||||
// CHECK-NEXT: Relocation {
|
||||
// CHECK-NEXT: Offset: [[ADDR]]
|
||||
// CHECK-NEXT: Type: R_X86_64_64
|
||||
// CHECK-NEXT: Symbol: bar
|
||||
// CHECK-NEXT: Addend: 0x42
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
.quad bar + 0x42
|
||||
Loading…
Reference in New Issue