[lld] r247992 - Start adding support for creating the GOT.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 18 07:40:20 PDT 2015
Author: rafael
Date: Fri Sep 18 09:40:19 2015
New Revision: 247992
URL: http://llvm.org/viewvc/llvm-project?rev=247992&view=rev
Log:
Start adding support for creating the GOT.
With this a program can call into a shared library with
jmp *foo at GOTPCREL(%rip)
Added:
lld/trunk/test/elf2/got.s
Modified:
lld/trunk/ELF/InputFiles.h
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=247992&r1=247991&r2=247992&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri Sep 18 09:40:19 2015
@@ -134,7 +134,7 @@ public:
ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
- const 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=247992&r1=247991&r2=247992&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Fri Sep 18 09:40:19 2015
@@ -70,6 +70,10 @@ public:
}
void setDynamicSymbolTableIndex(unsigned V) { DynamicSymbolTableIndex = V; }
+ unsigned getGotIndex() const { return GotIndex; }
+ bool isInGot() const { return GotIndex != -1U; }
+ void setGotIndex(unsigned I) { GotIndex = I; }
+
// 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
@@ -96,6 +100,7 @@ protected:
unsigned MostConstrainingVisibility : 2;
unsigned IsUsedInRegularObj : 1;
unsigned DynamicSymbolTableIndex = 0;
+ unsigned GotIndex = -1;
StringRef Name;
Symbol *Backref = nullptr;
};
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=247992&r1=247991&r2=247992&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Sep 18 09:40:19 2015
@@ -81,6 +81,8 @@ public:
}
uint32_t getType() { return Header.sh_type; }
+ static unsigned getAddrSize() { return Is64Bits ? 8 : 4; }
+
virtual void finalize() {}
virtual void writeTo(uint8_t *Buf) = 0;
@@ -98,17 +100,55 @@ template <class ELFT> struct DynamicRelo
const Elf_Rel &RI;
};
+static bool relocNeedsGOT(uint32_t Type) {
+ switch (Type) {
+ default:
+ return false;
+ case R_X86_64_GOTPCREL:
+ return true;
+ }
+}
+
+template <class ELFT>
+class GotSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef OutputSectionBase<ELFT::Is64Bits> Base;
+ typedef typename Base::uintX_t uintX_t;
+
+public:
+ GotSection()
+ : OutputSectionBase<ELFT::Is64Bits>(".got", SHT_PROGBITS,
+ SHF_ALLOC | SHF_WRITE) {
+ this->Header.sh_addralign = this->getAddrSize();
+ }
+ void finalize() override {
+ this->Header.sh_size = Entries.size() * this->getAddrSize();
+ }
+ void writeTo(uint8_t *Buf) override {}
+ void addEntry(SymbolBody *Sym) {
+ Sym->setGotIndex(Entries.size());
+ Entries.push_back(Sym);
+ }
+ bool empty() const { return Entries.empty(); }
+ uintX_t getEntryAddr(const SymbolBody &B) const {
+ return this->getVA() + B.getGotIndex() * this->getAddrSize();
+ }
+
+private:
+ std::vector<const SymbolBody *> Entries;
+};
+
template <class ELFT>
class RelocationSection final : public OutputSectionBase<ELFT::Is64Bits> {
typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
public:
- RelocationSection(SymbolTableSection<ELFT> &DynSymSec, bool IsRela)
+ RelocationSection(SymbolTableSection<ELFT> &DynSymSec,
+ const GotSection<ELFT> &GotSec, bool IsRela)
: OutputSectionBase<ELFT::Is64Bits>(IsRela ? ".rela.dyn" : ".rel.dyn",
IsRela ? SHT_RELA : SHT_REL,
SHF_ALLOC),
- DynSymSec(DynSymSec), IsRela(IsRela) {
+ DynSymSec(DynSymSec), GotSec(GotSec), IsRela(IsRela) {
this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
}
@@ -127,12 +167,18 @@ public:
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);
- if (IsRela)
- P->r_addend = static_cast<const Elf_Rela &>(RI).r_addend;
+ uint32_t Type = RI.getType(IsMips64EL);
+ if (relocNeedsGOT(Type)) {
+ P->r_offset = GotSec.getEntryAddr(*Body);
+ P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
+ R_X86_64_GLOB_DAT, IsMips64EL);
+ } else {
+ P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA();
+ P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type,
+ IsMips64EL);
+ if (IsRela)
+ P->r_addend = static_cast<const Elf_Rela &>(RI).r_addend;
+ }
++P;
}
@@ -143,6 +189,7 @@ public:
private:
std::vector<DynamicReloc<ELFT>> Relocs;
SymbolTableSection<ELFT> &DynSymSec;
+ const GotSection<ELFT> &GotSec;
const bool IsRela;
};
}
@@ -155,8 +202,10 @@ public:
typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
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(const GotSection<ELFT> &GotSec, StringRef Name,
+ uint32_t sh_type, uintX_t sh_flags)
+ : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
+ GotSec(GotSec) {}
void addChunk(SectionChunk<ELFT> *C);
void writeTo(uint8_t *Buf) override;
@@ -173,6 +222,7 @@ public:
private:
std::vector<SectionChunk<ELFT> *> Chunks;
+ const GotSection<ELFT> &GotSec;
};
namespace {
@@ -507,7 +557,7 @@ public:
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
Writer(SymbolTable *T)
: SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
- RelaDynSec(DynSymSec, T->shouldUseRela()), HashSec(DynSymSec),
+ RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), HashSec(DynSymSec),
DynamicSec(*T, HashSec, RelaDynSec) {}
void run();
@@ -559,6 +609,8 @@ private:
RelocationSection<ELFT> RelaDynSec;
+ GotSection<ELFT> GotSec;
+
HashTableSection<ELFT> HashSec;
DynamicSection<ELFT> DynamicSec;
@@ -676,16 +728,22 @@ void OutputSection<ELFT>::relocate(
if (!Body)
continue;
+ uint32_t Type = RI.getType(IsMips64EL);
uintX_t SymVA;
- if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(Body))
+ if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(Body)) {
SymVA = getSymVA<ELFT>(DR);
- else if (auto *DA = dyn_cast<DefinedAbsolute<ELFT>>(Body))
+ } else if (auto *DA = dyn_cast<DefinedAbsolute<ELFT>>(Body)) {
SymVA = DA->Sym.st_value;
- else
+ } else if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body)) {
+ if (!relocNeedsGOT(Type))
+ continue;
+ SymVA = GotSec.getEntryAddr(*S);
+ Type = R_X86_64_PC32;
+ } else {
// Skip unsupported for now.
continue;
+ }
- uint32_t Type = RI.getType(IsMips64EL);
relocateOne(Buf, RI, Type, BaseAddr, SymVA);
}
}
@@ -899,12 +957,17 @@ void Writer<ELFT>::scanRelocs(
bool IsMips64EL = File.getObj()->isMips64EL();
for (const RelType &RI : Rels) {
uint32_t SymIndex = RI.getSymbol(IsMips64EL);
- const SymbolBody *Body = File.getSymbolBody(SymIndex);
+ SymbolBody *Body = File.getSymbolBody(SymIndex);
if (!Body)
continue;
auto *S = dyn_cast<SharedSymbol<ELFT>>(Body);
if (!S)
continue;
+ if (relocNeedsGOT(RI.getType(IsMips64EL))) {
+ if (Body->isInGot())
+ continue;
+ GotSec.addEntry(Body);
+ }
RelaDynSec.addReloc({C, RI});
}
}
@@ -934,7 +997,7 @@ 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>(GotSec, Key.Name, Key.sh_type, Key.sh_flags);
OutputSections.push_back(Sec);
}
return Sec;
@@ -1009,6 +1072,8 @@ template <class ELFT> void Writer<ELFT>:
OutputSections.push_back(&DynStrSec);
if (RelaDynSec.hasRelocs())
OutputSections.push_back(&RelaDynSec);
+ if (!GotSec.empty())
+ OutputSections.push_back(&GotSec);
}
std::stable_sort(OutputSections.begin(), OutputSections.end(),
Added: lld/trunk/test/elf2/got.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/got.s?rev=247992&view=auto
==============================================================================
--- lld/trunk/test/elf2/got.s (added)
+++ lld/trunk/test/elf2/got.s Fri Sep 18 09:40:19 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 -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+// CHECK: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x15000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT: 0x15000 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT: 0x15008 R_X86_64_GLOB_DAT zed 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+// 0x15000 - (0x11000 + 2) - 4 = 16378
+// 0x15000 - (0x11006 + 2) - 4 = 16372
+// 0x15008 - (0x1100c + 2) - 4 = 16374
+
+// DISASM: _start:
+// DISASM-NEXT: 11000: ff 25 fa 3f 00 00 jmpq *16378(%rip)
+// DISASM-NEXT: 11006: ff 25 f4 3f 00 00 jmpq *16372(%rip)
+// DISASM-NEXT: 1100c: ff 25 f6 3f 00 00 jmpq *16374(%rip)
+
+.global _start
+_start:
+ jmp *bar at GOTPCREL(%rip)
+ jmp *bar at GOTPCREL(%rip)
+ jmp *zed at GOTPCREL(%rip)
More information about the llvm-commits
mailing list