[lld] r248165 - Start adding support for PLT.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 08:11:30 PDT 2015
Author: rafael
Date: Mon Sep 21 10:11:29 2015
New Revision: 248165
URL: http://llvm.org/viewvc/llvm-project?rev=248165&view=rev
Log:
Start adding support for PLT.
For now this doesn't support lazy symbol resolution, but is enough to link
and run a program with
jmp foo at PLT
Added:
lld/trunk/test/elf2/plt.s
Modified:
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=248165&r1=248164&r2=248165&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon Sep 21 10:11:29 2015
@@ -75,6 +75,10 @@ public:
bool isInGot() const { return GotIndex != -1U; }
void setGotIndex(unsigned I) { GotIndex = I; }
+ unsigned getPltIndex() const { return PltIndex; }
+ bool isInPlt() const { return PltIndex != -1U; }
+ void setPltIndex(unsigned I) { PltIndex = 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
@@ -102,6 +106,7 @@ protected:
unsigned IsUsedInRegularObj : 1;
unsigned DynamicSymbolTableIndex = 0;
unsigned GotIndex = -1;
+ unsigned PltIndex = -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=248165&r1=248164&r2=248165&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Sep 21 10:11:29 2015
@@ -100,7 +100,18 @@ template <class ELFT> struct DynamicRelo
const Elf_Rel &RI;
};
+static bool relocNeedsPLT(uint32_t Type) {
+ switch (Type) {
+ default:
+ return false;
+ case R_X86_64_PLT32:
+ return true;
+ }
+}
+
static bool relocNeedsGOT(uint32_t Type) {
+ if (relocNeedsPLT(Type))
+ return true;
switch (Type) {
default:
return false;
@@ -138,6 +149,58 @@ private:
};
template <class ELFT>
+class PltSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef OutputSectionBase<ELFT::Is64Bits> Base;
+ typedef typename Base::uintX_t uintX_t;
+
+public:
+ PltSection(const GotSection<ELFT> &GotSec)
+ : OutputSectionBase<ELFT::Is64Bits>(".plt", SHT_PROGBITS,
+ SHF_ALLOC | SHF_EXECINSTR),
+ GotSec(GotSec) {
+ this->Header.sh_addralign = 16;
+ }
+ void finalize() override {
+ this->Header.sh_size = Entries.size() * EntrySize;
+ }
+ void writeTo(uint8_t *Buf) override {
+ uintptr_t Start = reinterpret_cast<uintptr_t>(Buf);
+ ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
+ for (const SymbolBody *E : Entries) {
+ uintptr_t InstPos = reinterpret_cast<uintptr_t>(Buf);
+
+ memcpy(Buf, Jmp.data(), Jmp.size());
+ Buf += Jmp.size();
+
+ uintptr_t OffsetInPLT = (InstPos + 6) - Start;
+ uintptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT);
+ assert(isInt<32>(Delta));
+ support::endian::write32le(Buf, Delta);
+ Buf += 4;
+
+ *Buf = 0x90; // nop
+ ++Buf;
+ *Buf = 0x90; // nop
+ ++Buf;
+ }
+ }
+ void addEntry(SymbolBody *Sym) {
+ Sym->setPltIndex(Entries.size());
+ Entries.push_back(Sym);
+ }
+ bool empty() const { return Entries.empty(); }
+ uintX_t getEntryAddr(const SymbolBody &B) const {
+ return this->getVA() + B.getPltIndex() * EntrySize;
+ }
+
+ static const unsigned EntrySize = 8;
+
+private:
+ std::vector<const SymbolBody *> Entries;
+ const GotSection<ELFT> &GotSec;
+};
+
+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;
@@ -202,10 +265,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(const GotSection<ELFT> &GotSec, StringRef Name,
- uint32_t sh_type, uintX_t sh_flags)
+ OutputSection(const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec,
+ StringRef Name, uint32_t sh_type, uintX_t sh_flags)
: OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
- GotSec(GotSec) {}
+ PltSec(PltSec), GotSec(GotSec) {}
void addChunk(SectionChunk<ELFT> *C);
void writeTo(uint8_t *Buf) override;
@@ -222,6 +285,7 @@ public:
private:
std::vector<SectionChunk<ELFT> *> Chunks;
+ const PltSection<ELFT> &PltSec;
const GotSection<ELFT> &GotSec;
};
@@ -557,8 +621,8 @@ public:
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
Writer(SymbolTable *T)
: SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
- RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), HashSec(DynSymSec),
- DynamicSec(*T, HashSec, RelaDynSec) {}
+ RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), PltSec(GotSec),
+ HashSec(DynSymSec), DynamicSec(*T, HashSec, RelaDynSec) {}
void run();
const OutputSection<ELFT> &getBSS() const {
@@ -610,6 +674,7 @@ private:
RelocationSection<ELFT> RelaDynSec;
GotSection<ELFT> GotSec;
+ PltSection<ELFT> PltSec;
HashTableSection<ELFT> HashSec;
@@ -744,10 +809,15 @@ void OutputSection<ELFT>::relocate(
break;
}
case SymbolBody::SharedKind:
- if (!relocNeedsGOT(Type))
+ if (relocNeedsPLT(Type)) {
+ SymVA = PltSec.getEntryAddr(*Body);
+ Type = R_X86_64_PC32;
+ } else if (relocNeedsGOT(Type)) {
+ SymVA = GotSec.getEntryAddr(*Body);
+ Type = R_X86_64_PC32;
+ } else {
continue;
- SymVA = GotSec.getEntryAddr(*Body);
- Type = R_X86_64_PC32;
+ }
break;
case SymbolBody::UndefinedKind:
assert(Body->isWeak() && "Undefined symbol reached writer");
@@ -978,7 +1048,13 @@ void Writer<ELFT>::scanRelocs(
auto *S = dyn_cast<SharedSymbol<ELFT>>(Body);
if (!S)
continue;
- if (relocNeedsGOT(RI.getType(IsMips64EL))) {
+ uint32_t Type = RI.getType(IsMips64EL);
+ if (relocNeedsPLT(Type)) {
+ if (Body->isInPlt())
+ continue;
+ PltSec.addEntry(Body);
+ }
+ if (relocNeedsGOT(Type)) {
if (Body->isInGot())
continue;
GotSec.addEntry(Body);
@@ -1011,8 +1087,8 @@ template <class ELFT> void Writer<ELFT>:
SectionKey<ELFT::Is64Bits> Key{Name, sh_type, sh_flags};
OutputSection<ELFT> *&Sec = Map[Key];
if (!Sec) {
- Sec = new (CAlloc.Allocate())
- OutputSection<ELFT>(GotSec, Key.Name, Key.sh_type, Key.sh_flags);
+ Sec = new (CAlloc.Allocate()) OutputSection<ELFT>(
+ PltSec, GotSec, Key.Name, Key.sh_type, Key.sh_flags);
OutputSections.push_back(Sec);
}
return Sec;
@@ -1090,6 +1166,8 @@ template <class ELFT> void Writer<ELFT>:
OutputSections.push_back(&RelaDynSec);
if (!GotSec.empty())
OutputSections.push_back(&GotSec);
+ if (!PltSec.empty())
+ OutputSections.push_back(&PltSec);
}
std::stable_sort(OutputSections.begin(), OutputSections.end(),
Added: lld/trunk/test/elf2/plt.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/plt.s?rev=248165&view=auto
==============================================================================
--- lld/trunk/test/elf2/plt.s (added)
+++ lld/trunk/test/elf2/plt.s Mon Sep 21 10:11:29 2015
@@ -0,0 +1,57 @@
+// 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: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x16000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// 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:
+
+// 0x16000 - (0x11000 + 1) - 4 = 20475
+// 0x16000 - (0x11005 + 1) - 4 = 20470
+// 0x16008 - (0x1100a + 1) - 4 = 20473
+
+// DISASM: _start:
+// DISASM-NEXT: 11000: e9 fb 4f 00 00 jmp 20475
+// DISASM-NEXT: 11005: e9 f6 4f 00 00 jmp 20470
+// DISASM-NEXT: 1100a: e9 f9 4f 00 00 jmp 20473
+
+// 0x15000 - 0x16006 = -4102
+// 0x15008 - 0x1600e = -4102
+
+// DISASM: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT: 16000: ff 25 fa ef ff ff jmpq *-4102(%rip)
+// DISASM-NEXT: 16006: 90 nop
+// DISASM-NEXT: 16007: 90 nop
+// DISASM-NEXT: 16008: ff 25 fa ef ff ff jmpq *-4102(%rip)
+// DISASM-NEXT: 1600e: 90 nop
+// DISASM-NEXT: 1600f: 90 nop
+
+.global _start
+_start:
+ jmp bar at PLT
+ jmp bar at PLT
+ jmp zed at PLT
More information about the llvm-commits
mailing list