_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;
};
, _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;
_referenceEndIndex = _referenceList.size();
}
-private:
+ void setOrdinal(uint64_t ord) { _ordinal = ord; }
+private:
const ELFFile<ELFT> &_owningFile;
StringRef _symbolName;
StringRef _sectionName;
*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,
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:
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; }
#include "llvm/ADT/StringSwitch.h"
using namespace lld;
+using namespace lld::elf;
namespace {
using namespace llvm::ELF;
}
virtual Alignment alignment() const {
- // The alignment should be 4 byte aligned
- return Alignment(2);
+ return Alignment(4); // 16
}
#ifndef NDEBUG
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") {}
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);
///
/// 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();
/// \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);
}
/// \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
}
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.
///
handleReference(*atom, *ref);
// Add all created atoms to the link.
- if (_null)
+ 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);
- for (const auto &got : _gotMap)
+ }
+ 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);
- for (const auto &plt : _pltMap)
- mf.addAtom(*plt.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
// 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();
// 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
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)
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)
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);
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:
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;
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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--
+++ /dev/null
-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
+++ /dev/null
-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
--- /dev/null
+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
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]]
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
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
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
// 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
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
--- /dev/null
+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