Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 77a17af

Browse files
committed
Find PLT entries for x86, x86_64, and AArch64.
This adds a new method to ELFObjectFileBase that returns the symbols and addresses of PLT entries. This design was suggested by pcc and eugenis in https://reviews.llvm.org/D49383. Differential Revision: https://reviews.llvm.org/D50203 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@340610 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 97d7bcd commit 77a17af

File tree

5 files changed

+162
-0
lines changed

5 files changed

+162
-0
lines changed

include/llvm/MC/MCInstrAnalysis.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
namespace llvm {
2424

2525
class MCRegisterInfo;
26+
class Triple;
2627

2728
class MCInstrAnalysis {
2829
protected:
@@ -105,6 +106,13 @@ class MCInstrAnalysis {
105106
virtual bool
106107
evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size,
107108
uint64_t &Target) const;
109+
110+
/// Returns (PLT virtual address, GOT virtual address) pairs for PLT entries.
111+
virtual std::vector<std::pair<uint64_t, uint64_t>>
112+
findPltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents,
113+
uint64_t GotPltSectionVA, const Triple &TargetTriple) const {
114+
return {};
115+
}
108116
};
109117

110118
} // end namespace llvm

include/llvm/Object/ELFObjectFile.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ class ELFObjectFileBase : public ObjectFile {
8686
void setARMSubArch(Triple &TheTriple) const override;
8787

8888
virtual uint16_t getEType() const = 0;
89+
90+
std::vector<std::pair<DataRefImpl, uint64_t>> getPltAddresses() const;
8991
};
9092

9193
class ELFSectionRef : public SectionRef {

lib/Object/ELFObjectFile.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/Object/ELFObjectFile.h"
1515
#include "llvm/ADT/Triple.h"
1616
#include "llvm/BinaryFormat/ELF.h"
17+
#include "llvm/MC/MCInstrAnalysis.h"
1718
#include "llvm/MC/SubtargetFeature.h"
1819
#include "llvm/Object/ELF.h"
1920
#include "llvm/Object/ELFTypes.h"
@@ -23,6 +24,7 @@
2324
#include "llvm/Support/Endian.h"
2425
#include "llvm/Support/ErrorHandling.h"
2526
#include "llvm/Support/MathExtras.h"
27+
#include "llvm/Support/TargetRegistry.h"
2628
#include <algorithm>
2729
#include <cstddef>
2830
#include <cstdint>
@@ -327,3 +329,66 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
327329

328330
TheTriple.setArchName(Triple);
329331
}
332+
333+
std::vector<std::pair<DataRefImpl, uint64_t>>
334+
ELFObjectFileBase::getPltAddresses() const {
335+
std::string Err;
336+
const auto Triple = makeTriple();
337+
const auto *T = TargetRegistry::lookupTarget(Triple.str(), Err);
338+
if (!T)
339+
return {};
340+
uint64_t JumpSlotReloc = 0;
341+
switch (Triple.getArch()) {
342+
case Triple::x86:
343+
JumpSlotReloc = ELF::R_386_JUMP_SLOT;
344+
break;
345+
case Triple::x86_64:
346+
JumpSlotReloc = ELF::R_X86_64_JUMP_SLOT;
347+
break;
348+
case Triple::aarch64:
349+
JumpSlotReloc = ELF::R_AARCH64_JUMP_SLOT;
350+
break;
351+
default:
352+
return {};
353+
}
354+
const auto *MIA = T->createMCInstrAnalysis(T->createMCInstrInfo());
355+
if (!MIA)
356+
return {};
357+
Optional<SectionRef> Plt = None, RelaPlt = None, GotPlt = None;
358+
for (const SectionRef &Section : sections()) {
359+
StringRef Name;
360+
if (Section.getName(Name))
361+
continue;
362+
if (Name == ".plt")
363+
Plt = Section;
364+
else if (Name == ".rela.plt" || Name == ".rel.plt")
365+
RelaPlt = Section;
366+
else if (Name == ".got.plt")
367+
GotPlt = Section;
368+
}
369+
if (!Plt || !RelaPlt || !GotPlt)
370+
return {};
371+
StringRef PltContents;
372+
if (Plt->getContents(PltContents))
373+
return {};
374+
ArrayRef<uint8_t> PltBytes((const uint8_t *)PltContents.data(),
375+
Plt->getSize());
376+
auto PltEntries = MIA->findPltEntries(Plt->getAddress(), PltBytes,
377+
GotPlt->getAddress(), Triple);
378+
// Build a map from GOT entry virtual address to PLT entry virtual address.
379+
DenseMap<uint64_t, uint64_t> GotToPlt;
380+
for (const auto &Entry : PltEntries)
381+
GotToPlt.insert(std::make_pair(Entry.second, Entry.first));
382+
// Find the relocations in the dynamic relocation table that point to
383+
// locations in the GOT for which we know the corresponding PLT entry.
384+
std::vector<std::pair<DataRefImpl, uint64_t>> Result;
385+
for (const auto &Relocation : RelaPlt->relocations()) {
386+
if (Relocation.getType() != JumpSlotReloc)
387+
continue;
388+
auto PltEntryIter = GotToPlt.find(Relocation.getOffset());
389+
if (PltEntryIter != GotToPlt.end())
390+
Result.push_back(std::make_pair(
391+
Relocation.getSymbol()->getRawDataRefImpl(), PltEntryIter->second));
392+
}
393+
return Result;
394+
}

lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/MC/MCRegisterInfo.h"
2525
#include "llvm/MC/MCStreamer.h"
2626
#include "llvm/MC/MCSubtargetInfo.h"
27+
#include "llvm/Support/Endian.h"
2728
#include "llvm/Support/ErrorHandling.h"
2829
#include "llvm/Support/TargetRegistry.h"
2930

