[lld] r247811 - Start creating dynamic relocations.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 16 08:54:15 PDT 2015
Author: rafael
Date: Wed Sep 16 10:54:15 2015
New Revision: 247811
URL: http://llvm.org/viewvc/llvm-project?rev=247811&view=rev
Log:
Start creating dynamic relocations.
For now we don't create got/plt and only Elf_Rela is supported.
Added:
lld/trunk/test/elf2/dynamic-reloc.s
Modified:
lld/trunk/ELF/Chunks.h
lld/trunk/ELF/InputFiles.h
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Chunks.h?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/Chunks.h (original)
+++ lld/trunk/ELF/Chunks.h Wed Sep 16 10:54:15 2015
@@ -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; }
Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed Sep 16 10:54:15 2015
@@ -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;
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Wed Sep 16 10:54:15 2015
@@ -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;
};
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Sep 16 10:54:15 2015
@@ -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(Secti
}
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 g
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
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<Is
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>:
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>:
// 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>:
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(),
Added: lld/trunk/test/elf2/dynamic-reloc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/dynamic-reloc.s?rev=247811&view=auto
==============================================================================
--- lld/trunk/test/elf2/dynamic-reloc.s (added)
+++ lld/trunk/test/elf2/dynamic-reloc.s Wed Sep 16 10:54:15 2015
@@ -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
More information about the llvm-commits
mailing list