summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp255
-rw-r--r--lld/test/elf/ARM/plt-interwork.test340
-rw-r--r--lld/test/elf/ARM/rel-ifunc.test8
3 files changed, 510 insertions, 93 deletions
diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
index 86b3ec30390..713d4dfd79f 100644
--- a/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
+++ b/lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
@@ -20,7 +20,7 @@
#include "ARMLinkingContext.h"
#include "Atoms.h"
#include "lld/Core/Simple.h"
-#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
@@ -51,13 +51,15 @@ static const uint8_t ARMGotAtomContent[4] = {0};
// .plt values (other entries)
static const uint8_t ARMPltAtomContent[12] = {
- 0x00, 0xc0, 0x8f,
- 0xe2, // add ip, pc, #offset[G0]
- 0x00, 0xc0, 0x8c,
- 0xe2, // add ip, ip, #offset[G1]
+ 0x00, 0xc0, 0x8f, 0xe2, // add ip, pc, #offset[G0]
+ 0x00, 0xc0, 0x8c, 0xe2, // add ip, ip, #offset[G1]
+ 0x00, 0xf0, 0xbc, 0xe5 // ldr pc, [ip, #offset[G2]]!
+};
- 0x00, 0xf0, 0xbc,
- 0xe5, // ldr pc, [ip, #offset[G2]]!
+// Veneer for switching from Thumb to ARM code for PLT entries.
+static const uint8_t ARMPltVeneerAtomContent[4] = {
+ 0x78, 0x47, // bx pc
+ 0x00, 0x00 // nop
};
/// \brief Atoms that hold veneer code.
@@ -121,22 +123,48 @@ public:
/// \brief Atoms that are used by ARM dynamic linking
class ARMGOTAtom : public GOTAtom {
public:
- ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+ ARMGOTAtom(const File &f) : GOTAtom(f, ".got") {}
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(ARMGotAtomContent);
}
Alignment alignment() const override { return 4; }
+
+protected:
+ // Constructor for PLTGOT atom.
+ ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
+};
+
+class ARMGOTPLTAtom : public ARMGOTAtom {
+public:
+ ARMGOTPLTAtom(const File &f) : ARMGOTAtom(f, ".got.plt") {}
};
class ARMPLTAtom : public PLTAtom {
public:
- ARMPLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
+ ARMPLTAtom(const File &f) : PLTAtom(f, ".plt") {}
ArrayRef<uint8_t> rawContent() const override {
return llvm::makeArrayRef(ARMPltAtomContent);
}
+
+ Alignment alignment() const override { return 4; }
+};
+
+class ARMPLTVeneerAtom : public PLTAtom {
+public:
+ ARMPLTVeneerAtom(const File &f) : PLTAtom(f, ".plt") {}
+
+ DefinedAtom::CodeModel codeModel() const override {
+ return DefinedAtom::codeARMThumb;
+ }
+
+ ArrayRef<uint8_t> rawContent() const override {
+ return llvm::makeArrayRef(ARMPltVeneerAtomContent);
+ }
+
+ Alignment alignment() const override { return 4; }
};
class ELFPassFile : public SimpleFile {
@@ -172,7 +200,7 @@ template <class Derived> class ARMRelocationPass : public Pass {
case R_ARM_JUMP24:
case R_ARM_THM_JUMP24:
case R_ARM_THM_JUMP11:
- static_cast<Derived *>(this)->handleIFUNC(ref);
+ static_cast<Derived *>(this)->handleIFUNC(atom, ref);
static_cast<Derived *>(this)->handleVeneer(atom, ref);
break;
case R_ARM_TLS_IE32:
@@ -188,10 +216,15 @@ template <class Derived> class ARMRelocationPass : public Pass {
protected:
std::error_code handleVeneer(const DefinedAtom &atom, const Reference &ref) {
+ const VeneerAtom *(Derived::*getVeneer)(const DefinedAtom *, StringRef) =
+ nullptr;
const auto kindValue = ref.kindValue();
switch (kindValue) {
case R_ARM_JUMP24:
+ getVeneer = &Derived::getVeneer_ARM_B_BL;
+ break;
case R_ARM_THM_JUMP24:
+ getVeneer = &Derived::getVeneer_THM_B_BL;
break;
default:
return std::error_code();
@@ -226,19 +259,9 @@ protected:
llvm_unreachable(errStr.c_str());
}
- const Atom *veneer = nullptr;
- switch (kindValue) {
- case R_ARM_JUMP24:
- veneer = static_cast<Derived *>(this)
- ->getVeneer_ARM_B_BL(target, secName);
- break;
- case R_ARM_THM_JUMP24:
- veneer = static_cast<Derived *>(this)
- ->getVeneer_THM_B_BL(target, secName);
- break;
- default:
- llvm_unreachable("Unhandled reference type for veneer generation");
- }
+ assert(getVeneer && "The veneer handler is missing");
+ const Atom *veneer =
+ (static_cast<Derived *>(this)->*getVeneer)(target, secName);
assert(veneer && "The veneer is not set");
const_cast<Reference &>(ref).setTarget(veneer);
@@ -257,64 +280,113 @@ protected:
/// \brief Create a GOT entry for TLS with reloc type and addend specified.
template <Reference::KindValue R_ARM_TLS, Reference::Addend A = 0>
const GOTAtom *getGOTTLSEntry(const DefinedAtom *da) {
- auto got = _gotMap.find(da);
- if (got != _gotMap.end())
- return got->second;
- auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
+ if (auto got = _gotAtoms.lookup(da))
+ return got;
+ auto g = new (_file._alloc) ARMGOTAtom(_file);
g->addReferenceELF_ARM(R_ARM_TLS, 0, da, A);
#ifndef NDEBUG
g->_name = "__got_tls_";
g->_name += da->name();
#endif
- _gotMap[da] = g;
- _gotVector.push_back(g);
+ _gotAtoms[da] = g;
return g;
}
- /// \brief Create a PLT entry referencing PLTGOT entry.
+ /// \brief get a veneer for a PLT entry.
+ const PLTAtom *getPLTVeneer(const DefinedAtom *da, PLTAtom *pa,
+ StringRef source) {
+ auto va = new (_file._alloc) ARMPLTVeneerAtom(_file);
+ // Fake reference to show connection between veneer and PLT entry.
+ va->addReferenceELF_ARM(R_ARM_NONE, 0, pa, 0);
+#ifndef NDEBUG
+ va->_name = "__plt_from_thumb";
+ va->_name += source;
+ va->_name += da->name();
+#endif
+ _pltAtoms[da] = PLTWithVeneer(pa, va);
+ return va;
+ }
+
+ typedef const GOTAtom *(Derived::*GOTFactory)(const DefinedAtom *);
+
+ /// \brief get a PLT entry referencing PLTGOT entry.
///
- /// The function creates the PLT entry object and passes ownership
- /// over it to the caller.
- PLTAtom *createPLTforGOT(const GOTAtom *ga) {
- auto pa = new (_file._alloc) ARMPLTAtom(_file, ".plt");
+ /// If the entry does not exist, both GOT and PLT entry are created.
+ const PLTAtom *getPLTEntry(const DefinedAtom *da, bool fromThumb,
+ GOTFactory gotFactory, StringRef source) {
+ auto pltVeneer = _pltAtoms.lookup(da);
+ if (!pltVeneer.empty()) {
+ // Return clean PLT entry provided it is ARM code.
+ if (!fromThumb)
+ return pltVeneer._plt;
+
+ // Check if veneer is present for Thumb to ARM transition.
+ if (pltVeneer._veneer)
+ return pltVeneer._veneer;
+
+ // Create veneer for existing PLT entry.
+ return getPLTVeneer(da, pltVeneer._plt, source);
+ }
+
+ // Create specific GOT entry.
+ const auto *ga = (static_cast<Derived *>(this)->*gotFactory)(da);
+ assert(_gotAtoms.lookup(da) == ga &&
+ "GOT entry should be added to the map");
+ assert(ga->customSectionName() == ".got.plt" &&
+ "GOT entry should be in a special section");
+
+ // Create PLT entry for the GOT entry.
+ auto pa = new (_file._alloc) ARMPLTAtom(_file);
pa->addReferenceELF_ARM(R_ARM_ALU_PC_G0_NC, 0, ga, -8);
pa->addReferenceELF_ARM(R_ARM_ALU_PC_G1_NC, 4, ga, -4);
pa->addReferenceELF_ARM(R_ARM_LDR_PC_G2, 8, ga, 0);
+#ifndef NDEBUG
+ pa->_name = "__plt";
+ pa->_name += source;
+ pa->_name += da->name();
+#endif
+ // Since all PLT entries are in ARM code, Thumb to ARM
+ // switching should be added if the relocated place contais Thumb code.
+ if (fromThumb)
+ return getPLTVeneer(da, pa, source);
+
+ // Otherwise just add PLT entry and return it to the caller.
+ _pltAtoms[da] = PLTWithVeneer(pa);
return pa;
}
+ /// \brief Create the GOT entry for a given IFUNC Atom.
+ const GOTAtom *createIFUNCGOTEntry(const DefinedAtom *da) {
+ assert(!_gotAtoms.lookup(da) && "IFUNC GOT entry already exists");
+ auto g = new (_file._alloc) ARMGOTPLTAtom(_file);
+ g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0);
+ g->addReferenceELF_ARM(R_ARM_IRELATIVE, 0, da, 0);
+#ifndef NDEBUG
+ g->_name = "__got_ifunc_";
+ g->_name += da->name();
+#endif
+ _gotAtoms[da] = g;
+ return g;
+ }
+
/// \brief get the PLT entry for a given IFUNC Atom.
- ///
- /// If the entry does not exist. Both the GOT and PLT entry is created.
- const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da) {
- auto plt = _pltMap.find(da);
- if (plt != _pltMap.end())
- return plt->second;
- auto ga = new (_file._alloc) ARMGOTAtom(_file, ".got.plt");
- ga->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0);
- ga->addReferenceELF_ARM(R_ARM_IRELATIVE, 0, da, 0);
- auto pa = createPLTforGOT(ga);
+ const PLTAtom *getIFUNCPLTEntry(const DefinedAtom *da, bool fromThumb) {
+ StringRef source;
#ifndef NDEBUG
- ga->_name = "__got_ifunc_";
- ga->_name += da->name();
- pa->_name = "__plt_ifunc_";
- pa->_name += da->name();
+ source = "_ifunc_";
#endif
- _gotMap[da] = ga;
- _pltMap[da] = pa;
- _gotVector.push_back(ga);
- _pltVector.push_back(pa);
- return pa;
+ return getPLTEntry(da, fromThumb, &Derived::createIFUNCGOTEntry, source);
}
/// \brief Redirect the call to the PLT stub for the target IFUNC.
///
/// 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.
- std::error_code handleIFUNC(const Reference &ref) {
+ std::error_code handleIFUNC(const DefinedAtom &atom, const Reference &ref) {
auto target = dyn_cast<const DefinedAtom>(ref.target());
if (target && target->contentType() == DefinedAtom::typeResolver) {
- const_cast<Reference &>(ref).setTarget(getIFUNCPLTEntry(target));
+ const_cast<Reference &>(ref).setTarget(
+ getIFUNCPLTEntry(target, isThumbCode(atom.codeModel())));
}
return std::error_code();
}
@@ -322,7 +394,7 @@ protected:
/// \brief Create a GOT entry containing 0.
const GOTAtom *getNullGOT() {
if (!_null) {
- _null = new (_file._alloc) ARMGOTAtom(_file, ".got.plt");
+ _null = new (_file._alloc) ARMGOTPLTAtom(_file);
#ifndef NDEBUG
_null->_name = "__got_null";
#endif
@@ -331,17 +403,15 @@ protected:
}
const GOTAtom *getGOT(const DefinedAtom *da) {
- auto got = _gotMap.find(da);
- if (got != _gotMap.end())
- return got->second;
- auto g = new (_file._alloc) ARMGOTAtom(_file, ".got");
+ if (auto got = _gotAtoms.lookup(da))
+ return got;
+ auto g = new (_file._alloc) ARMGOTAtom(_file);
g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0);
#ifndef NDEBUG
g->_name = "__got_";
g->_name += da->name();
#endif
- _gotMap[da] = g;
- _gotVector.push_back(g);
+ _gotAtoms[da] = g;
return g;
}
@@ -392,19 +462,27 @@ public:
// Add all created atoms to the link.
uint64_t ordinal = 0;
- for (auto &plt : _pltVector) {
- plt->setOrdinal(ordinal++);
- mf->addAtom(*plt);
+ for (auto &pltKV : _pltAtoms) {
+ auto &plt = pltKV.second;
+ if (auto *v = plt._veneer) {
+ v->setOrdinal(ordinal++);
+ mf->addAtom(*v);
+ }
+ auto *p = plt._plt;
+ p->setOrdinal(ordinal++);
+ mf->addAtom(*p);
}
if (_null) {
_null->setOrdinal(ordinal++);
mf->addAtom(*_null);
}
- for (auto &got : _gotVector) {
+ for (auto &gotKV : _gotAtoms) {
+ auto &got = gotKV.second;
got->setOrdinal(ordinal++);
mf->addAtom(*got);
}
- for (auto &veneer : _veneerVector) {
+ for (auto &veneerKV : _veneerAtoms) {
+ auto &veneer = veneerKV.second;
veneer->setOrdinal(ordinal++);
mf->addAtom(*veneer);
}
@@ -416,20 +494,25 @@ protected:
const ELFLinkingContext &_ctx;
/// \brief Map Atoms to their GOT entries.
- llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
+ llvm::MapVector<const Atom *, GOTAtom *> _gotAtoms;
- /// \brief Map Atoms to their PLT entries.
- llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
+ /// \brief Map Atoms to their PLT entries depending on the code model.
+ struct PLTWithVeneer {
+ PLTWithVeneer(PLTAtom *p = nullptr, PLTAtom *v = nullptr)
+ : _plt(p), _veneer(v) {}
- /// \brief Map Atoms to their veneers.
- llvm::DenseMap<const Atom *, VeneerAtom *> _veneerMap;
+ bool empty() const {
+ assert((_plt || !_veneer) && "Veneer appears without PLT entry");
+ return !_plt && !_veneer;
+ }
- /// \brief the list of GOT/PLT atoms
- std::vector<GOTAtom *> _gotVector;
- std::vector<PLTAtom *> _pltVector;
+ PLTAtom *_plt;
+ PLTAtom *_veneer;
+ };
+ llvm::MapVector<const Atom *, PLTWithVeneer> _pltAtoms;
- /// \brief the list of veneer atoms.
- std::vector<VeneerAtom *> _veneerVector;
+ /// \brief Map Atoms to their veneers.
+ llvm::MapVector<const Atom *, VeneerAtom *> _veneerAtoms;
/// \brief GOT entry that is always 0. Used for undefined weaks.
GOTAtom *_null = nullptr;
@@ -450,10 +533,8 @@ public:
/// \brief Get the veneer for ARM B/BL instructions.
const VeneerAtom *getVeneer_ARM_B_BL(const DefinedAtom *da,
StringRef secName) {
- auto veneer = _veneerMap.find(da);
- if (_veneerMap.end() != veneer)
- return veneer->second;
-
+ if (auto veneer = _veneerAtoms.lookup(da))
+ return veneer;
auto v = new (_file._alloc) Veneer_ARM_B_BL_StaticAtom(_file, secName);
v->addReferenceELF_ARM(R_ARM_ABS32, 4, da, 0);
@@ -461,18 +542,15 @@ public:
v->_name += da->name();
v->_name += "_from_arm";
- _veneerMap[da] = v;
- _veneerVector.push_back(v);
+ _veneerAtoms[da] = v;
return v;
}
/// \brief Get the veneer for Thumb B/BL instructions.
const VeneerAtom *getVeneer_THM_B_BL(const DefinedAtom *da,
StringRef secName) {
- auto veneer = _veneerMap.find(da);
- if (_veneerMap.end() != veneer)
- return veneer->second;
-
+ if (auto veneer = _veneerAtoms.lookup(da))
+ return veneer;
auto v = new (_file._alloc) Veneer_THM_B_BL_StaticAtom(_file, secName);
v->addReferenceELF_ARM(R_ARM_JUMP24, 4, da, 0);
@@ -480,8 +558,7 @@ public:
v->_name += da->name();
v->_name += "_from_thumb";
- _veneerMap[da] = v;
- _veneerVector.push_back(v);
+ _veneerAtoms[da] = v;
return v;
}
diff --git a/lld/test/elf/ARM/plt-interwork.test b/lld/test/elf/ARM/plt-interwork.test
new file mode 100644
index 00000000000..240d11dfb8a
--- /dev/null
+++ b/lld/test/elf/ARM/plt-interwork.test
@@ -0,0 +1,340 @@
+# Check that PLT entries are properly generated for cases when
+# referenced from both ARM and Thumb code.
+#
+# 1. ARM code generates PLT without transition veneer.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-f1-arm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-arm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=ARM-ONE %s
+
+# ARM-ONE: Contents of section .plt:
+# ARM-ONE-NEXT: 40007c 00c68fe2 00ca8ce2 7cffbce5
+# ^ regular veneer ^
+# Next line shows that .plt section ends.
+# ARM-ONE-NEXT: Contents of section .text:
+
+# 2. Thumb code generates PLT with transition veneer.
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-f1-thm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-thm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=THM-ONE %s
+
+# THM-ONE: Contents of section .plt:
+# THM-ONE-NEXT: 40007c 78470000 00c68fe2 00ca8ce2 78ffbce5
+# bx pc ^^ ^ regular veneer ^
+# Next line shows that .plt section ends.
+# THM-ONE-NEXT: Contents of section .text:
+
+# 3. ARM + Thumb code generate same single PLT with transition veneer.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-f1-arm.o
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-f1-thm-for-arm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-arm.o %t-f1-thm-for-arm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=THM-ONE %s
+
+# 4. Thumb + ARM code generate same single PLT with transition veneer.
+# RUN: yaml2obj -format=elf -docnum 3 %s > %t-f1-thm-for-arm.o
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-f1-arm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-thm-for-arm.o %t-f1-arm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=THM-ONE %s
+
+# 5. ARM + ARM code generate two PLTs without transition veneers.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-f1-arm.o
+# RUN: yaml2obj -format=elf -docnum 4 %s > %t-f2-arm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-arm.o %t-f2-arm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=ARM-TWO %s
+
+# ARM-TWO: Contents of section .plt:
+# ARM-TWO-NEXT: 400084 00c68fe2 00ca8ce2 74ffbce5 00c68fe2
+# ^ regular veneer 1 ^ ^ --
+# ARM-TWO-NEXT: 400094 00ca8ce2 6cffbce5
+# --- regular veneer 2 ^
+# Next line shows that .plt section ends.
+# ARM-TWO-NEXT: Contents of section .text:
+
+# 6. ARM + Thumb code generate two PLTs without and with transition veneer.
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t-f1-arm.o
+# RUN: yaml2obj -format=elf -docnum 5 %s > %t-f2-thm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-arm.o %t-f2-thm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=ARM-THM-TWO %s
+
+# ARM-THM-TWO: Contents of section .plt:
+# ARM-THM-TWO-NEXT: 400084 00c68fe2 00ca8ce2 74ffbce5 78470000
+# ^ regular veneer 1 ^ ^^ bx pc 2
+# ARM-THM-TWO-NEXT: 400094 00c68fe2 00ca8ce2 68ffbce5
+# ^ regular veneer 2 ^
+# Next line shows that .plt section ends.
+# ARM-THM-TWO-NEXT: Contents of section .text:
+
+# 7. Thumb + ARM code generate two PLTs with and without transition veneer.
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-f1-thm.o
+# RUN: yaml2obj -format=elf -docnum 4 %s > %t-f2-arm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-thm.o %t-f2-arm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=THM-ARM-TWO %s
+
+# THM-ARM-TWO: Contents of section .plt:
+# THM-ARM-TWO-NEXT: 400084 78470000 00c68fe2 00ca8ce2 70ffbce
+# bx pc 1 ^^ ^ regular veneer 1 ^
+# THM-ARM-TWO-NEXT: 400094 00c68fe2 00ca8ce2 68ffbce5
+# ^ regular veneer 2 ^
+# Next line shows that .plt section ends.
+# THM-ARM-TWO-NEXT: Contents of section .text:
+
+# 8. Thumb + Thumb code generate two PLTs with transition veneers.
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t-f1-thm.o
+# RUN: yaml2obj -format=elf -docnum 5 %s > %t-f2-thm.o
+# RUN: lld -flavor gnu -target arm-linux-gnu \
+# RUN: -Bstatic --noinhibit-exec %t-f1-thm.o %t-f2-thm.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck -check-prefix=THM-TWO %s
+
+# THM-TWO: Contents of section .plt:
+# THM-TWO-NEXT: 400084 78470000 00c68fe2 00ca8ce2 70ffbce5
+# bx pc 1 ^^ ^ regular veneer 1 ^
+# THM-TWO-NEXT: 400094 78470000 00c68fe2 00ca8ce2 64ffbce5
+# bx pc 2 ^^ ^ regular veneer 2 ^
+# Next line shows that .plt section ends.
+# THM-TWO-NEXT: Contents of section .text:
+
+# f1-arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE2003000E3003040E30300A0E100D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEB0030A0E10300A0E10088BDE8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000008
+ Symbol: main
+ Type: R_ARM_MOVW_ABS_NC
+ - Offset: 0x000000000000000C
+ Symbol: main
+ Type: R_ARM_MOVT_ABS
+ - Offset: 0x0000000000000028
+ Symbol: f1
+ Type: R_ARM_CALL
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: f1
+ Type: STT_GNU_IFUNC
+ Section: .text
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000020
+
+# f1-thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF40F20003C0F200031846BD465DF8047B704700BF80B500AFFFF7FEFF0346184680BD00BF
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: main
+ Type: R_ARM_THM_MOVW_ABS_NC
+ - Offset: 0x0000000000000008
+ Symbol: main
+ Type: R_ARM_THM_MOVT_ABS
+ - Offset: 0x000000000000001C
+ Symbol: f1
+ Type: R_ARM_THM_CALL
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: f1
+ Type: STT_GNU_IFUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000019
+
+# f1-thm-for-arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B500AFFFF7FEFF0346184680BD00BF
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: f1
+ Type: R_ARM_THM_CALL
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: f
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: f1
+
+# f2-arm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 04B02DE500B08DE2003000E3003040E30300A0E100D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEB0030A0E10300A0E10088BDE8
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000008
+ Symbol: f
+ Type: R_ARM_MOVW_ABS_NC
+ - Offset: 0x000000000000000C
+ Symbol: f
+ Type: R_ARM_MOVT_ABS
+ - Offset: 0x0000000000000028
+ Symbol: f2
+ Type: R_ARM_CALL
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: f2
+ Type: STT_GNU_IFUNC
+ Section: .text
+ - Name: f
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000020
+
+# f2-thm.o
+---
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 80B400AF40F20003C0F200031846BD465DF8047B704700BF80B500AFFFF7FEFF0346184680BD00BF
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000004
+ Symbol: f
+ Type: R_ARM_THM_MOVW_ABS_NC
+ - Offset: 0x0000000000000008
+ Symbol: f
+ Type: R_ARM_THM_MOVT_ABS
+ - Offset: 0x000000000000001C
+ Symbol: f2
+ Type: R_ARM_THM_CALL
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+Symbols:
+ Global:
+ - Name: f2
+ Type: STT_GNU_IFUNC
+ Section: .text
+ Value: 0x0000000000000001
+ - Name: f
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000019
+...
diff --git a/lld/test/elf/ARM/rel-ifunc.test b/lld/test/elf/ARM/rel-ifunc.test
index 50eaf6b4c5a..19461906c53 100644
--- a/lld/test/elf/ARM/rel-ifunc.test
+++ b/lld/test/elf/ARM/rel-ifunc.test
@@ -7,14 +7,14 @@
# CHECK: Contents of section .rel.plt:
# CHECK: 400074 00104000
# CHECK: Contents of section .plt:
-# CHECK: 400080 00c68fe2 00ca8ce2 78ffbce5
+# CHECK: 40007c 00c68fe2 00ca8ce2 7cffbce5
# CHECK: Contents of section .text:
-# CHECK: 4001ac 00482de9 04b08de2 d4ffffeb b0ffffeb
+# CHECK: 4001a8 00482de9 04b08de2 d4ffffeb b0ffffeb
# ^ bl #-320 (to address 0x400080=__plt_ifunc_myfunc)
# CHECK: Contents of section .got.plt:
-# CHECK: 401000 c4004000
+# CHECK: 401000 c0004000
# CHECK: SYMBOL TABLE:
-# CHECK: 004000c4 g .text 00000020 myfunc
+# CHECK: 004000c0 g .text 00000020 myfunc
# CHECK: 00400074 g *ABS* 00000000 __rel_iplt_start
# CHECK: 0040007c g *ABS* 00000000 __rel_iplt_end
OpenPOWER on IntegriCloud