@@ -153,6 +154,31 @@ class AArch64MCInstrAnalysis : public MCInstrAnalysis {
153154
}
154155
return false;
155156
}
157+
158+
std::vector<std::pair<uint64_t, uint64_t>>
159+
findPltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents,
160+
uint64_t GotPltSectionVA,
161+
const Triple &TargetTriple) const override {
162+
// Do a lightweight parsing of PLT entries.
163+
std::vector<std::pair<uint64_t, uint64_t>> Result;
164+
for (uint64_t Byte = 0, End = PltContents.size(); Byte + 7 < End;
165+
Byte += 4) {
166+
uint32_t Insn = support::endian::read32le(PltContents.data() + Byte);
167+
// Check for adrp.
168+
if ((Insn & 0x9f000000) != 0x90000000)
169+
continue;
170+
uint64_t Imm = (((PltSectionVA + Byte) >> 12) << 12) +
171+
(((Insn >> 29) & 3) << 12) + (((Insn >> 5) & 0x3ffff) << 14);
172+
uint32_t Insn2 = support::endian::read32le(PltContents.data() + Byte + 4);
173+
// Check for: ldr Xt, [Xn, #pimm].
174+
if (Insn2 >> 22 == 0x3e5) {
175+
Imm += ((Insn2 >> 10) & 0xfff) << 3;
176+
Result.push_back(std::make_pair(PltSectionVA + Byte, Imm));
177+
Byte += 4;
178+
}
179+
}
180+
return Result;
181+
}
156182
};
157183

158184
} // end anonymous namespace

lib/Target/X86/MCTargetDesc/X86MCTargetDesc.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,9 @@ class X86MCInstrAnalysis : public MCInstrAnalysis {
384384
const MCInst &Inst) const override;
385385
bool clearsSuperRegisters(const MCRegisterInfo &MRI, const MCInst &Inst,
386386
APInt &Mask) const override;
387+
std::vector<std::pair<uint64_t, uint64_t>>
388+
findPltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents,
389+
uint64_t GotSectionVA, const Triple &TargetTriple) const;
387390
};
388391

389392
bool X86MCInstrAnalysis::isDependencyBreaking(const MCSubtargetInfo &STI,
@@ -510,6 +513,64 @@ bool X86MCInstrAnalysis::clearsSuperRegisters(const MCRegisterInfo &MRI,
510513
return Mask.getBoolValue();
511514
}
512515

516+
static std::vector<std::pair<uint64_t, uint64_t>>
517+
findX86PltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents,
518+
uint64_t GotPltSectionVA) {
519+
// Do a lightweight parsing of PLT entries.
520+
std::vector<std::pair<uint64_t, uint64_t>> Result;
521+
for (uint64_t Byte = 0, End = PltContents.size(); Byte + 6 < End; ) {
522+
// Recognize a jmp.
523+
if (PltContents[Byte] == 0xff && PltContents[Byte + 1] == 0xa3) {
524+
// The jmp instruction at the beginning of each PLT entry jumps to the
525+
// address of the base of the .got.plt section plus the immediate.
526+
uint32_t Imm = support::endian::read32le(PltContents.data() + Byte + 2);
527+
Result.push_back(
528+
std::make_pair(PltSectionVA + Byte, GotPltSectionVA + Imm));
529+
Byte += 6;
530+
} else if (PltContents[Byte] == 0xff && PltContents[Byte + 1] == 0x25) {
531+
// The jmp instruction at the beginning of each PLT entry jumps to the
532+
// immediate.
533+
uint32_t Imm = support::endian::read32le(PltContents.data() + Byte + 2);
534+
Result.push_back(std::make_pair(PltSectionVA + Byte, Imm));
535+
Byte += 6;
536+
} else
537+
Byte++;
538+
}
539+
return Result;
540+
}
541+
542+
static std::vector<std::pair<uint64_t, uint64_t>>
543+
findX86_64PltEntries(uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents) {
544+
// Do a lightweight parsing of PLT entries.
545+
std::vector<std::pair<uint64_t, uint64_t>> Result;
546+
for (uint64_t Byte = 0, End = PltContents.size(); Byte + 6 < End; ) {
547+
// Recognize a jmp.
548+
if (PltContents[Byte] == 0xff && PltContents[Byte + 1] == 0x25) {
549+
// The jmp instruction at the beginning of each PLT entry jumps to the
550+
// address of the next instruction plus the immediate.
551+
uint32_t Imm = support::endian::read32le(PltContents.data() + Byte + 2);
552+
Result.push_back(
553+
std::make_pair(PltSectionVA + Byte, PltSectionVA + Byte + 6 + Imm));
554+
Byte += 6;
555+
} else
556+
Byte++;
557+
}
558+
return Result;
559+
}
560+
561+
std::vector<std::pair<uint64_t, uint64_t>> X86MCInstrAnalysis::findPltEntries(
562+
uint64_t PltSectionVA, ArrayRef<uint8_t> PltContents,
563+
uint64_t GotPltSectionVA, const Triple &TargetTriple) const {
564+
switch (TargetTriple.getArch()) {
565+
case Triple::x86:
566+
return findX86PltEntries(PltSectionVA, PltContents, GotPltSectionVA);
567+
case Triple::x86_64:
568+
return findX86_64PltEntries(PltSectionVA, PltContents);
569+
default:
570+
return {};
571+
}
572+
}
573+
513574
} // end of namespace X86_MC
514575

515576
} // end of namespace llvm

0 commit comments

Comments
 (0)