summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2020-08-03 14:32:30 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2020-08-03 14:32:30 +0000
commite2b60a9295fbbe3404a39e3ef48f04c4a56e87a0 (patch)
tree0e939e7d12d0f5fe5f8b45ed16523e809b228167 /gnu
parent5a955d4af575a7c0dba03b0ad4d9798c4e5fd479 (diff)
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom tested by plenty
Diffstat (limited to 'gnu')
-rw-r--r--gnu/llvm/lld/ELF/Thunks.cpp745
1 files changed, 156 insertions, 589 deletions
diff --git a/gnu/llvm/lld/ELF/Thunks.cpp b/gnu/llvm/lld/ELF/Thunks.cpp
index 5964196a1ba..f9c2e2d74e0 100644
--- a/gnu/llvm/lld/ELF/Thunks.cpp
+++ b/gnu/llvm/lld/ELF/Thunks.cpp
@@ -22,15 +22,16 @@
#include "Thunks.h"
#include "Config.h"
-#include "InputFiles.h"
#include "InputSection.h"
#include "OutputSections.h"
#include "Symbols.h"
#include "SyntheticSections.h"
#include "Target.h"
-#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include <cstdint>
@@ -39,8 +40,9 @@
using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
namespace {
@@ -71,7 +73,7 @@ public:
// if the target is in range, otherwise it creates a long thunk.
class ARMThunk : public Thunk {
public:
- ARMThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
+ ARMThunk(Symbol &dest) : Thunk(dest, 0) {}
bool getMayUseShortThunk();
uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
@@ -101,9 +103,7 @@ private:
// which has a range of 16MB.
class ThumbThunk : public Thunk {
public:
- ThumbThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
- alignment = 2;
- }
+ ThumbThunk(Symbol &dest) : Thunk(dest, 0) { alignment = 2; }
bool getMayUseShortThunk();
uint32_t size() override { return getMayUseShortThunk() ? 4 : sizeLong(); }
@@ -126,7 +126,7 @@ private:
// Source State, TargetState, Target Requirement, ABS or PI, Range
class ARMV7ABSLongThunk final : public ARMThunk {
public:
- ARMV7ABSLongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
+ ARMV7ABSLongThunk(Symbol &dest) : ARMThunk(dest) {}
uint32_t sizeLong() override { return 12; }
void writeLong(uint8_t *buf) override;
@@ -135,7 +135,7 @@ public:
class ARMV7PILongThunk final : public ARMThunk {
public:
- ARMV7PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
+ ARMV7PILongThunk(Symbol &dest) : ARMThunk(dest) {}
uint32_t sizeLong() override { return 16; }
void writeLong(uint8_t *buf) override;
@@ -144,8 +144,7 @@ public:
class ThumbV7ABSLongThunk final : public ThumbThunk {
public:
- ThumbV7ABSLongThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
+ ThumbV7ABSLongThunk(Symbol &dest) : ThumbThunk(dest) {}
uint32_t sizeLong() override { return 10; }
void writeLong(uint8_t *buf) override;
@@ -154,114 +153,53 @@ public:
class ThumbV7PILongThunk final : public ThumbThunk {
public:
- ThumbV7PILongThunk(Symbol &dest, int64_t addend) : ThumbThunk(dest, addend) {}
-
- uint32_t sizeLong() override { return 12; }
- void writeLong(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
-};
-
-// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
-class ThumbV6MABSLongThunk final : public ThumbThunk {
-public:
- ThumbV6MABSLongThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
+ ThumbV7PILongThunk(Symbol &dest) : ThumbThunk(dest) {}
uint32_t sizeLong() override { return 12; }
void writeLong(uint8_t *buf) override;
void addSymbols(ThunkSection &isec) override;
};
-class ThumbV6MPILongThunk final : public ThumbThunk {
+// Implementations of Thunks for older Arm architectures that do not support
+// the movt/movw instructions. These thunks require at least Architecture v5
+// as used on processors such as the Arm926ej-s. There are no Thumb entry
+// points as there is no Thumb branch instruction on these architecture that
+// can result in a thunk
+class ARMV5ABSLongThunk final : public ARMThunk {
public:
- ThumbV6MPILongThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
-
- uint32_t sizeLong() override { return 16; }
- void writeLong(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
-};
-
-// Architectures v4, v5 and v6 do not support the movt/movw instructions. v5 and
-// v6 support BLX to which BL instructions can be rewritten inline. There are no
-// Thumb entrypoints for v5 and v6 as there is no Thumb branch instruction on
-// these architecture that can result in a thunk.
-
-// LDR on v5 and v6 can switch processor state, so for v5 and v6,
-// ARMV5LongLdrPcThunk can be used for both Arm->Arm and Arm->Thumb calls. v4
-// can also use this thunk, but only for Arm->Arm calls.
-class ARMV5LongLdrPcThunk final : public ARMThunk {
-public:
- ARMV5LongLdrPcThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
+ ARMV5ABSLongThunk(Symbol &dest) : ARMThunk(dest) {}
uint32_t sizeLong() override { return 8; }
void writeLong(uint8_t *buf) override;
void addSymbols(ThunkSection &isec) override;
+ bool isCompatibleWith(const InputSection &isec,
+ const Relocation &rel) const override;
};
-// Implementations of Thunks for v4. BLX is not supported, and loads
-// will not invoke Arm/Thumb state changes.
-class ARMV4PILongBXThunk final : public ARMThunk {
-public:
- ARMV4PILongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
-
- uint32_t sizeLong() override { return 16; }
- void writeLong(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
-};
-
-class ARMV4PILongThunk final : public ARMThunk {
-public:
- ARMV4PILongThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
-
- uint32_t sizeLong() override { return 12; }
- void writeLong(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
-};
-
-class ThumbV4PILongBXThunk final : public ThumbThunk {
+class ARMV5PILongThunk final : public ARMThunk {
public:
- ThumbV4PILongBXThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
+ ARMV5PILongThunk(Symbol &dest) : ARMThunk(dest) {}
uint32_t sizeLong() override { return 16; }
void writeLong(uint8_t *buf) override;
void addSymbols(ThunkSection &isec) override;
+ bool isCompatibleWith(const InputSection &isec,
+ const Relocation &rel) const override;
};
-class ThumbV4PILongThunk final : public ThumbThunk {
-public:
- ThumbV4PILongThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
-
- uint32_t sizeLong() override { return 20; }
- void writeLong(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
-};
-
-class ARMV4ABSLongBXThunk final : public ARMThunk {
-public:
- ARMV4ABSLongBXThunk(Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
-
- uint32_t sizeLong() override { return 12; }
- void writeLong(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
-};
-
-class ThumbV4ABSLongBXThunk final : public ThumbThunk {
+// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
+class ThumbV6MABSLongThunk final : public ThumbThunk {
public:
- ThumbV4ABSLongBXThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
+ ThumbV6MABSLongThunk(Symbol &dest) : ThumbThunk(dest) {}
uint32_t sizeLong() override { return 12; }
void writeLong(uint8_t *buf) override;
void addSymbols(ThunkSection &isec) override;
};
-class ThumbV4ABSLongThunk final : public ThumbThunk {
+class ThumbV6MPILongThunk final : public ThumbThunk {
public:
- ThumbV4ABSLongThunk(Symbol &dest, int64_t addend)
- : ThumbThunk(dest, addend) {}
+ ThumbV6MPILongThunk(Symbol &dest) : ThumbThunk(dest) {}
uint32_t sizeLong() override { return 16; }
void writeLong(uint8_t *buf) override;
@@ -340,83 +278,11 @@ public:
uint32_t size() override { return 20; }
void writeTo(uint8_t *buf) override;
void addSymbols(ThunkSection &isec) override;
- bool isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const override;
-};
-
-// PPC64 R2 Save Stub
-// When the caller requires a valid R2 TOC pointer but the callee does not
-// require a TOC pointer and the callee cannot guarantee that it doesn't
-// clobber R2 then we need to save R2. This stub:
-// 1) Saves the TOC pointer to the stack.
-// 2) Tail calls the callee.
-class PPC64R2SaveStub final : public Thunk {
-public:
- PPC64R2SaveStub(Symbol &dest, int64_t addend) : Thunk(dest, addend) {
- alignment = 16;
- }
-
- // To prevent oscillations in layout when moving from short to long thunks
- // we make sure that once a thunk has been set to long it cannot go back.
- bool getMayUseShortThunk() {
- if (!mayUseShortThunk)
- return false;
- if (!isInt<26>(computeOffset())) {
- mayUseShortThunk = false;
- return false;
- }
- return true;
- }
- uint32_t size() override { return getMayUseShortThunk() ? 8 : 32; }
- void writeTo(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
- bool isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const override;
-
-private:
- // Transitioning from long to short can create layout oscillations in
- // certain corner cases which would prevent the layout from converging.
- // This is similar to the handling for ARMThunk.
- bool mayUseShortThunk = true;
- int64_t computeOffset() const {
- return destination.getVA() - (getThunkTargetSym()->getVA() + 4);
- }
-};
-
-// PPC64 R12 Setup Stub
-// When a caller that does not maintain a toc-pointer performs a local call to
-// a callee which requires a toc-pointer then we need this stub to place the
-// callee's global entry point into r12 without a save of R2.
-class PPC64R12SetupStub final : public Thunk {
-public:
- PPC64R12SetupStub(Symbol &dest) : Thunk(dest, 0) { alignment = 16; }
- uint32_t size() override { return 32; }
- void writeTo(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
- bool isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const override;
-};
-
-// PPC64 PC-relative PLT Stub
-// When a caller that does not maintain a toc-pointer performs an extern call
-// then this stub is needed for:
-// 1) Loading the target functions address from the procedure linkage table into
-// r12 for use by the target functions global entry point, and into the count
-// register with pc-relative instructions.
-// 2) Transferring control to the target function through an indirect branch.
-class PPC64PCRelPLTStub final : public Thunk {
-public:
- PPC64PCRelPLTStub(Symbol &dest) : Thunk(dest, 0) { alignment = 16; }
- uint32_t size() override { return 32; }
- void writeTo(uint8_t *buf) override;
- void addSymbols(ThunkSection &isec) override;
- bool isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const override;
};
// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
-// larger than that we need to emit a long-branch thunk. The target address
+// larger then that we need to emit a long-branch thunk. The target address
// of the callee is stored in a table to be accessed TOC-relative. Since the
// call must be local (a non-local call will have a PltCallStub instead) the
// table stores the address of the callee's local entry point. For
@@ -424,11 +290,9 @@ public:
// used.
class PPC64LongBranchThunk : public Thunk {
public:
- uint32_t size() override { return 32; }
+ uint32_t size() override { return 16; }
void writeTo(uint8_t *buf) override;
void addSymbols(ThunkSection &isec) override;
- bool isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const override;
protected:
PPC64LongBranchThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {}
@@ -439,12 +303,12 @@ public:
PPC64PILongBranchThunk(Symbol &dest, int64_t addend)
: PPC64LongBranchThunk(dest, addend) {
assert(!dest.isPreemptible);
- if (std::optional<uint32_t> index =
+ if (Optional<uint32_t> index =
in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
- mainPart->relaDyn->addRelativeReloc(
- target->relativeRel, *in.ppc64LongBranchTarget, *index * UINT64_C(8),
- dest, addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther),
- target->symbolicRel, R_ABS);
+ mainPart->relaDyn->addReloc(
+ {target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8),
+ true, &dest,
+ addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)});
}
}
};
@@ -488,11 +352,11 @@ void AArch64ABSLongThunk::writeTo(uint8_t *buf) {
};
uint64_t s = getAArch64ThunkDestVA(destination, addend);
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 8, R_AARCH64_ABS64, s);
+ target->relocateOne(buf + 8, R_AARCH64_ABS64, s);
}
void AArch64ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__AArch64AbsLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__AArch64AbsLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 8, isec);
@@ -512,14 +376,14 @@ void AArch64ADRPThunk::writeTo(uint8_t *buf) {
uint64_t s = getAArch64ThunkDestVA(destination, addend);
uint64_t p = getThunkTargetSym()->getVA();
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
- getAArch64Page(s) - getAArch64Page(p));
- target->relocateNoSym(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
+ target->relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21,
+ getAArch64Page(s) - getAArch64Page(p));
+ target->relocateOne(buf + 4, R_AARCH64_ADD_ABS_LO12_NC, s);
}
void AArch64ADRPThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__AArch64ADRPThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ addSymbol(saver.save("__AArch64ADRPThunk_" + destination.getName()), STT_FUNC,
+ 0, isec);
addSymbol("$x", STT_NOTYPE, 0, isec);
}
@@ -558,27 +422,19 @@ void ARMThunk::writeTo(uint8_t *buf) {
0x00, 0x00, 0x00, 0xea, // b S
};
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_ARM_JUMP24, offset);
+ target->relocateOne(buf, R_ARM_JUMP24, offset);
}
bool ARMThunk::isCompatibleWith(const InputSection &isec,
const Relocation &rel) const {
- // v4T does not have BLX, so also deny R_ARM_THM_CALL
- if (!config->armHasBlx && rel.type == R_ARM_THM_CALL)
- return false;
-
// Thumb branch relocations can't use BLX
return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
}
-// This function returns true if:
-// the target is Thumb
-// && is within branch range
-// && this function has not previously returned false
-// (see comment for mayUseShortThunk)
-// && the arch supports Thumb branch range extension.
+// This function returns true if the target is Thumb and is within 2^25, and
+// it has not previously returned false (see comment for mayUseShortThunk).
bool ThumbThunk::getMayUseShortThunk() {
- if (!mayUseShortThunk || !config->armJ1J2BranchEncoding)
+ if (!mayUseShortThunk)
return false;
uint64_t s = getARMThunkDestVA(destination);
if ((s & 1) == 0) {
@@ -604,15 +460,11 @@ void ThumbThunk::writeTo(uint8_t *buf) {
0x00, 0xf0, 0x00, 0xb0, // b.w S
};
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_ARM_THM_JUMP24, offset);
+ target->relocateOne(buf, R_ARM_THM_JUMP24, offset);
}
bool ThumbThunk::isCompatibleWith(const InputSection &isec,
const Relocation &rel) const {
- // v4T does not have BLX, so also deny R_ARM_CALL
- if (!config->armHasBlx && rel.type == R_ARM_CALL)
- return false;
-
// ARM branch relocations can't use BLX
return rel.type != R_ARM_JUMP24 && rel.type != R_ARM_PC24 && rel.type != R_ARM_PLT32;
}
@@ -625,12 +477,12 @@ void ARMV7ABSLongThunk::writeLong(uint8_t *buf) {
};
uint64_t s = getARMThunkDestVA(destination);
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_ARM_MOVW_ABS_NC, s);
- target->relocateNoSym(buf + 4, R_ARM_MOVT_ABS, s);
+ target->relocateOne(buf, R_ARM_MOVW_ABS_NC, s);
+ target->relocateOne(buf + 4, R_ARM_MOVT_ABS, s);
}
void ARMV7ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv7ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ARMv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
@@ -643,12 +495,12 @@ void ThumbV7ABSLongThunk::writeLong(uint8_t *buf) {
};
uint64_t s = getARMThunkDestVA(destination);
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, s);
- target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, s);
+ target->relocateOne(buf, R_ARM_THM_MOVW_ABS_NC, s);
+ target->relocateOne(buf + 4, R_ARM_THM_MOVT_ABS, s);
}
void ThumbV7ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv7ABSLongThunk_" + destination.getName()),
+ addSymbol(saver.save("__Thumbv7ABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
@@ -664,13 +516,13 @@ void ARMV7PILongThunk::writeLong(uint8_t *buf) {
uint64_t p = getThunkTargetSym()->getVA();
int64_t offset = s - p - 16;
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_ARM_MOVW_PREL_NC, offset);
- target->relocateNoSym(buf + 4, R_ARM_MOVT_PREL, offset);
+ target->relocateOne(buf, R_ARM_MOVW_PREL_NC, offset);
+ target->relocateOne(buf + 4, R_ARM_MOVT_PREL, offset);
}
void ARMV7PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMV7PILongThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ addSymbol(saver.save("__ARMV7PILongThunk_" + destination.getName()), STT_FUNC,
+ 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
}
@@ -685,139 +537,39 @@ void ThumbV7PILongThunk::writeLong(uint8_t *buf) {
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
int64_t offset = s - p - 12;
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf, R_ARM_THM_MOVW_PREL_NC, offset);
- target->relocateNoSym(buf + 4, R_ARM_THM_MOVT_PREL, offset);
+ target->relocateOne(buf, R_ARM_THM_MOVW_PREL_NC, offset);
+ target->relocateOne(buf + 4, R_ARM_THM_MOVT_PREL, offset);
}
void ThumbV7PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ThumbV7PILongThunk_" + destination.getName()),
+ addSymbol(saver.save("__ThumbV7PILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
}
-void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
- // Most Thumb instructions cannot access the high registers r8 - r15. As the
- // only register we can corrupt is r12 we must instead spill a low register
- // to the stack to use as a scratch register. We push r1 even though we
- // don't need to get some space to use for the return address.
+void ARMV5ABSLongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
- 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
- 0x01, 0x48, // ldr r0, [pc, #4] ; L1
- 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
- 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
- 0x00, 0x00, 0x00, 0x00 // L1: .word S
- };
- uint64_t s = getARMThunkDestVA(destination);
- memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 8, R_ARM_ABS32, s);
-}
-
-void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv6MABSLongThunk_" + destination.getName()),
- STT_FUNC, 1, isec);
- addSymbol("$t", STT_NOTYPE, 0, isec);
- addSymbol("$d", STT_NOTYPE, 8, isec);
-}
-
-void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
- // Most Thumb instructions cannot access the high registers r8 - r15. As the
- // only register we can corrupt is ip (r12) we must instead spill a low
- // register to the stack to use as a scratch register.
- const uint8_t data[] = {
- 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
- 0x02, 0x48, // ldr r0, [pc, #8] ; L2
- 0x84, 0x46, // mov ip, r0 ; high to low register
- 0x01, 0xbc, // pop {r0} ; restore scratch register
- 0xe7, 0x44, // L1: add pc, ip ; transfer control
- 0xc0, 0x46, // nop ; pad to 4-byte boundary
- 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
- };
- uint64_t s = getARMThunkDestVA(destination);
- uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
- memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
-}
-
-void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv6MPILongThunk_" + destination.getName()),
- STT_FUNC, 1, isec);
- addSymbol("$t", STT_NOTYPE, 0, isec);
- addSymbol("$d", STT_NOTYPE, 12, isec);
-}
-
-void ARMV5LongLdrPcThunk::writeLong(uint8_t *buf) {
- const uint8_t data[] = {
- 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
+ 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
0x00, 0x00, 0x00, 0x00, // L1: .word S
};
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
+ target->relocateOne(buf + 4, R_ARM_ABS32, getARMThunkDestVA(destination));
}
-void ARMV5LongLdrPcThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv5LongLdrPcThunk_" + destination.getName()),
+void ARMV5ABSLongThunk::addSymbols(ThunkSection &isec) {
+ addSymbol(saver.save("__ARMv5ABSLongThunk_" + destination.getName()),
STT_FUNC, 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 4, isec);
}
-void ARMV4ABSLongBXThunk::writeLong(uint8_t *buf) {
- const uint8_t data[] = {
- 0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1
- 0x1c, 0xff, 0x2f, 0xe1, // bx r12
- 0x00, 0x00, 0x00, 0x00, // L1: .word S
- };
- memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
-}
-
-void ARMV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv4ABSLongBXThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
- addSymbol("$a", STT_NOTYPE, 0, isec);
- addSymbol("$d", STT_NOTYPE, 8, isec);
-}
-
-void ThumbV4ABSLongBXThunk::writeLong(uint8_t *buf) {
- const uint8_t data[] = {
- 0x78, 0x47, // bx pc
- 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
- 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc, #-4] ; L1
- 0x00, 0x00, 0x00, 0x00, // L1: .word S
- };
- memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 8, R_ARM_ABS32, getARMThunkDestVA(destination));
-}
-
-void ThumbV4ABSLongBXThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv4ABSLongBXThunk_" + destination.getName()),
- STT_FUNC, 1, isec);
- addSymbol("$t", STT_NOTYPE, 0, isec);
- addSymbol("$a", STT_NOTYPE, 4, isec);
- addSymbol("$d", STT_NOTYPE, 8, isec);
-}
-
-void ThumbV4ABSLongThunk::writeLong(uint8_t *buf) {
- const uint8_t data[] = {
- 0x78, 0x47, // bx pc
- 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
- 0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L1
- 0x1c, 0xff, 0x2f, 0xe1, // bx r12
- 0x00, 0x00, 0x00, 0x00, // L1: .word S
- };
- memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 12, R_ARM_ABS32, getARMThunkDestVA(destination));
-}
-
-void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv4ABSLongThunk_" + destination.getName()),
- STT_FUNC, 1, isec);
- addSymbol("$t", STT_NOTYPE, 0, isec);
- addSymbol("$a", STT_NOTYPE, 4, isec);
- addSymbol("$d", STT_NOTYPE, 12, isec);
+bool ARMV5ABSLongThunk::isCompatibleWith(const InputSection &isec,
+ const Relocation &rel) const {
+ // Thumb branch relocations can't use BLX
+ return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
}
-void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
+void ARMV5PILongThunk::writeLong(uint8_t *buf) {
const uint8_t data[] = {
0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
@@ -827,78 +579,70 @@ void ARMV4PILongBXThunk::writeLong(uint8_t *buf) {
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 12);
+ target->relocateOne(buf + 12, R_ARM_REL32, s - p - 12);
}
-void ARMV4PILongBXThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv4PILongBXThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+void ARMV5PILongThunk::addSymbols(ThunkSection &isec) {
+ addSymbol(saver.save("__ARMV5PILongThunk_" + destination.getName()), STT_FUNC,
+ 0, isec);
addSymbol("$a", STT_NOTYPE, 0, isec);
addSymbol("$d", STT_NOTYPE, 12, isec);
}
-void ARMV4PILongThunk::writeLong(uint8_t *buf) {
- const uint8_t data[] = {
- 0x00, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc] ; L2
- 0x0c, 0xf0, 0x8f, 0xe0, // L1: add pc, pc, r12
- 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
- };
- uint64_t s = getARMThunkDestVA(destination);
- uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
- memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 8, R_ARM_REL32, s - p - 12);
-}
-
-void ARMV4PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__ARMv4PILongThunk_" + destination.getName()),
- STT_FUNC, 0, isec);
- addSymbol("$a", STT_NOTYPE, 0, isec);
- addSymbol("$d", STT_NOTYPE, 8, isec);
+bool ARMV5PILongThunk::isCompatibleWith(const InputSection &isec,
+ const Relocation &rel) const {
+ // Thumb branch relocations can't use BLX
+ return rel.type != R_ARM_THM_JUMP19 && rel.type != R_ARM_THM_JUMP24;
}
-void ThumbV4PILongBXThunk::writeLong(uint8_t *buf) {
+void ThumbV6MABSLongThunk::writeLong(uint8_t *buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is r12 we must instead spill a low register
+ // to the stack to use as a scratch register. We push r1 even though we
+ // don't need to get some space to use for the return address.
const uint8_t data[] = {
- 0x78, 0x47, // P: bx pc
- 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
- 0x00, 0xc0, 0x9f, 0xe5, // ldr r12, [pc] ; L2
- 0x0f, 0xf0, 0x8c, 0xe0, // L1: add pc, r12, pc
- 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
+ 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
+ 0x01, 0x48, // ldr r0, [pc, #4] ; L1
+ 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
+ 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
+ 0x00, 0x00, 0x00, 0x00 // L1: .word S
};
uint64_t s = getARMThunkDestVA(destination);
- uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 12, R_ARM_REL32, s - p - 16);
+ target->relocateOne(buf + 8, R_ARM_ABS32, s);
}
-void ThumbV4PILongBXThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv4PILongBXThunk_" + destination.getName()),
+void ThumbV6MABSLongThunk::addSymbols(ThunkSection &isec) {
+ addSymbol(saver.save("__Thumbv6MABSLongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
- addSymbol("$a", STT_NOTYPE, 4, isec);
- addSymbol("$d", STT_NOTYPE, 12, isec);
+ addSymbol("$d", STT_NOTYPE, 8, isec);
}
-void ThumbV4PILongThunk::writeLong(uint8_t *buf) {
+void ThumbV6MPILongThunk::writeLong(uint8_t *buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is ip (r12) we must instead spill a low
+ // register to the stack to use as a scratch register.
const uint8_t data[] = {
- 0x78, 0x47, // P: bx pc
- 0xfd, 0xe7, // b #-6 ; Arm recommended sequence to follow bx pc
- 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, [pc,#4] ; L2
- 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
- 0x1c, 0xff, 0x2f, 0xe1, // bx ip
- 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
+ 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
+ 0x02, 0x48, // ldr r0, [pc, #8] ; L2
+ 0x84, 0x46, // mov ip, r0 ; high to low register
+ 0x01, 0xbc, // pop {r0} ; restore scratch register
+ 0xe7, 0x44, // L1: add pc, ip ; transfer control
+ 0xc0, 0x46, // nop ; pad to 4-byte boundary
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
};
uint64_t s = getARMThunkDestVA(destination);
uint64_t p = getThunkTargetSym()->getVA() & ~0x1;
memcpy(buf, data, sizeof(data));
- target->relocateNoSym(buf + 16, R_ARM_REL32, s - p - 16);
+ target->relocateOne(buf + 12, R_ARM_REL32, s - p - 12);
}
-void ThumbV4PILongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__Thumbv4PILongThunk_" + destination.getName()),
+void ThumbV6MPILongThunk::addSymbols(ThunkSection &isec) {
+ addSymbol(saver.save("__Thumbv6MPILongThunk_" + destination.getName()),
STT_FUNC, 1, isec);
addSymbol("$t", STT_NOTYPE, 0, isec);
- addSymbol("$a", STT_NOTYPE, 4, isec);
- addSymbol("$d", STT_NOTYPE, 16, isec);
+ addSymbol("$d", STT_NOTYPE, 12, isec);
}
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
@@ -908,12 +652,12 @@ void MipsThunk::writeTo(uint8_t *buf) {
write32(buf + 4, 0x08000000 | (s >> 2)); // j func
write32(buf + 8, 0x27390000); // addiu $25, $25, %lo(func)
write32(buf + 12, 0x00000000); // nop
- target->relocateNoSym(buf, R_MIPS_HI16, s);
- target->relocateNoSym(buf + 8, R_MIPS_LO16, s);
+ target->relocateOne(buf, R_MIPS_HI16, s);
+ target->relocateOne(buf + 8, R_MIPS_LO16, s);
}
void MipsThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__LA25Thunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
@@ -930,15 +674,14 @@ void MicroMipsThunk::writeTo(uint8_t *buf) {
write16(buf + 4, 0xd400); // j func
write16(buf + 8, 0x3339); // addiu $25, $25, %lo(func)
write16(buf + 12, 0x0c00); // nop
- target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
- target->relocateNoSym(buf + 4, R_MICROMIPS_26_S1, s);
- target->relocateNoSym(buf + 8, R_MICROMIPS_LO16, s);
+ target->relocateOne(buf, R_MICROMIPS_HI16, s);
+ target->relocateOne(buf + 4, R_MICROMIPS_26_S1, s);
+ target->relocateOne(buf + 8, R_MICROMIPS_LO16, s);
}
void MicroMipsThunk::addSymbols(ThunkSection &isec) {
- Defined *d =
- addSymbol(saver().save("__microLA25Thunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ Defined *d = addSymbol(
+ saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
@@ -955,15 +698,14 @@ void MicroMipsR6Thunk::writeTo(uint8_t *buf) {
write16(buf, 0x1320); // lui $25, %hi(func)
write16(buf + 4, 0x3339); // addiu $25, $25, %lo(func)
write16(buf + 8, 0x9400); // bc func
- target->relocateNoSym(buf, R_MICROMIPS_HI16, s);
- target->relocateNoSym(buf + 4, R_MICROMIPS_LO16, s);
- target->relocateNoSym(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
+ target->relocateOne(buf, R_MICROMIPS_HI16, s);
+ target->relocateOne(buf + 4, R_MICROMIPS_LO16, s);
+ target->relocateOne(buf + 8, R_MICROMIPS_PC26_S1, s - p - 12);
}
void MicroMipsR6Thunk::addSymbols(ThunkSection &isec) {
- Defined *d =
- addSymbol(saver().save("__microLA25Thunk_" + destination.getName()),
- STT_FUNC, 0, isec);
+ Defined *d = addSymbol(
+ saver.save("__microLA25Thunk_" + destination.getName()), STT_FUNC, 0, isec);
d->stOther |= STO_MIPS_MICROMIPS;
}
@@ -972,8 +714,8 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
return dyn_cast<InputSection>(dr.section);
}
-void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
- const InputFile *file, int64_t addend) {
+void writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
+ const InputFile *file, int64_t addend) {
if (!config->isPic) {
write32(buf + 0, 0x3d600000 | (gotPltVA + 0x8000) >> 16); // lis r11,ha
write32(buf + 4, 0x816b0000 | (uint16_t)gotPltVA); // lwz r11,l(r11)
@@ -986,9 +728,8 @@ void elf::writePPC32PltCallStub(uint8_t *buf, uint64_t gotPltVA,
// The stub loads an address relative to r30 (.got2+Addend). Addend is
// almost always 0x8000. The address of .got2 is different in another object
// file, so a stub cannot be shared.
- offset = gotPltVA -
- (in.ppc32Got2->getParent()->getVA() +
- (file->ppc32Got2 ? file->ppc32Got2->outSecOff : 0) + addend);
+ offset = gotPltVA - (in.ppc32Got2->getParent()->getVA() +
+ file->ppc32Got2OutSecOff + addend);
} else {
// The stub loads an address relative to _GLOBAL_OFFSET_TABLE_ (which is
// currently the address of .got).
@@ -1023,7 +764,7 @@ void PPC32PltCallStub::addSymbols(ThunkSection &isec) {
else
os << ".plt_pic32.";
os << destination.getName();
- addSymbol(saver().save(os.str()), STT_FUNC, 0, isec);
+ addSymbol(saver.save(os.str()), STT_FUNC, 0, isec);
}
bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
@@ -1032,7 +773,7 @@ bool PPC32PltCallStub::isCompatibleWith(const InputSection &isec,
}
void PPC32LongThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__LongThunk_" + destination.getName()), STT_FUNC, 0,
isec);
}
@@ -1058,7 +799,7 @@ void PPC32LongThunk::writeTo(uint8_t *buf) {
write32(buf + 4, 0x4e800420); // bctr
}
-void elf::writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
+void writePPC64LoadAndBranch(uint8_t *buf, int64_t offset) {
uint16_t offHa = (offset + 0x8000) >> 16;
uint16_t offLo = offset & 0xffff;
@@ -1076,131 +817,12 @@ void PPC64PltCallStub::writeTo(uint8_t *buf) {
}
void PPC64PltCallStub::addSymbols(ThunkSection &isec) {
- Defined *s = addSymbol(saver().save("__plt_" + destination.getName()),
- STT_FUNC, 0, isec);
+ Defined *s = addSymbol(saver.save("__plt_" + destination.getName()), STT_FUNC,
+ 0, isec);
s->needsTocRestore = true;
s->file = destination.file;
}
-bool PPC64PltCallStub::isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const {
- return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
-}
-
-void PPC64R2SaveStub::writeTo(uint8_t *buf) {
- const int64_t offset = computeOffset();
- write32(buf + 0, 0xf8410018); // std r2,24(r1)
- // The branch offset needs to fit in 26 bits.
- if (getMayUseShortThunk()) {
- write32(buf + 4, 0x48000000 | (offset & 0x03fffffc)); // b <offset>
- } else if (isInt<34>(offset)) {
- int nextInstOffset;
- uint64_t tocOffset = destination.getVA() - getPPC64TocBase();
- if (tocOffset >> 16 > 0) {
- const uint64_t addi = ADDI_R12_TO_R12_NO_DISP | (tocOffset & 0xffff);
- const uint64_t addis =
- ADDIS_R12_TO_R2_NO_DISP | ((tocOffset >> 16) & 0xffff);
- write32(buf + 4, addis); // addis r12, r2 , top of offset
- write32(buf + 8, addi); // addi r12, r12, bottom of offset
- nextInstOffset = 12;
- } else {
- const uint64_t addi = ADDI_R12_TO_R2_NO_DISP | (tocOffset & 0xffff);
- write32(buf + 4, addi); // addi r12, r2, offset
- nextInstOffset = 8;
- }
- write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
- write32(buf + nextInstOffset + 4, BCTR); // bctr
- } else {
- in.ppc64LongBranchTarget->addEntry(&destination, addend);
- const int64_t offsetFromTOC =
- in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
- getPPC64TocBase();
- writePPC64LoadAndBranch(buf + 4, offsetFromTOC);
- }
-}
-
-void PPC64R2SaveStub::addSymbols(ThunkSection &isec) {
- Defined *s = addSymbol(saver().save("__toc_save_" + destination.getName()),
- STT_FUNC, 0, isec);
- s->needsTocRestore = true;
-}
-
-bool PPC64R2SaveStub::isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const {
- return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
-}
-
-void PPC64R12SetupStub::writeTo(uint8_t *buf) {
- int64_t offset = destination.getVA() - getThunkTargetSym()->getVA();
- if (!isInt<34>(offset))
- reportRangeError(buf, offset, 34, destination, "R12 setup stub offset");
-
- int nextInstOffset;
- if (!config->power10Stubs) {
- uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
- write32(buf + 0, 0x7c0802a6); // mflr r12
- write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
- write32(buf + 8, 0x7d6802a6); // mflr r11
- write32(buf + 12, 0x7d8803a6); // mtlr r12
- write32(buf + 16, 0x3d8b0000 | computeHiBits(off));// addis r12,r11,off@ha
- write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
- nextInstOffset = 24;
- } else {
- uint64_t paddi = PADDI_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
- (offset & 0xffff);
- writePrefixedInstruction(buf + 0, paddi); // paddi r12, 0, func@pcrel, 1
- nextInstOffset = 8;
- }
- write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
- write32(buf + nextInstOffset + 4, BCTR); // bctr
-}
-
-void PPC64R12SetupStub::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__gep_setup_" + destination.getName()), STT_FUNC, 0,
- isec);
-}
-
-bool PPC64R12SetupStub::isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const {
- return rel.type == R_PPC64_REL24_NOTOC;
-}
-
-void PPC64PCRelPLTStub::writeTo(uint8_t *buf) {
- int nextInstOffset = 0;
- int64_t offset = destination.getGotPltVA() - getThunkTargetSym()->getVA();
-
- if (config->power10Stubs) {
- if (!isInt<34>(offset))
- reportRangeError(buf, offset, 34, destination,
- "PC-relative PLT stub offset");
- const uint64_t pld = PLD_R12_NO_DISP | (((offset >> 16) & 0x3ffff) << 32) |
- (offset & 0xffff);
- writePrefixedInstruction(buf + 0, pld); // pld r12, func@plt@pcrel
- nextInstOffset = 8;
- } else {
- uint32_t off = destination.getVA(addend) - getThunkTargetSym()->getVA() - 8;
- write32(buf + 0, 0x7c0802a6); // mflr r12
- write32(buf + 4, 0x429f0005); // bcl 20,31,.+4
- write32(buf + 8, 0x7d6802a6); // mflr r11
- write32(buf + 12, 0x7d8803a6); // mtlr r12
- write32(buf + 16, 0x3d8b0000 | computeHiBits(off)); // addis r12,r11,off@ha
- write32(buf + 20, 0x398c0000 | (off & 0xffff)); // addi r12,r12,off@l
- nextInstOffset = 24;
- }
- write32(buf + nextInstOffset, MTCTR_R12); // mtctr r12
- write32(buf + nextInstOffset + 4, BCTR); // bctr
-}
-
-void PPC64PCRelPLTStub::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__plt_pcrel_" + destination.getName()), STT_FUNC, 0,
- isec);
-}
-
-bool PPC64PCRelPLTStub::isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const {
- return rel.type == R_PPC64_REL24_NOTOC;
-}
-
void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
int64_t offset = in.ppc64LongBranchTarget->getEntryVA(&destination, addend) -
getPPC64TocBase();
@@ -1208,72 +830,28 @@ void PPC64LongBranchThunk::writeTo(uint8_t *buf) {
}
void PPC64LongBranchThunk::addSymbols(ThunkSection &isec) {
- addSymbol(saver().save("__long_branch_" + destination.getName()), STT_FUNC, 0,
+ addSymbol(saver.save("__long_branch_" + destination.getName()), STT_FUNC, 0,
isec);
}
-bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec,
- const Relocation &rel) const {
- return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14;
-}
-
Thunk::Thunk(Symbol &d, int64_t a) : destination(d), addend(a), offset(0) {}
Thunk::~Thunk() = default;
static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
- if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26 &&
- type != R_AARCH64_PLT32)
+ if (type != R_AARCH64_CALL26 && type != R_AARCH64_JUMP26)
fatal("unrecognized relocation type");
if (config->picThunk)
return make<AArch64ADRPThunk>(s, a);
return make<AArch64ABSLongThunk>(s, a);
}
-// Creates a thunk for long branches or Thumb-ARM interworking.
-// Arm Architectures v4t does not support Thumb2 technology, and does not
-// support BLX or LDR Arm/Thumb state switching. This means that
-// - MOVT and MOVW instructions cannot be used.
-// - We can't rewrite BL in place to BLX. We will need thunks.
-//
-// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
-// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
-static Thunk *addThunkArmv4(RelType reloc, Symbol &s, int64_t a) {
- bool thumb_target = s.getVA(a) & 1;
-
- switch (reloc) {
- case R_ARM_PC24:
- case R_ARM_PLT32:
- case R_ARM_JUMP24:
- case R_ARM_CALL:
- if (config->picThunk) {
- if (thumb_target)
- return make<ARMV4PILongBXThunk>(s, a);
- return make<ARMV4PILongThunk>(s, a);
- }
- if (thumb_target)
- return make<ARMV4ABSLongBXThunk>(s, a);
- return make<ARMV5LongLdrPcThunk>(s, a);
- case R_ARM_THM_CALL:
- if (config->picThunk) {
- if (thumb_target)
- return make<ThumbV4PILongThunk>(s, a);
- return make<ThumbV4PILongBXThunk>(s, a);
- }
- if (thumb_target)
- return make<ThumbV4ABSLongThunk>(s, a);
- return make<ThumbV4ABSLongBXThunk>(s, a);
- }
- fatal("relocation " + toString(reloc) + " to " + toString(s) +
- " not supported for Armv4 or Armv4T target");
-}
-
-// Creates a thunk for Thumb-ARM interworking compatible with Armv5 and Armv6.
-// Arm Architectures v5 and v6 do not support Thumb2 technology. This means that
+// Creates a thunk for Thumb-ARM interworking.
+// Arm Architectures v5 and v6 do not support Thumb2 technology. This means
// - MOVT and MOVW instructions cannot be used
// - Only Thumb relocation that can generate a Thunk is a BL, this can always
// be transformed into a BLX
-static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) {
+static Thunk *addThunkPreArmv7(RelType reloc, Symbol &s) {
switch (reloc) {
case R_ARM_PC24:
case R_ARM_PLT32:
@@ -1281,8 +859,8 @@ static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) {
case R_ARM_CALL:
case R_ARM_THM_CALL:
if (config->picThunk)
- return make<ARMV4PILongBXThunk>(s, a);
- return make<ARMV5LongLdrPcThunk>(s, a);
+ return make<ARMV5PILongThunk>(s);
+ return make<ARMV5ABSLongThunk>(s);
}
fatal("relocation " + toString(reloc) + " to " + toString(s) +
" not supported for Armv5 or Armv6 targets");
@@ -1293,21 +871,21 @@ static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) {
// - MOVT and MOVW instructions cannot be used.
// - Only a limited number of instructions can access registers r8 and above
// - No interworking support is needed (all Thumb).
-static Thunk *addThunkV6M(RelType reloc, Symbol &s, int64_t a) {
+static Thunk *addThunkV6M(RelType reloc, Symbol &s) {
switch (reloc) {
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
case R_ARM_THM_CALL:
if (config->isPic)
- return make<ThumbV6MPILongThunk>(s, a);
- return make<ThumbV6MABSLongThunk>(s, a);
+ return make<ThumbV6MPILongThunk>(s);
+ return make<ThumbV6MABSLongThunk>(s);
}
fatal("relocation " + toString(reloc) + " to " + toString(s) +
" not supported for Armv6-M targets");
}
// Creates a thunk for Thumb-ARM interworking or branch range extension.
-static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
+static Thunk *addThunkArm(RelType reloc, Symbol &s) {
// Decide which Thunk is needed based on:
// Available instruction set
// - An Arm Thunk can only be used if Arm state is available.
@@ -1325,11 +903,9 @@ static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
// of the input objects. InputFiles.cpp contains the mapping from ARM
// architecture to flag.
if (!config->armHasMovtMovw) {
- if (config->armJ1J2BranchEncoding)
- return addThunkV6M(reloc, s, a);
- if (config->armHasBlx)
- return addThunkArmv5v6(reloc, s, a);
- return addThunkArmv4(reloc, s, a);
+ if (!config->armJ1J2BranchEncoding)
+ return addThunkPreArmv7(reloc, s);
+ return addThunkV6M(reloc, s);
}
switch (reloc) {
@@ -1338,14 +914,14 @@ static Thunk *addThunkArm(RelType reloc, Symbol &s, int64_t a) {
case R_ARM_JUMP24:
case R_ARM_CALL:
if (config->picThunk)
- return make<ARMV7PILongThunk>(s, a);
- return make<ARMV7ABSLongThunk>(s, a);
+ return make<ARMV7PILongThunk>(s);
+ return make<ARMV7ABSLongThunk>(s);
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
case R_ARM_THM_CALL:
if (config->picThunk)
- return make<ThumbV7PILongThunk>(s, a);
- return make<ThumbV7ABSLongThunk>(s, a);
+ return make<ThumbV7PILongThunk>(s);
+ return make<ThumbV7ABSLongThunk>(s);
}
fatal("unrecognized relocation type");
}
@@ -1369,21 +945,9 @@ static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
}
static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
- assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
- type == R_PPC64_REL24_NOTOC) &&
- "unexpected relocation type for thunk");
+ assert(type == R_PPC64_REL24 && "unexpected relocation type for thunk");
if (s.isInPlt())
- return type == R_PPC64_REL24_NOTOC ? (Thunk *)make<PPC64PCRelPLTStub>(s)
- : (Thunk *)make<PPC64PltCallStub>(s);
-
- // This check looks at the st_other bits of the callee. If the value is 1
- // then the callee clobbers the TOC and we need an R2 save stub when RelType
- // is R_PPC64_REL14 or R_PPC64_REL24.
- if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
- return make<PPC64R2SaveStub>(s, a);
-
- if (type == R_PPC64_REL24_NOTOC)
- return make<PPC64R12SetupStub>(s);
+ return make<PPC64PltCallStub>(s);
if (config->picThunk)
return make<PPC64PILongBranchThunk>(s, a);
@@ -1391,7 +955,7 @@ static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) {
return make<PPC64PDLongBranchThunk>(s, a);
}
-Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
+Thunk *addThunk(const InputSection &isec, Relocation &rel) {
Symbol &s = *rel.sym;
int64_t a = rel.addend;
@@ -1399,7 +963,7 @@ Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
return addThunkAArch64(rel.type, s, a);
if (config->emachine == EM_ARM)
- return addThunkArm(rel.type, s, a);
+ return addThunkArm(rel.type, s);
if (config->emachine == EM_MIPS)
return addThunkMips(rel.type, s);
@@ -1412,3 +976,6 @@ Thunk *elf::addThunk(const InputSection &isec, Relocation &rel) {
llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC");
}
+
+} // end namespace elf
+} // end namespace lld