[ELF] Add support for IFUNC.
This sadly doesn't have a test for the final output because llvm-objdump can't dump relocations that don't belong to a section :( llvm-svn: 173808
This commit is contained in:
parent
978b5a0e02
commit
289dcedea5
|
@ -18,6 +18,8 @@
|
|||
#include <memory>
|
||||
|
||||
namespace lld {
|
||||
class DefinedAtom;
|
||||
class Reference;
|
||||
|
||||
namespace elf { template <typename ELFT> class ELFTargetHandler; }
|
||||
|
||||
|
@ -37,6 +39,11 @@ public:
|
|||
virtual StringRef getEntry() const;
|
||||
virtual uint64_t getBaseAddress() const { return _options._baseAddress; }
|
||||
|
||||
virtual bool isRuntimeRelocation(const DefinedAtom &,
|
||||
const Reference &) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ELFTargetInfo> create(const LinkerOptions &lo);
|
||||
|
||||
template <typename ELFT>
|
||||
|
|
|
@ -23,7 +23,10 @@
|
|||
namespace lld {
|
||||
class SimpleFile : public MutableFile {
|
||||
public:
|
||||
SimpleFile(const TargetInfo &ti, StringRef path) : MutableFile(ti, path) {}
|
||||
SimpleFile(const TargetInfo &ti, StringRef path) : MutableFile(ti, path) {
|
||||
static uint32_t lastOrdinal = 0;
|
||||
_ordinal = lastOrdinal++;
|
||||
}
|
||||
|
||||
virtual void addAtom(const Atom &atom) {
|
||||
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom)) {
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
ORDER_TEXT = 70,
|
||||
ORDER_PLT = 80,
|
||||
ORDER_FINI = 90,
|
||||
ORDER_REL = 95,
|
||||
ORDER_RODATA = 100,
|
||||
ORDER_EH_FRAME = 110,
|
||||
ORDER_EH_FRAMEHDR = 120,
|
||||
|
@ -251,6 +252,16 @@ public:
|
|||
return _programHeader;
|
||||
}
|
||||
|
||||
ELFRelocationTable<ELFT> *getRelocationTable() {
|
||||
// Only create the relocation table if it is needed.
|
||||
if (!_relocationTable) {
|
||||
_relocationTable = new (_allocator)
|
||||
ELFRelocationTable<ELFT>(_targetInfo, ".rela.plt", ORDER_REL);
|
||||
addSection(_relocationTable);
|
||||
}
|
||||
return _relocationTable;
|
||||
}
|
||||
|
||||
private:
|
||||
SectionMapT _sectionMap;
|
||||
MergedSectionMapT _mergedSectionMap;
|
||||
|
@ -260,6 +271,7 @@ private:
|
|||
std::vector<MergedSections<ELFT> *> _mergedSections;
|
||||
ELFHeader<ELFT> *_elfHeader;
|
||||
ELFProgramHeader<ELFT> *_programHeader;
|
||||
ELFRelocationTable<ELFT> *_relocationTable;
|
||||
std::vector<AbsoluteAtomPair> _absoluteAtoms;
|
||||
llvm::BumpPtrAllocator _allocator;
|
||||
const ELFTargetInfo &_targetInfo;
|
||||
|
@ -272,6 +284,7 @@ DefaultELFLayout<ELFT>::getSectionOrder(const StringRef name,
|
|||
int32_t contentPermissions)
|
||||
{
|
||||
switch (contentType) {
|
||||
case DefinedAtom::typeResolver:
|
||||
case DefinedAtom::typeCode:
|
||||
return llvm::StringSwitch<Reference::Kind>(name)
|
||||
.StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
|
||||
|
@ -292,6 +305,11 @@ DefaultELFLayout<ELFT>::getSectionOrder(const StringRef name,
|
|||
case DefinedAtom::typeZeroFill:
|
||||
return ORDER_BSS;
|
||||
|
||||
case DefinedAtom::typeGOT:
|
||||
return ORDER_GOT;
|
||||
case DefinedAtom::typeStub:
|
||||
return ORDER_PLT;
|
||||
|
||||
default:
|
||||
// If we get passed in a section push it to OTHER
|
||||
if (contentPermissions == DefinedAtom::perm___)
|
||||
|
@ -327,6 +345,7 @@ DefaultELFLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
|
|||
case ORDER_HASH:
|
||||
case ORDER_DYNAMIC_SYMBOLS:
|
||||
case ORDER_DYNAMIC_STRINGS:
|
||||
case ORDER_REL:
|
||||
case ORDER_INIT:
|
||||
case ORDER_PLT:
|
||||
case ORDER_FINI:
|
||||
|
@ -343,9 +362,9 @@ DefaultELFLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
|
|||
|
||||
case ORDER_CTORS:
|
||||
case ORDER_DTORS:
|
||||
case ORDER_GOT:
|
||||
return llvm::ELF::PT_GNU_RELRO;
|
||||
|
||||
case ORDER_GOT:
|
||||
case ORDER_GOT_PLT:
|
||||
case ORDER_DATA:
|
||||
case ORDER_BSS:
|
||||
|
@ -366,6 +385,7 @@ DefaultELFLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) {
|
|||
case ORDER_HASH:
|
||||
case ORDER_DYNAMIC_SYMBOLS:
|
||||
case ORDER_DYNAMIC_STRINGS:
|
||||
case ORDER_REL:
|
||||
case ORDER_INIT:
|
||||
case ORDER_PLT:
|
||||
case ORDER_TEXT:
|
||||
|
@ -415,6 +435,10 @@ DefaultELFLayout<ELFT>::addAtom(const Atom *atom) {
|
|||
section = _sectionMap[sectionKey];
|
||||
}
|
||||
section->appendAtom(atom);
|
||||
// Add runtime relocations to the .rela section.
|
||||
for (const auto &reloc : *definedAtom)
|
||||
if (_targetInfo.isRuntimeRelocation(*definedAtom, *reloc))
|
||||
getRelocationTable()->addRelocation(*definedAtom, *reloc);
|
||||
} else if (const AbsoluteAtom *absoluteAtom = dyn_cast<AbsoluteAtom>(atom)) {
|
||||
// Absolute atoms are not part of any section, they are global for the whole
|
||||
// link
|
||||
|
|
|
@ -227,9 +227,16 @@ Section<ELFT>::appendAtom(const Atom *atom) {
|
|||
case DefinedAtom::typeCode:
|
||||
case DefinedAtom::typeData:
|
||||
case DefinedAtom::typeConstant:
|
||||
case DefinedAtom::typeGOT:
|
||||
case DefinedAtom::typeStub:
|
||||
case DefinedAtom::typeResolver:
|
||||
_atoms.push_back(AtomLayout(atom, fOffset, 0));
|
||||
this->_fsize = fOffset + definedAtom->size();
|
||||
this->_msize = mOffset + definedAtom->size();
|
||||
DEBUG_WITH_TYPE("Section",
|
||||
llvm::dbgs() << "[" << this->name() << " " << this << "] "
|
||||
<< "Adding atom: " << atom->name() << "@"
|
||||
<< fOffset << "\n");
|
||||
break;
|
||||
case DefinedAtom::typeZeroFill:
|
||||
_atoms.push_back(AtomLayout(atom, mOffset, 0));
|
||||
|
@ -286,10 +293,16 @@ Section<ELFT>::flags() {
|
|||
template<class ELFT>
|
||||
int
|
||||
Section<ELFT>::type() {
|
||||
if (_sectionKind == K_SymbolTable)
|
||||
return llvm::ELF::SHT_SYMTAB;
|
||||
|
||||
switch (_contentType) {
|
||||
case DefinedAtom::typeCode:
|
||||
case DefinedAtom::typeData:
|
||||
case DefinedAtom::typeConstant:
|
||||
case DefinedAtom::typeGOT:
|
||||
case DefinedAtom::typeStub:
|
||||
case DefinedAtom::typeResolver:
|
||||
return llvm::ELF::SHT_PROGBITS;
|
||||
|
||||
case DefinedAtom::typeZeroFill:
|
||||
|
@ -332,6 +345,9 @@ template <class ELFT>
|
|||
void Section<ELFT>::write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
|
||||
uint8_t *chunkBuffer = buffer.getBufferStart();
|
||||
for (auto &ai : _atoms) {
|
||||
DEBUG_WITH_TYPE("Section",
|
||||
llvm::dbgs() << "Writing atom: " << ai._atom->name()
|
||||
<< " | " << ai._fileOffset << "\n");
|
||||
const DefinedAtom *definedAtom = cast<DefinedAtom>(ai._atom);
|
||||
if (definedAtom->contentType() == DefinedAtom::typeZeroFill)
|
||||
continue;
|
||||
|
@ -603,11 +619,17 @@ ELFSymbolTable<ELFT>::addSymbol(const Atom *atom,
|
|||
lld::DefinedAtom::ContentType ct;
|
||||
switch (ct = da->contentType()){
|
||||
case DefinedAtom::typeCode:
|
||||
case DefinedAtom::typeStub:
|
||||
symbol->st_value = addr;
|
||||
type = llvm::ELF::STT_FUNC;
|
||||
break;
|
||||
case DefinedAtom::typeResolver:
|
||||
symbol->st_value = addr;
|
||||
type = llvm::ELF::STT_GNU_IFUNC;
|
||||
break;
|
||||
case DefinedAtom::typeData:
|
||||
case DefinedAtom::typeConstant:
|
||||
case DefinedAtom::typeGOT:
|
||||
symbol->st_value = addr;
|
||||
type = llvm::ELF::STT_OBJECT;
|
||||
break;
|
||||
|
@ -678,6 +700,46 @@ void ELFSymbolTable<ELFT>::write(ELFWriter *writer,
|
|||
}
|
||||
}
|
||||
|
||||
template <class ELFT> class ELFRelocationTable : public Section<ELFT> {
|
||||
public:
|
||||
typedef llvm::object::Elf_Rel_Impl<ELFT, true> Elf_Rela;
|
||||
|
||||
ELFRelocationTable(const ELFTargetInfo &ti, StringRef str, int32_t order)
|
||||
: Section<ELFT>(ti, str, llvm::ELF::SHT_RELA, DefinedAtom::permR__, order,
|
||||
Section<ELFT>::K_Default) {
|
||||
this->setOrder(order);
|
||||
this->_entSize = sizeof(Elf_Rela);
|
||||
this->_align2 = llvm::alignOf<Elf_Rela>();
|
||||
}
|
||||
|
||||
void addRelocation(const DefinedAtom &da, const Reference &r) {
|
||||
_relocs.emplace_back(da, r);
|
||||
this->_fsize = _relocs.size() * sizeof(Elf_Rela);
|
||||
this->_msize = this->_fsize;
|
||||
}
|
||||
|
||||
void write(ELFWriter *writer, llvm::FileOutputBuffer &buffer) {
|
||||
uint8_t *chunkBuffer = buffer.getBufferStart();
|
||||
uint8_t *dest = chunkBuffer + this->fileOffset();
|
||||
for (const auto &rel : _relocs) {
|
||||
Elf_Rela *r = reinterpret_cast<Elf_Rela *>(dest);
|
||||
r->setSymbolAndType(0, rel.second.kind());
|
||||
r->r_offset =
|
||||
writer->addressOfAtom(&rel.first) + rel.second.offsetInAtom();
|
||||
r->r_addend =
|
||||
writer->addressOfAtom(rel.second.target()) + rel.second.addend();
|
||||
dest += sizeof(Elf_Rela);
|
||||
DEBUG_WITH_TYPE("ELFRelocationTable", llvm::dbgs()
|
||||
<< "IRELATIVE relocation at " << rel.first.name() << "@"
|
||||
<< r->r_offset << " to " << rel.second.target()->name()
|
||||
<< "@" << r->r_addend << "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<const DefinedAtom &, const Reference &>> _relocs;
|
||||
};
|
||||
|
||||
} // elf
|
||||
} // lld
|
||||
|
||||
|
|
|
@ -52,6 +52,9 @@ public:
|
|||
FileELF(const ELFTargetInfo &ti, std::unique_ptr<llvm::MemoryBuffer> MB,
|
||||
llvm::error_code &EC)
|
||||
: File(MB->getBufferIdentifier()), _elfTargetInfo(ti) {
|
||||
static uint32_t lastOrdinal = 0;
|
||||
_ordinal = lastOrdinal++;
|
||||
|
||||
llvm::OwningPtr<llvm::object::Binary> binaryFile;
|
||||
EC = createBinary(MB.release(), binaryFile);
|
||||
if (EC)
|
||||
|
|
|
@ -156,6 +156,8 @@ void ELFExecutableWriter<ELFT>::addDefaultAtoms() {
|
|||
_runtimeFile.addAbsoluteAtom("end");
|
||||
_runtimeFile.addAbsoluteAtom("__init_array_start");
|
||||
_runtimeFile.addAbsoluteAtom("__init_array_end");
|
||||
_runtimeFile.addAbsoluteAtom("__rela_iplt_start");
|
||||
_runtimeFile.addAbsoluteAtom("__rela_iplt_end");
|
||||
}
|
||||
|
||||
/// \brief Hook in lld to add CRuntime file
|
||||
|
@ -175,16 +177,24 @@ void ELFExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
|
|||
auto endAtomIter = _layout->findAbsoluteAtom("end");
|
||||
auto initArrayStartIter = _layout->findAbsoluteAtom("__init_array_start");
|
||||
auto initArrayEndIter = _layout->findAbsoluteAtom("__init_array_end");
|
||||
auto realIpltStartIter = _layout->findAbsoluteAtom("__rela_iplt_start");
|
||||
auto realIpltEndIter = _layout->findAbsoluteAtom("__rela_iplt_end");
|
||||
|
||||
auto section = _layout->findOutputSection(".init_array");
|
||||
auto startEnd = [&](typename DefaultELFLayout<ELFT>::AbsoluteAtomIterT start,
|
||||
typename DefaultELFLayout<ELFT>::AbsoluteAtomIterT end,
|
||||
StringRef sec) -> void {
|
||||
auto section = _layout->findOutputSection(sec);
|
||||
if (section) {
|
||||
initArrayStartIter->setValue(section->virtualAddr());
|
||||
initArrayEndIter->setValue(section->virtualAddr() +
|
||||
section->memSize());
|
||||
start->setValue(section->virtualAddr());
|
||||
end->setValue(section->virtualAddr() + section->memSize());
|
||||
} else {
|
||||
initArrayStartIter->setValue(0);
|
||||
initArrayEndIter->setValue(0);
|
||||
start->setValue(0);
|
||||
end->setValue(0);
|
||||
}
|
||||
};
|
||||
|
||||
startEnd(initArrayStartIter, initArrayEndIter, ".init_array");
|
||||
startEnd(realIpltStartIter, realIpltEndIter, ".rela.plt");
|
||||
|
||||
assert(!(bssStartAtomIter == _layout->absoluteAtoms().end() ||
|
||||
bssEndAtomIter == _layout->absoluteAtoms().end() ||
|
||||
|
@ -193,17 +203,15 @@ void ELFExecutableWriter<ELFT>::finalizeDefaultAtomValues() {
|
|||
"Unable to find the absolute atoms that have been added by lld");
|
||||
|
||||
auto phe = _programHeader->findProgramHeader(
|
||||
llvm::ELF::PT_LOAD,
|
||||
llvm::ELF::PF_W,
|
||||
llvm::ELF::PF_X);
|
||||
llvm::ELF::PT_LOAD, llvm::ELF::PF_W, llvm::ELF::PF_X);
|
||||
|
||||
assert(!(phe == _programHeader->end()) &&
|
||||
"Can't find a data segment in the program header!");
|
||||
|
||||
bssStartAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_filesz);
|
||||
bssEndAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
|
||||
underScoreEndAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
|
||||
endAtomIter->setValue((*phe)->p_vaddr+(*phe)->p_memsz);
|
||||
bssStartAtomIter->setValue((*phe)->p_vaddr + (*phe)->p_filesz);
|
||||
bssEndAtomIter->setValue((*phe)->p_vaddr + (*phe)->p_memsz);
|
||||
underScoreEndAtomIter->setValue((*phe)->p_vaddr + (*phe)->p_memsz);
|
||||
endAtomIter->setValue((*phe)->p_vaddr + (*phe)->p_memsz);
|
||||
}
|
||||
|
||||
template<class ELFT>
|
||||
|
|
|
@ -30,12 +30,19 @@ public:
|
|||
|
||||
virtual uint64_t getPageSize() const { return 0x1000; }
|
||||
|
||||
virtual void addPasses(PassManager &) const;
|
||||
|
||||
virtual uint64_t getBaseAddress() const {
|
||||
if (_options._baseAddress == 0)
|
||||
return 0x400000;
|
||||
return _options._baseAddress;
|
||||
}
|
||||
|
||||
virtual bool isRuntimeRelocation(const DefinedAtom &,
|
||||
const Reference &r) const {
|
||||
return r.kind() == llvm::ELF::R_X86_64_IRELATIVE;
|
||||
}
|
||||
|
||||
virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const;
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(int32_t kind) const;
|
||||
|
||||
|
|
|
@ -9,10 +9,129 @@
|
|||
|
||||
#include "X86_64ELFTargetInfo.h"
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/Pass.h"
|
||||
#include "lld/Core/PassManager.h"
|
||||
#include "lld/ReaderWriter/Simple.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
|
||||
using namespace lld;
|
||||
|
||||
namespace {
|
||||
class GOTAtom : public SimpleDefinedAtom {
|
||||
static const uint8_t _defaultContent[8];
|
||||
|
||||
public:
|
||||
GOTAtom(const File &f, const DefinedAtom *target) : SimpleDefinedAtom(f) {
|
||||
if (target->contentType() == typeResolver) {
|
||||
DEBUG_WITH_TYPE("GOTAtom", llvm::dbgs() << "IRELATIVE relocation to "
|
||||
<< target->name());
|
||||
addReference(llvm::ELF::R_X86_64_IRELATIVE, 0, target, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual StringRef name() const { return "ELF-GOTAtom"; }
|
||||
|
||||
virtual SectionChoice sectionChoice() const { return sectionCustomRequired; }
|
||||
|
||||
virtual StringRef customSectionName() const { return ".got.plt"; }
|
||||
|
||||
virtual ContentType contentType() const { return typeGOT; }
|
||||
|
||||
virtual uint64_t size() const { return rawContent().size(); }
|
||||
|
||||
virtual ContentPermissions permissions() const { return permRW_; }
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
return ArrayRef<uint8_t>(_defaultContent, 8);
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t GOTAtom::_defaultContent[8] = { 0 };
|
||||
|
||||
class PLTAtom : public SimpleDefinedAtom {
|
||||
static const uint8_t _defaultContent[16];
|
||||
|
||||
public:
|
||||
PLTAtom(const File &f, GOTAtom *ga) : SimpleDefinedAtom(f) {
|
||||
addReference(llvm::ELF::R_X86_64_PC32, 2, ga, -4);
|
||||
}
|
||||
|
||||
virtual StringRef name() const { return "ELF-PLTAtom"; }
|
||||
|
||||
virtual SectionChoice sectionChoice() const { return sectionCustomRequired; }
|
||||
|
||||
virtual StringRef customSectionName() const { return ".plt"; }
|
||||
|
||||
virtual ContentType contentType() const { return typeStub; }
|
||||
|
||||
virtual uint64_t size() const { return rawContent().size(); }
|
||||
|
||||
virtual ContentPermissions permissions() const { return permR_X; }
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
return ArrayRef<uint8_t>(_defaultContent, 16);
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t PLTAtom::_defaultContent[16] = {
|
||||
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
|
||||
0x68, 0x00, 0x00, 0x00, 0x00, // pushq pltentry
|
||||
0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
|
||||
};
|
||||
|
||||
class ELFPassFile : public SimpleFile {
|
||||
public:
|
||||
ELFPassFile(const ELFTargetInfo &eti) : SimpleFile(eti, "ELFPassFile") {}
|
||||
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
class PLTPass : public Pass {
|
||||
public:
|
||||
PLTPass(const ELFTargetInfo &ti) : _file(ti) {}
|
||||
|
||||
virtual void perform(MutableFile &mf) {
|
||||
for (const auto &atom : mf.defined())
|
||||
for (const auto &ref : *atom) {
|
||||
if (ref->kind() != llvm::ELF::R_X86_64_PC32)
|
||||
continue;
|
||||
if (const DefinedAtom *da =
|
||||
dyn_cast<const DefinedAtom>(ref->target())) {
|
||||
if (da->contentType() != DefinedAtom::typeResolver)
|
||||
continue;
|
||||
// We have a PC32 call to a IFUNC. Create a plt and got entry.
|
||||
// Look it up first.
|
||||
const PLTAtom *pa;
|
||||
auto plt = _pltMap.find(da);
|
||||
if (plt == _pltMap.end()) {
|
||||
// Add an entry.
|
||||
auto ga = new (_file._alloc) GOTAtom(_file, da);
|
||||
mf.addAtom(*ga);
|
||||
pa = new (_file._alloc) PLTAtom(_file, ga);
|
||||
mf.addAtom(*pa);
|
||||
_pltMap[da] = pa;
|
||||
} else
|
||||
pa = plt->second;
|
||||
// This is dirty.
|
||||
const_cast<Reference *>(ref)->setTarget(pa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::DenseMap<const DefinedAtom *, const PLTAtom *> _pltMap;
|
||||
ELFPassFile _file;
|
||||
};
|
||||
} // end anon namespace
|
||||
|
||||
void elf::X86_64ELFTargetInfo::addPasses(PassManager &pm) const {
|
||||
pm.add(std::unique_ptr<Pass>(new PLTPass(*this)));
|
||||
}
|
||||
|
||||
#define LLD_CASE(name) .Case(#name, llvm::ELF::name)
|
||||
|
||||
ErrorOr<int32_t> elf::X86_64ELFTargetInfo::relocKindFromString(StringRef str) const {
|
||||
|
|
|
@ -112,6 +112,8 @@ bool X86_64KindHandler::isLazyTarget(Kind kind) {
|
|||
void X86_64KindHandler::applyFixup(int32_t reloc, uint64_t addend,
|
||||
uint8_t *location, uint64_t fixupAddress,
|
||||
uint64_t targetAddress) {
|
||||
if (reloc == llvm::ELF::R_X86_64_IRELATIVE)
|
||||
return;
|
||||
if (_fixupHandler[reloc])
|
||||
_fixupHandler[reloc](location, fixupAddress, targetAddress, addend);
|
||||
else {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
extern "C" int hey();
|
||||
|
||||
int main() { return hey(); }
|
Binary file not shown.
|
@ -1,6 +1,27 @@
|
|||
RUN: lld -core -target x86_64-linux -emit-yaml -output=- %p/Inputs/ifunc.x86-64 \
|
||||
RUN: | FileCheck %s
|
||||
RUN: lld -core -target x86_64-linux -emit-yaml -output=- %p/Inputs/ifunc.x86-64 \
|
||||
RUN: %p/Inputs/ifunc.cpp.x86-64 | FileCheck %s --check-prefix=PLT
|
||||
|
||||
CHECK: name: hey
|
||||
CHECK: scope: global
|
||||
CHECK: type: resolver
|
||||
|
||||
// Get the target that main references.
|
||||
PLT: name: main
|
||||
PLT: scope: global
|
||||
PLT: references
|
||||
PLT: kind: R_X86_64_PC32
|
||||
PLT: target: [[PLTNAME:[a-zA-Z0-9-]+]]
|
||||
|
||||
// Make sure there's a got entry with a IRELATIVE relocation.
|
||||
PLT: type: got
|
||||
PLT: kind: R_X86_64_IRELATIVE
|
||||
|
||||
// Make sure the target of main's relocation is a stub with a PC32 relocation.
|
||||
// This relocation is to the got atom, but you can't really write that check in
|
||||
// FileCheck.
|
||||
PLT: name: [[PLTNAME]]
|
||||
PLT: type: stub
|
||||
PLT: references
|
||||
PLT: kind: R_X86_64_PC32
|
||||
|
|
Loading…
Reference in New Issue