[ELF][x86-64] Separate static and dynamic GOT/PLT generation.

llvm-svn: 176294
This commit is contained in:
Michael J. Spencer 2013-02-28 20:04:32 +00:00
parent ca5a85fad4
commit a26f71c9ed
16 changed files with 316 additions and 116 deletions

View File

@ -164,9 +164,11 @@ public:
_references.push_back(SimpleReference(kind, offset, target, addend));
}
void setOrdinal(uint64_t ord) { _ordinal = ord; }
private:
const File &_file;
uint32_t _ordinal;
uint64_t _ordinal;
std::vector<SimpleReference> _references;
};

View File

@ -184,10 +184,7 @@ public:
, _referenceStartIndex(referenceStart)
, _referenceEndIndex(referenceEnd)
, _referenceList(referenceList)
, _targetAtomHandler(nullptr) {
static uint64_t orderNumber = 0;
_ordinal = ++orderNumber;
}
, _targetAtomHandler(nullptr) {}
virtual const ELFFile<ELFT> &file() const {
return _owningFile;
@ -480,8 +477,9 @@ public:
_referenceEndIndex = _referenceList.size();
}
private:
void setOrdinal(uint64_t ord) { _ordinal = ord; }
private:
const ELFFile<ELFT> &_owningFile;
StringRef _symbolName;
StringRef _sectionName;

View File

@ -98,7 +98,8 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
*reinterpret_cast<llvm::support::little64_t *>(location) = result;
}
break;
case R_X86_64_TLSLD:
}
case R_X86_64_TLSLD: {
// Rewrite to move %fs:0 into %rax. Technically we should verify that the
// next relocation is a PC32 to __tls_get_addr...
static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
@ -106,9 +107,25 @@ ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
std::memcpy(location - 3, instr, sizeof(instr));
break;
}
case LLD_R_X86_64_GOTRELINDEX: {
const DefinedAtom *target = cast<const DefinedAtom>(ref.target());
for (const Reference *r : *target) {
if (r->kind() == R_X86_64_JUMP_SLOT) {
uint32_t index;
if (!_targetInfo.getTargetHandler<X86_64ELFType>().targetLayout()
.getPLTRelocationTable()->getRelocationIndex(*r, index))
llvm_unreachable("Relocation doesn't exist");
reloc32(location, 0, index, 0);
break;
}
}
break;
}
// Runtime only relocations. Ignore here.
case R_X86_64_RELATIVE:
case R_X86_64_IRELATIVE:
case R_X86_64_JUMP_SLOT:
case R_X86_64_GLOB_DAT:
break;
case lld::Reference::kindLayoutAfter:
@ -142,7 +159,7 @@ public:
virtual SectionChoice sectionChoice() const { return sectionCustomRequired; }
virtual StringRef customSectionName() const { return ".got"; }
virtual StringRef customSectionName() const { return ".got.plt"; }
virtual ContentType contentType() const { return typeGOT; }

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/StringSwitch.h"
using namespace lld;
using namespace lld::elf;
namespace {
using namespace llvm::ELF;
@ -90,8 +91,7 @@ public:
}
virtual Alignment alignment() const {
// The alignment should be 4 byte aligned
return Alignment(2);
return Alignment(4); // 16
}
#ifndef NDEBUG
@ -105,10 +105,31 @@ public:
const uint8_t PLTAtom::_defaultContent[16] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
0x68, 0x00, 0x00, 0x00, 0x00, // pushq pltentry
0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index
0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
};
class PLT0Atom : public PLTAtom {
static const uint8_t _plt0Content[16];
public:
PLT0Atom(const File &f) : PLTAtom(f, ".plt") {
#ifndef NDEBUG
_name = ".PLT0";
#endif
}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_plt0Content, 16);
}
};
const uint8_t PLT0Atom::_plt0Content[16] = {
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
0x90, 0x90, 0x90, 0x90 // nopnopnop
};
class ELFPassFile : public SimpleFile {
public:
ELFPassFile(const ELFTargetInfo &eti) : SimpleFile(eti, "ELFPassFile") {}
@ -121,16 +142,15 @@ public:
template <class Derived> class GOTPLTPass : public Pass {
/// \brief Handle a specific reference.
void handleReference(const DefinedAtom &atom, const Reference &ref) {
const DefinedAtom *da = dyn_cast_or_null<const DefinedAtom>(ref.target());
switch (ref.kind()) {
case R_X86_64_PLT32:
static_cast<Derived *>(this)->handlePLT32(ref);
break;
case R_X86_64_PC32:
static_cast<Derived *>(this)->handleIFUNC(ref, da);
static_cast<Derived *>(this)->handlePC32(ref);
break;
case R_X86_64_GOTTPOFF: // GOT Thread Pointer Offset
static_cast<Derived *>(this)->handleGOTTPOFF(ref, da);
static_cast<Derived *>(this)->handleGOTTPOFF(ref);
break;
case R_X86_64_GOTPCREL:
static_cast<Derived *>(this)->handleGOTPCREL(ref);
@ -165,7 +185,8 @@ protected:
///
/// This create a PLT and GOT entry for the IFUNC if one does not exist. The
/// GOT entry and a IRELATIVE relocation to the original target resolver.
ErrorOr<void> handleIFUNC(const Reference &ref, const DefinedAtom *target) {
ErrorOr<void> handleIFUNC(const Reference &ref) {
auto target = dyn_cast_or_null<const DefinedAtom>(ref.target());
if (target && target->contentType() == DefinedAtom::typeResolver)
const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target));
return error_code::success();
@ -189,7 +210,8 @@ protected:
/// \brief Create a TPOFF64 GOT entry and change the relocation to a PC32 to
/// the GOT.
void handleGOTTPOFF(const Reference &ref, const DefinedAtom *target) {
void handleGOTTPOFF(const Reference &ref) {
auto target = dyn_cast_or_null<const DefinedAtom>(ref.target());
const_cast<Reference &>(ref).setTarget(getGOTTPOFF(target));
const_cast<Reference &>(ref).setKind(R_X86_64_PC32);
}
@ -197,7 +219,7 @@ protected:
/// \brief Create a GOT entry containing 0.
const GOTAtom *getNullGOT() {
if (!_null) {
_null = new (_file._alloc) GOTAtom(_file, ".got");
_null = new (_file._alloc) GOTAtom(_file, ".got.plt");
#ifndef NDEBUG
_null->_name = "__got_null";
#endif
@ -231,7 +253,9 @@ protected:
}
public:
GOTPLTPass(const ELFTargetInfo &ti) : _file(ti), _null(nullptr) {}
GOTPLTPass(const ELFTargetInfo &ti)
: _file(ti), _null(nullptr), _PLT0(nullptr), _got0(nullptr),
_got1(nullptr) {}
/// \brief Do the pass.
///
@ -248,23 +272,51 @@ public:
handleReference(*atom, *ref);
// Add all created atoms to the link.
if (_null)
mf.addAtom(*_null);
for (const auto &got : _gotMap)
mf.addAtom(*got.second);
for (const auto &plt : _pltMap)
uint64_t ordinal = 0;
if (_PLT0) {
_PLT0->setOrdinal(ordinal++);
mf.addAtom(*_PLT0);
}
for (const auto &plt : _pltMap) {
plt.second->setOrdinal(ordinal++);
mf.addAtom(*plt.second);
}
if (_null) {
_null->setOrdinal(ordinal++);
mf.addAtom(*_null);
}
if (_PLT0) {
_got0->setOrdinal(ordinal++);
_got1->setOrdinal(ordinal++);
mf.addAtom(*_got0);
mf.addAtom(*_got1);
}
for (const auto &got : _gotMap) {
got.second->setOrdinal(ordinal++);
mf.addAtom(*got.second);
}
}
protected:
/// \brief Owner of all the Atoms created by this pass.
ELFPassFile _file;
/// \brief Map Atoms to their GOT entries.
llvm::DenseMap<const Atom *, const GOTAtom *> _gotMap;
llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
/// \brief Map Atoms to their PLT entries.
llvm::DenseMap<const Atom *, const PLTAtom *> _pltMap;
llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
/// \brief GOT entry that is always 0. Used for undefined weaks.
GOTAtom *_null;
/// \brief The got and plt entries for .PLT0. This is used to call into the
/// dynamic linker for symbol resolution.
/// @{
PLT0Atom *_PLT0;
GOTAtom *_got0;
GOTAtom *_got1;
/// @}
};
/// This implements the static relocation model. Meaning GOT and PLT entries are
@ -288,23 +340,47 @@ public:
// Handle IFUNC.
if (const DefinedAtom *da = dyn_cast_or_null<const DefinedAtom>(ref.target()))
if (da->contentType() == DefinedAtom::typeResolver)
return handleIFUNC(ref, da);
return handleIFUNC(ref);
return error_code::success();
}
ErrorOr<void> handlePC32(const Reference &ref) { return handleIFUNC(ref); }
};
class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass<DynamicGOTPLTPass> {
public:
DynamicGOTPLTPass(const elf::X86_64TargetInfo &ti) : GOTPLTPass(ti) {}
const PLT0Atom *getPLT0() {
if (_PLT0)
return _PLT0;
// Fill in the null entry.
getNullGOT();
_PLT0 = new (_file._alloc) PLT0Atom(_file);
_got0 = new (_file._alloc) GOTAtom(_file, ".got.plt");
_got1 = new (_file._alloc) GOTAtom(_file, ".got.plt");
_PLT0->addReference(R_X86_64_PC32, 2, _got0, -4);
_PLT0->addReference(R_X86_64_PC32, 8, _got1, -4);
#ifndef NDEBUG
_got0->_name = "__got0";
_got1->_name = "__got1";
#endif
return _PLT0;
}
const PLTAtom *getPLTEntry(const Atom *a) {
auto plt = _pltMap.find(a);
if (plt != _pltMap.end())
return plt->second;
auto ga = new (_file._alloc) GOTAtom(_file, ".got.plt");
ga->addReference(R_X86_64_RELATIVE, 0, a, 0);
ga->addReference(R_X86_64_JUMP_SLOT, 0, a, 0);
auto pa = new (_file._alloc) PLTAtom(_file, ".plt");
pa->addReference(R_X86_64_PC32, 2, ga, -4);
pa->addReference(LLD_R_X86_64_GOTRELINDEX, 7, ga, 0);
pa->addReference(R_X86_64_PC32, 12, getPLT0(), -4);
// Set the starting address of the got entry to the second instruction in
// the plt entry.
ga->addReference(R_X86_64_64, 0, pa, 6);
#ifndef NDEBUG
ga->_name = "__got_";
ga->_name += a->name();
@ -322,10 +398,16 @@ public:
// Handle IFUNC.
if (const DefinedAtom *da = dyn_cast_or_null<const DefinedAtom>(ref.target()))
if (da->contentType() == DefinedAtom::typeResolver)
return handleIFUNC(ref, da);
return handleIFUNC(ref);
const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
return error_code::success();
}
ErrorOr<void> handlePC32(const Reference &ref) {
if (ref.target() && isa<SharedLibraryAtom>(ref.target()))
return handlePLT32(ref);
return handleIFUNC(ref);
}
};
} // end anon namespace
@ -335,6 +417,7 @@ void elf::X86_64TargetInfo::addPasses(PassManager &pm) const {
else if (_options._outputKind == OutputKind::DynamicExecutable ||
_options._outputKind == OutputKind::Shared)
pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this)));
ELFTargetInfo::addPasses(pm);
}
#define LLD_CASE(name) .Case(#name, llvm::ELF::name)
@ -380,6 +463,7 @@ ErrorOr<int32_t> elf::X86_64TargetInfo::relocKindFromString(
LLD_CASE(R_X86_64_TLSDESC_CALL)
LLD_CASE(R_X86_64_TLSDESC)
LLD_CASE(R_X86_64_IRELATIVE)
.Case("LLD_R_X86_64_GOTRELINDEX", LLD_R_X86_64_GOTRELINDEX)
.Default(-1);
if (ret == -1)
@ -432,6 +516,8 @@ ErrorOr<std::string> elf::X86_64TargetInfo::stringFromRelocKind(
LLD_CASE(R_X86_64_TLSDESC_CALL)
LLD_CASE(R_X86_64_TLSDESC)
LLD_CASE(R_X86_64_IRELATIVE)
case LLD_R_X86_64_GOTRELINDEX:
return std::string("LLD_R_X86_64_GOTRELINDEX");
}
return make_error_code(yaml_reader_error::illegal_value);

View File

@ -20,6 +20,12 @@
namespace lld {
namespace elf {
/// \brief x86-64 internal references.
enum {
/// \brief The 32 bit index of the relocation in the got this reference refers
/// to.
LLD_R_X86_64_GOTRELINDEX = 1024,
};
class X86_64TargetInfo LLVM_FINAL : public ELFTargetInfo {
public:
@ -38,9 +44,26 @@ public:
return _options._baseAddress;
}
virtual bool isRuntimeRelocation(const DefinedAtom &,
virtual bool isDynamicRelocation(const DefinedAtom &,
const Reference &r) const {
return r.kind() == llvm::ELF::R_X86_64_IRELATIVE;
switch (r.kind()){
case llvm::ELF::R_X86_64_RELATIVE:
case llvm::ELF::R_X86_64_GLOB_DAT:
return true;
default:
return false;
}
}
virtual bool isPLTRelocation(const DefinedAtom &,
const Reference &r) const {
switch (r.kind()){
case llvm::ELF::R_X86_64_JUMP_SLOT:
case llvm::ELF::R_X86_64_IRELATIVE:
return true;
default:
return false;
}
}
virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const;

View File

@ -1,7 +0,0 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
RUN: -output-type=dynamic
RUN: llvm-readobj %t | FileCheck %s
CHECK: Sections:
CHECK: .hash {{[0-9a-f]+}} 8 4 required,rodata

View File

@ -1,8 +0,0 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
RUN: -output-type=dynamic
RUN: llvm-objdump -p %t | FileCheck %s
CHECK: INTERP
CHECK: flags r--
CHECK: off

View File

@ -1,18 +0,0 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -output=- -noinhibit-exec \
RUN: -output-type=dynamic \
RUN: | FileCheck %s
CHECK: name: main
CHECK: kind: R_X86_64_PC32
CHECK: target: [[PLTNAME:[-a-zA-Z0-9_]+]]
CHECK: type: got
CHECK: R_X86_64_RELATIVE
CHECK: name: [[PLTNAME]]
CHECK: type: stub
CHECK: shared-library-atoms:
CHECK: name: foo
CHECK: load-name: shared.so-x86-64

View File

@ -1,7 +0,0 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
RUN: -output-type=dynamic
RUN: llvm-objdump -p %t | FileCheck %s
CHECK: PHDR off 0x{{0+}}40
CHECK: flags r--

View File

@ -1,8 +0,0 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
RUN: -output-type=dynamic
RUN: llvm-readobj %t | FileCheck %s
CHECK: Dynamic Symbols:
CHECK: foo FUNC {{[0-9a-f]+}} 0 {{[0-9a-f]+}} undef,global
CHECK: Total: 1

View File

@ -1,15 +0,0 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
RUN: -output-type=dynamic
RUN: llvm-readobj %t | FileCheck %s
CHECK: Dynamic section contains 7 entries
CHECK: Tag Type Name/Value
CHECK: 0x0000000000000004 (HASH)
CHECK: 0x0000000000000005 (STRTAB)
CHECK: 0x0000000000000006 (SYMTAB)
CHECK: 0x000000000000000a (STRSZ)
CHECK: 0x000000000000000b (SYMENT) 24
CHECK: 0x0000000000000001 (NEEDED) Shared library: [shared.so-x86-64]
CHECK: 0x0000000000000000 (NULL) 0x0
CHECK: Total: 7

49
lld/test/elf/dynamic.test Normal file
View File

@ -0,0 +1,49 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
RUN: -output-type=dynamic
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -output=%t2 -noinhibit-exec \
RUN: -output-type=dynamic
RUN: llvm-objdump -p %t >> %t2
RUN: llvm-readobj %t >> %t2
RUN: FileCheck %s < %t2
CHECK: type: got
CHECK: R_X86_64_JUMP_SLOT
CHECK: name: main
CHECK: kind: R_X86_64_PC32
CHECK: target: [[PLTNAME:[-a-zA-Z0-9_]+]]
CHECK: name: [[PLTNAME]]
CHECK: type: stub
CHECK: shared-library-atoms:
CHECK: name: foo
CHECK: load-name: shared.so-x86-64
CHECK: PHDR off 0x{{0+}}40
CHECK: INTERP
CHECK: flags r--
CHECK: Dynamic Symbols:
CHECK: foo FUNC {{[0-9a-f]+}} 0 {{[0-9a-f]+}} undef,global
CHECK: Total: 1
CHECK: Sections:
CHECK: .hash {{[0-9a-f]+}} 8 4 required,rodata
CHECK: Dynamic section contains 11 entries
CHECK: Tag Type Name/Value
CHECK: 0x0000000000000004 (HASH)
CHECK: 0x0000000000000005 (STRTAB)
CHECK: 0x0000000000000006 (SYMTAB)
CHECK: 0x000000000000000a (STRSZ)
CHECK: 0x000000000000000b (SYMENT) 24
CHECK: 0x0000000000000002 (PLTRELSZ) 24
CHECK: 0x0000000000000003 (PLTGOT)
CHECK: 0x0000000000000014 (PLTREL) RELA
CHECK: 0x0000000000000017 (JMPREL)
CHECK: 0x0000000000000001 (NEEDED) Shared library: [shared.so-x86-64]
CHECK: 0x0000000000000000 (NULL) 0x0
CHECK: Total: 11

View File

@ -2,16 +2,16 @@ RUN: lld -core -target x86_64-linux -output=- -entry=main -output-type=static \
RUN: %p/Inputs/gotpcrel.x86-64 -emit-yaml -noinhibit-exec \
RUN: | FileCheck %s -check-prefix=YAML
YAML: name: main
YAML: kind: R_X86_64_PC32
YAML: target: [[NULLGOT:[a-zA-Z0-9_]+]]
YAML: kind: R_X86_64_PC32
YAML: target: [[MAINGOT:[a-zA-Z0-9_]+]]
YAML: name: [[NULLGOT]]
YAML: name: [[NULLGOT:[a-zA-Z0-9_]+]]
YAML: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
YAML-NOT: references:
YAML: name: [[MAINGOT]]
YAML: name: [[MAINGOT:[a-zA-Z0-9_]+]]
YAML: kind: R_X86_64_64
YAML: target: main
YAML: name: main
YAML: kind: R_X86_64_PC32
YAML: target: [[NULLGOT]]
YAML: kind: R_X86_64_PC32
YAML: target: [[MAINGOT]]

View File

@ -9,9 +9,10 @@ RUN: lld -core -target x86_64-linux -output=%t %p/Inputs/ifunc.x86-64 \
RUN: -entry=main -output-type=static %p/Inputs/ifunc.cpp.x86-64 \
RUN: && llvm-objdump -d -s %t| FileCheck %s --check-prefix=BIN
CHECK: name: hey
CHECK: scope: global
CHECK: type: resolver
// Make sure there's a got entry with a IRELATIVE relocation.
PLT: type: got
PLT: kind: R_X86_64_IRELATIVE
PLT: target: hey
PLT: name: plt
PLT: scope: global
@ -24,9 +25,9 @@ PLT: references
PLT: kind: R_X86_64_PC32
PLT: target: [[PLTNAME]]
// Make sure there's a got entry with a IRELATIVE relocation.
PLT: type: got
PLT: kind: R_X86_64_IRELATIVE
CHECK: name: hey
CHECK: scope: global
CHECK: type: resolver
// 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
@ -36,8 +37,6 @@ PLT: type: stub
PLT: references
PLT: kind: R_X86_64_PC32
// This is a horribly brittle test. We need a way to do arithmetic on captured
// variables.
BIN: 4000ec: ff 25 0e 0f 00 00 jmpq *3854(%rip)
BIN: {{[0-9a-f]+}}: ff 25 {{[0-9a-f]+}} {{[0-9a-f]+}} 00 00 jmpq *{{[0-9]+}}(%rip)
BIN: .got.plt:
BIN-NEXT: 401000 00000000 00000000
BIN-NEXT: {{[0-9a-f]+}} 00000000 00000000

View File

@ -8,6 +8,10 @@ RUN: | FileCheck %s
// Verify that the TLS accesses have the correct offsets.
YAML: type: got
YAML: kind: R_X86_64_TPOFF64
YAML: target: tls2
YAML: name: main
YAML: kind: R_X86_64_TPOFF32
YAML: offset: 9
@ -23,11 +27,6 @@ YAML: name: GOTTPOFF
YAML: kind: R_X86_64_PC32
YAML: target: [[GOTNAME:[a-zA-Z0-9_]+]]
YAML: name: [[GOTNAME]]
YAML: type: got
YAML: kind: R_X86_64_TPOFF64
YAML: target: tls2
// main
CHECK: addl %fs:-4
CHECK: addl %fs:-8

View File

@ -0,0 +1,90 @@
RUN: lld -core -target x86_64-linux %p/Inputs/use-shared.x86-64 \
RUN: %p/Inputs/shared.so-x86-64 -emit-yaml -output=- -noinhibit-exec \
RUN: -output-type=dynamic | FileCheck %s
// Don't check the GOT and PLT names as they are only present in assert builds.
- name: __got_null
CHECK: type: got
CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
CHECK: alignment: 2^3
CHECK: section-choice: custom-required
CHECK: section-name: .got.plt
CHECK: permissions: rw-
- name: __got0
CHECK: type: got
CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
CHECK: alignment: 2^3
CHECK: section-choice: custom-required
CHECK: section-name: .got.plt
CHECK: permissions: rw-
- name: __got1
CHECK: type: got
CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
CHECK: alignment: 2^3
CHECK: section-choice: custom-required
CHECK: section-name: .got.plt
CHECK: permissions: rw-
- name: __got_foo
CHECK: type: got
CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
CHECK: alignment: 2^3
CHECK: section-choice: custom-required
CHECK: section-name: .got.plt
CHECK: permissions: rw-
CHECK: references:
CHECK: - kind: R_X86_64_JUMP_SLOT
CHECK: offset: 0
CHECK: target: foo
CHECK: - kind: R_X86_64_64
CHECK: offset: 0
target: __plt_foo
CHECK: addend: 6
CHECK: - name: main
CHECK: scope: global
CHECK: references:
CHECK: - kind: R_X86_64_PC32
CHECK: offset: 7
target: __plt_foo
CHECK: addend: -4
- name: .PLT0
CHECK: type: stub
CHECK: content: [ FF, 35, 00, 00, 00, 00, FF, 25, 00, 00, 00, 00,
CHECK: 90, 90, 90, 90 ]
CHECK: alignment: 2^4
CHECK: section-choice: custom-required
CHECK: section-name: .plt
CHECK: references:
CHECK: - kind: R_X86_64_PC32
CHECK: offset: 2
target: __got0
CHECK: addend: -4
CHECK: - kind: R_X86_64_PC32
CHECK: offset: 8
target: __got1
CHECK: addend: -4
- name: __plt_foo
CHECK: type: stub
CHECK: content: [ FF, 25, 00, 00, 00, 00, 68, 00, 00, 00, 00, E9,
CHECK: 00, 00, 00, 00 ]
CHECK: alignment: 2^4
CHECK: section-choice: custom-required
CHECK: section-name: .plt
CHECK: references:
CHECK: - kind: R_X86_64_PC32
CHECK: offset: 2
target: __got_foo
CHECK: addend: -4
CHECK: - kind: LLD_R_X86_64_GOTRELINDEX
CHECK: offset: 7
target: __got_foo
CHECK: - kind: R_X86_64_PC32
CHECK: offset: 12
target: .PLT0
CHECK: addend: -4
CHECK:shared-library-atoms:
CHECK: - name: foo
CHECK: load-name: shared.so-x86-64