summaryrefslogtreecommitdiff
path: root/ELF/Target.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Target.cpp')
-rw-r--r--ELF/Target.cpp437
1 files changed, 261 insertions, 176 deletions
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 55fcf1734d1fa..664dcd1ed44e6 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -45,7 +45,10 @@ using namespace llvm::support::endian;
using namespace llvm::ELF;
std::string lld::toString(uint32_t Type) {
- return getELFRelocationTypeName(elf::Config->EMachine, Type);
+ StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type);
+ if (S == "Unknown")
+ return ("Unknown (" + Twine(Type) + ")").str();
+ return S;
}
namespace lld {
@@ -56,20 +59,20 @@ TargetInfo *Target;
static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); }
static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); }
-template <class ELFT> static std::string getErrorLoc(uint8_t *Loc) {
- for (InputSectionData *D : Symtab<ELFT>::X->Sections) {
- auto *IS = dyn_cast_or_null<InputSection<ELFT>>(D);
+template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) {
+ for (InputSectionBase *D : InputSections) {
+ auto *IS = dyn_cast_or_null<InputSection>(D);
if (!IS || !IS->OutSec)
continue;
- uint8_t *ISLoc = cast<OutputSection<ELFT>>(IS->OutSec)->Loc + IS->OutSecOff;
+ uint8_t *ISLoc = cast<OutputSection>(IS->OutSec)->Loc + IS->OutSecOff;
if (ISLoc <= Loc && Loc < ISLoc + IS->getSize())
- return IS->getLocation(Loc - ISLoc) + ": ";
+ return IS->template getLocation<ELFT>(Loc - ISLoc) + ": ";
}
return "";
}
-static std::string getErrorLocation(uint8_t *Loc) {
+static std::string getErrorLocation(const uint8_t *Loc) {
switch (Config->EKind) {
case ELF32LEKind:
return getErrorLoc<ELF32LE>(Loc);
@@ -116,17 +119,17 @@ namespace {
class X86TargetInfo final : public TargetInfo {
public:
X86TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
uint32_t getDynRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@@ -141,15 +144,15 @@ public:
template <class ELFT> class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
bool isPicRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@@ -170,14 +173,16 @@ class PPCTargetInfo final : public TargetInfo {
public:
PPCTargetInfo();
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
};
class PPC64TargetInfo final : public TargetInfo {
public:
PPC64TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
@@ -185,12 +190,13 @@ public:
class AArch64TargetInfo final : public TargetInfo {
public:
AArch64TargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
bool isPicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
@@ -205,44 +211,47 @@ class AMDGPUTargetInfo final : public TargetInfo {
public:
AMDGPUTargetInfo();
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
};
class ARMTargetInfo final : public TargetInfo {
public:
ARMTargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
bool isPicRel(uint32_t Type) const override;
uint32_t getDynRel(uint32_t Type) const override;
- uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
bool isTlsInitialExecRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
- RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
- const SymbolBody &S) const override;
+ void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override;
+ void addPltHeaderSymbols(InputSectionBase *ISD) const override;
+ bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+ const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
};
template <class ELFT> class MipsTargetInfo final : public TargetInfo {
public:
MipsTargetInfo();
- RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override;
- uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
+ RelExpr getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const override;
+ int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override;
bool isPicRel(uint32_t Type) const override;
uint32_t getDynRel(uint32_t Type) const override;
bool isTlsLocalDynamicRel(uint32_t Type) const override;
- bool isTlsGlobalDynamicRel(uint32_t Type) const override;
void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override;
void writePltHeader(uint8_t *Buf) const override;
- void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
+ void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
- RelExpr getThunkExpr(RelExpr Expr, uint32_t RelocType, const InputFile &File,
- const SymbolBody &S) const override;
+ bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File,
+ const SymbolBody &S) const override;
void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override;
bool usesOnlyLowPageBits(uint32_t Type) const override;
};
@@ -286,25 +295,21 @@ TargetInfo *createTarget() {
TargetInfo::~TargetInfo() {}
-uint64_t TargetInfo::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
+int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
return 0;
}
bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; }
-RelExpr TargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
- const SymbolBody &S) const {
- return Expr;
+bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
+ const InputFile *File, const SymbolBody &S) const {
+ return false;
}
bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; }
bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; }
-bool TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const { return false; }
-
void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
writeGotPlt(Buf, S);
}
@@ -352,10 +357,14 @@ X86TargetInfo::X86TargetInfo() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
+ // 0xCC is the "int3" (call debug exception handler) instruction.
+ TrapInstr = 0xcccccccc;
}
-RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
+ case R_386_8:
case R_386_16:
case R_386_32:
case R_386_TLS_LDO_32:
@@ -366,6 +375,7 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
return R_TLSLD;
case R_386_PLT32:
return R_PLT_PC;
+ case R_386_PC8:
case R_386_PC16:
case R_386_PC32:
return R_PC;
@@ -375,6 +385,24 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
return R_GOT;
case R_386_GOT32:
case R_386_GOT32X:
+ // These relocations can be calculated in two different ways.
+ // Usual calculation is G + A - GOT what means an offset in GOT table
+ // (R_GOT_FROM_END). When instruction pointed by relocation has no base
+ // register, then relocations can be used when PIC code is disabled. In that
+ // case calculation is G + A, it resolves to an address of entry in GOT
+ // (R_GOT) and not an offset.
+ //
+ // To check that instruction has no base register we scan ModR/M byte.
+ // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte"
+ // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/
+ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf)
+ if ((Loc[-1] & 0xc7) != 0x5)
+ return R_GOT_FROM_END;
+ if (Config->Pic)
+ error(toString(S.File) + ": relocation " + toString(Type) + " against '" +
+ S.getName() +
+ "' without base register can not be used when PIC enabled");
+ return R_GOT;
case R_386_TLS_GOTIE:
return R_GOT_FROM_END;
case R_386_GOTOFF:
@@ -384,10 +412,9 @@ RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_386_TLS_LE_32:
return R_NEG_TLS;
case R_386_NONE:
- return R_HINT;
+ return R_NONE;
default:
- error("do not know how to handle relocation '" + toString(Type) + "' (" +
- Twine(Type) + ")");
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
return R_HINT;
}
}
@@ -411,12 +438,12 @@ void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const {
void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const {
// Entries in .got.plt initially points back to the corresponding
// PLT entries with a fixed offset to skip the first instruction.
- write32le(Buf, S.getPltVA<ELF32LE>() + 6);
+ write32le(Buf, S.getPltVA() + 6);
}
void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
// An x86 entry is the address of the ifunc resolver function.
- write32le(Buf, S.getVA<ELF32LE>());
+ write32le(Buf, S.getVA());
}
uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
@@ -427,10 +454,6 @@ uint32_t X86TargetInfo::getDynRel(uint32_t Type) const {
return Type;
}
-bool X86TargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_386_TLS_GD;
-}
-
bool X86TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM;
}
@@ -440,30 +463,33 @@ bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const {
}
void X86TargetInfo::writePltHeader(uint8_t *Buf) const {
- // Executable files and shared object files have
- // separate procedure linkage tables.
if (Config->Pic) {
const uint8_t V[] = {
- 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
- 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
- 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
+ 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx)
+ 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx)
+ 0x90, 0x90, 0x90, 0x90 // nop
};
memcpy(Buf, V, sizeof(V));
+
+ uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
+ uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA() - Ebx;
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
return;
}
const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOT+4)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOT+8)
- 0x90, 0x90, 0x90, 0x90 // nop; nop; nop; nop
+ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4)
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8)
+ 0x90, 0x90, 0x90, 0x90 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint32_t Got = In<ELF32LE>::GotPlt->getVA();
- write32le(Buf + 2, Got + 4);
- write32le(Buf + 8, Got + 8);
+ uint32_t GotPlt = In<ELF32LE>::GotPlt->getVA();
+ write32le(Buf + 2, GotPlt + 4);
+ write32le(Buf + 8, GotPlt + 8);
}
-void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
@@ -473,22 +499,32 @@ void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, Inst, sizeof(Inst));
- // jmp *foo@GOT(%ebx) or jmp *foo_in_GOT
- Buf[1] = Config->Pic ? 0xa3 : 0x25;
- uint32_t Got = In<ELF32LE>::GotPlt->getVA();
- write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got : GotEntryAddr);
+ if (Config->Pic) {
+ // jmp *foo@GOT(%ebx)
+ uint32_t Ebx = In<ELF32LE>::Got->getVA() + In<ELF32LE>::Got->getSize();
+ Buf[1] = 0xa3;
+ write32le(Buf + 2, GotPltEntryAddr - Ebx);
+ } else {
+ // jmp *foo_in_GOT
+ Buf[1] = 0x25;
+ write32le(Buf + 2, GotPltEntryAddr);
+ }
+
write32le(Buf + 7, RelOff);
write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
}
-uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
+int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
switch (Type) {
default:
return 0;
+ case R_386_8:
+ case R_386_PC8:
+ return SignExtend64<8>(*Buf);
case R_386_16:
case R_386_PC16:
- return read16le(Buf);
+ return SignExtend64<16>(read16le(Buf));
case R_386_32:
case R_386_GOT32:
case R_386_GOT32X:
@@ -497,21 +533,36 @@ uint64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf,
case R_386_PC32:
case R_386_PLT32:
case R_386_TLS_LE:
- return read32le(Buf);
+ return SignExtend64<32>(read32le(Buf));
}
}
void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
- checkInt<32>(Loc, Val, Type);
-
- // R_386_PC16 and R_386_16 are not part of the current i386 psABI. They are
- // used by 16-bit x86 objects, like boot loaders.
- if (Type == R_386_16 || Type == R_386_PC16) {
+ // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are
+ // being used for some 16-bit programs such as boot loaders, so
+ // we want to support them.
+ switch (Type) {
+ case R_386_8:
+ checkUInt<8>(Loc, Val, Type);
+ *Loc = Val;
+ break;
+ case R_386_PC8:
+ checkInt<8>(Loc, Val, Type);
+ *Loc = Val;
+ break;
+ case R_386_16:
+ checkUInt<16>(Loc, Val, Type);
write16le(Loc, Val);
- return;
+ break;
+ case R_386_PC16:
+ checkInt<16>(Loc, Val, Type);
+ write16le(Loc, Val);
+ break;
+ default:
+ checkInt<32>(Loc, Val, Type);
+ write32le(Loc, Val);
}
- write32le(Loc, Val);
}
void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
@@ -527,7 +578,7 @@ void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
- relocateOne(Loc + 5, R_386_32, Val);
+ write32le(Loc + 5, Val);
}
void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
@@ -543,7 +594,7 @@ void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax
};
memcpy(Loc - 3, Inst, sizeof(Inst));
- relocateOne(Loc + 5, R_386_32, Val);
+ write32le(Loc + 5, Val);
}
// In some conditions, relocations can be optimized to avoid using GOT.
@@ -583,13 +634,13 @@ void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
Loc[-1] = 0x80 | (Reg << 3) | Reg;
}
}
- relocateOne(Loc, R_386_TLS_LE, Val);
+ write32le(Loc, Val);
}
void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
if (Type == R_386_TLS_LDO_32) {
- relocateOne(Loc, R_386_TLS_LE, Val);
+ write32le(Loc, Val);
return;
}
@@ -625,12 +676,16 @@ template <class ELFT> X86_64TargetInfo<ELFT>::X86_64TargetInfo() {
// Align to the large page size (known as a superpage or huge page).
// FreeBSD automatically promotes large, superpage-aligned allocations.
DefaultImageBase = 0x200000;
+ // 0xCC is the "int3" (call debug exception handler) instruction.
+ TrapInstr = 0xcccccccc;
}
template <class ELFT>
-RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
- const SymbolBody &S) const {
+RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
+ case R_X86_64_8:
+ case R_X86_64_16:
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
@@ -660,10 +715,9 @@ RelExpr X86_64TargetInfo<ELFT>::getRelExpr(uint32_t Type,
case R_X86_64_GOTTPOFF:
return R_GOT_PC;
case R_X86_64_NONE:
- return R_HINT;
+ return R_NONE;
default:
- error("do not know how to handle relocation '" + toString(Type) + "' (" +
- Twine(Type) + ")");
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
return R_HINT;
}
}
@@ -681,25 +735,25 @@ template <class ELFT>
void X86_64TargetInfo<ELFT>::writeGotPlt(uint8_t *Buf,
const SymbolBody &S) const {
// See comments in X86TargetInfo::writeGotPlt.
- write32le(Buf, S.getPltVA<ELFT>() + 6);
+ write32le(Buf, S.getPltVA() + 6);
}
template <class ELFT>
void X86_64TargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
const uint8_t PltData[] = {
- 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
- 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
- 0x0f, 0x1f, 0x40, 0x00 // nopl 0x0(rax)
+ 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip)
+ 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip)
+ 0x0f, 0x1f, 0x40, 0x00 // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = In<ELFT>::GotPlt->getVA();
+ uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
uint64_t Plt = In<ELFT>::Plt->getVA();
- write32le(Buf + 2, Got - Plt + 2); // GOT+8
- write32le(Buf + 8, Got - Plt + 4); // GOT+16
+ write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
+ write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
}
template <class ELFT>
-void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
@@ -709,7 +763,7 @@ void X86_64TargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, Inst, sizeof(Inst));
- write32le(Buf + 2, GotEntryAddr - PltEntryAddr - 6);
+ write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6);
write32le(Buf + 7, Index);
write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16);
}
@@ -725,11 +779,6 @@ bool X86_64TargetInfo<ELFT>::isTlsInitialExecRel(uint32_t Type) const {
}
template <class ELFT>
-bool X86_64TargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_X86_64_TLSGD;
-}
-
-template <class ELFT>
bool X86_64TargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 ||
Type == R_X86_64_TLSLD;
@@ -752,9 +801,10 @@ void X86_64TargetInfo<ELFT>::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type,
0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
+
// The original code used a pc relative relocation and so we have to
// compensate for the -4 in had in the addend.
- relocateOne(Loc + 8, R_X86_64_TPOFF32, Val + 4);
+ write32le(Loc + 8, Val + 4);
}
template <class ELFT>
@@ -774,9 +824,10 @@ void X86_64TargetInfo<ELFT>::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type,
0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax
};
memcpy(Loc - 4, Inst, sizeof(Inst));
+
// Both code sequences are PC relatives, but since we are moving the constant
// forward by 8 bytes we have to subtract the value by 8.
- relocateOne(Loc + 8, R_X86_64_PC32, Val - 8);
+ write32le(Loc + 8, Val - 8);
}
// In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to
@@ -821,7 +872,7 @@ void X86_64TargetInfo<ELFT>::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type,
// The original code used a PC relative relocation.
// Need to compensate for the -4 it had in the addend.
- relocateOne(Loc, R_X86_64_TPOFF32, Val + 4);
+ write32le(Loc, Val + 4);
}
template <class ELFT>
@@ -841,7 +892,7 @@ void X86_64TargetInfo<ELFT>::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type,
return;
}
if (Type == R_X86_64_DTPOFF32) {
- relocateOne(Loc, R_X86_64_TPOFF32, Val);
+ write32le(Loc, Val);
return;
}
@@ -857,6 +908,14 @@ template <class ELFT>
void X86_64TargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
uint64_t Val) const {
switch (Type) {
+ case R_X86_64_8:
+ checkUInt<8>(Loc, Val, Type);
+ *Loc = Val;
+ break;
+ case R_X86_64_16:
+ checkUInt<16>(Loc, Val, Type);
+ write16le(Loc, Val);
+ break;
case R_X86_64_32:
checkUInt<32>(Loc, Val, Type);
write32le(Loc, Val);
@@ -898,12 +957,14 @@ RelExpr X86_64TargetInfo<ELFT>::adjustRelaxExpr(uint32_t Type,
return RelExpr;
const uint8_t Op = Data[-2];
const uint8_t ModRm = Data[-1];
+
// FIXME: When PIC is disabled and foo is defined locally in the
// lower 32 bit address space, memory operand in mov can be converted into
// immediate operand. Otherwise, mov must be changed to lea. We support only
// latter relaxation at this moment.
if (Op == 0x8b)
return R_RELAX_GOT_PC;
+
// Relax call and jmp.
if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25))
return R_RELAX_GOT_PC;
@@ -961,7 +1022,7 @@ void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
// SIB.base field.
// See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A).
Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
- relocateOne(Loc, R_X86_64_PC32, Val);
+ write32le(Loc, Val);
return;
}
@@ -982,7 +1043,7 @@ void X86_64TargetInfo<ELFT>::relaxGotNoPic(uint8_t *Loc, uint64_t Val,
// descriptions about each operation.
Loc[-2] = 0x81;
Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2;
- relocateOne(Loc, R_X86_64_PC32, Val);
+ write32le(Loc, Val);
}
template <class ELFT>
@@ -993,7 +1054,7 @@ void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
// Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg".
if (Op == 0x8b) {
Loc[-2] = 0x8d;
- relocateOne(Loc, R_X86_64_PC32, Val);
+ write32le(Loc, Val);
return;
}
@@ -1012,7 +1073,7 @@ void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
// prefix. That makes result expression to be a single instruction.
Loc[-2] = 0x67; // addr32 prefix
Loc[-1] = 0xe8; // call
- relocateOne(Loc, R_X86_64_PC32, Val);
+ write32le(Loc, Val);
return;
}
@@ -1021,7 +1082,7 @@ void X86_64TargetInfo<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const {
assert(ModRm == 0x25);
Loc[-2] = 0xe9; // jmp
Loc[3] = 0x90; // nop
- relocateOne(Loc - 1, R_X86_64_PC32, Val + 1);
+ write32le(Loc - 1, Val + 1);
}
// Relocation masks following the #lo(value), #hi(value), #ha(value),
@@ -1059,7 +1120,8 @@ void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
}
-RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
case R_PPC_REL24:
case R_PPC_REL32:
@@ -1108,7 +1170,8 @@ uint64_t getPPC64TocBase() {
return TocVA + PPC64TocOffset;
}
-RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
default:
return R_ABS;
@@ -1126,10 +1189,10 @@ RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
}
}
-void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
- uint64_t Off = GotEntryAddr - getPPC64TocBase();
+ uint64_t Off = GotPltEntryAddr - getPPC64TocBase();
// FIXME: What we should do, in theory, is get the offset of the function
// descriptor in the .opd section, and use that as the offset from %r2 (the
@@ -1256,8 +1319,8 @@ AArch64TargetInfo::AArch64TargetInfo() {
TcbSize = 16;
}
-RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
- const SymbolBody &S) const {
+RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
default:
return R_ABS;
@@ -1289,6 +1352,8 @@ RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type,
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
return R_GOT_PAGE_PC;
+ case R_AARCH64_NONE:
+ return R_NONE;
}
}
@@ -1361,7 +1426,7 @@ void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const {
relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16);
}
-void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const uint8_t Inst[] = {
@@ -1373,9 +1438,9 @@ void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
memcpy(Buf, Inst, sizeof(Inst));
relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21,
- getAArch64Page(GotEntryAddr) - getAArch64Page(PltEntryAddr));
- relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotEntryAddr);
- relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotEntryAddr);
+ getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr));
+ relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr);
+ relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr);
}
static void write32AArch64Addr(uint8_t *L, uint64_t Imm) {
@@ -1598,7 +1663,8 @@ void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
}
-RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
case R_AMDGPU_ABS32:
case R_AMDGPU_ABS64:
@@ -1612,7 +1678,8 @@ RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_AMDGPU_GOTPCREL32_HI:
return R_GOT_PC;
default:
- fatal("do not know how to handle relocation " + Twine(Type));
+ error(toString(S.File) + ": unknown relocation type: " + toString(Type));
+ return R_HINT;
}
}
@@ -1634,7 +1701,8 @@ ARMTargetInfo::ARMTargetInfo() {
NeedsThunks = true;
}
-RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
+RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
switch (Type) {
default:
return R_ABS;
@@ -1683,7 +1751,7 @@ RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S) const {
case R_ARM_THM_MOVT_PREL:
return R_PC;
case R_ARM_NONE:
- return R_HINT;
+ return R_NONE;
case R_ARM_TLS_LE32:
return R_TLS;
}
@@ -1709,7 +1777,7 @@ void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const {
// An ARM entry is the address of the ifunc resolver function.
- write32le(Buf, S.getVA<ELF32LE>());
+ write32le(Buf, S.getVA());
}
void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
@@ -1726,7 +1794,13 @@ void ARMTargetInfo::writePltHeader(uint8_t *Buf) const {
write32le(Buf + 16, GotPlt - L1 - 8);
}
-void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void ARMTargetInfo::addPltHeaderSymbols(InputSectionBase *ISD) const {
+ auto *IS = cast<InputSection>(ISD);
+ addSyntheticLocal<ELF32LE>("$a", STT_NOTYPE, 0, 0, IS);
+ addSyntheticLocal<ELF32LE>("$d", STT_NOTYPE, 16, 0, IS);
+}
+
+void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
// FIXME: Using simple code sequence with simple relocations.
@@ -1740,18 +1814,24 @@ void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
};
memcpy(Buf, PltData, sizeof(PltData));
uint64_t L1 = PltEntryAddr + 4;
- write32le(Buf + 12, GotEntryAddr - L1 - 8);
+ write32le(Buf + 12, GotPltEntryAddr - L1 - 8);
+}
+
+void ARMTargetInfo::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const {
+ auto *IS = cast<InputSection>(ISD);
+ addSyntheticLocal<ELF32LE>("$a", STT_NOTYPE, Off, 0, IS);
+ addSyntheticLocal<ELF32LE>("$d", STT_NOTYPE, Off + 12, 0, IS);
}
-RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
- const InputFile &File,
- const SymbolBody &S) const {
+bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType,
+ const InputFile *File,
+ const SymbolBody &S) const {
// If S is an undefined weak symbol in an executable we don't need a Thunk.
// In a DSO calls to undefined symbols, including weak ones get PLT entries
// which may need a thunk.
- if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak()
- && !Config->Shared)
- return Expr;
+ if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() &&
+ !Config->Shared)
+ return false;
// A state change from ARM to Thumb and vice versa must go through an
// interworking thunk if the relocation type is not R_ARM_CALL or
// R_ARM_THM_CALL.
@@ -1761,20 +1841,18 @@ RelExpr ARMTargetInfo::getThunkExpr(RelExpr Expr, uint32_t RelocType,
case R_ARM_JUMP24:
// Source is ARM, all PLT entries are ARM so no interworking required.
// Otherwise we need to interwork if Symbol has bit 0 set (Thumb).
- if (Expr == R_PC && ((S.getVA<ELF32LE>() & 1) == 1))
- return R_THUNK_PC;
+ if (Expr == R_PC && ((S.getVA() & 1) == 1))
+ return true;
break;
case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24:
// Source is Thumb, all PLT entries are ARM so interworking is required.
// Otherwise we need to interwork if Symbol has bit 0 clear (ARM).
- if (Expr == R_PLT_PC)
- return R_THUNK_PLT_PC;
- if ((S.getVA<ELF32LE>() & 1) == 0)
- return R_THUNK_PC;
+ if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0))
+ return true;
break;
}
- return Expr;
+ return false;
}
void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
@@ -1796,6 +1874,7 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
case R_ARM_TLS_LDO32:
case R_ARM_TLS_LE32:
case R_ARM_TLS_TPOFF32:
+ case R_ARM_TLS_DTPOFF32:
write32le(Loc, Val);
break;
case R_ARM_TLS_DTPMOD32:
@@ -1911,8 +1990,8 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type,
}
}
-uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
+int64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
switch (Type) {
default:
return 0;
@@ -1990,10 +2069,6 @@ bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const {
return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32;
}
-bool ARMTargetInfo::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_ARM_TLS_GD32;
-}
-
bool ARMTargetInfo::isTlsInitialExecRel(uint32_t Type) const {
return Type == R_ARM_TLS_IE32;
}
@@ -2022,8 +2097,8 @@ template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
}
template <class ELFT>
-RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
- const SymbolBody &S) const {
+RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
+ const uint8_t *Loc) const {
// See comment in the calculateMipsRelChain.
if (ELFT::Is64Bits || Config->MipsN32Abi)
Type &= 0xff;
@@ -2039,13 +2114,16 @@ RelExpr MipsTargetInfo<ELFT>::getRelExpr(uint32_t Type,
return R_PLT;
case R_MIPS_HI16:
case R_MIPS_LO16:
- case R_MIPS_GOT_OFST:
// R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate
// offset between start of function and 'gp' value which by default
// equal to the start of .got section. In that case we consider these
// relocations as relative.
- if (&S == ElfSym<ELFT>::MipsGpDisp)
- return R_PC;
+ if (&S == ElfSym::MipsGpDisp)
+ return R_MIPS_GOT_GP_PC;
+ if (&S == ElfSym::MipsLocalGp)
+ return R_MIPS_GOT_GP;
+ // fallthrough
+ case R_MIPS_GOT_OFST:
return R_ABS;
case R_MIPS_PC32:
case R_MIPS_PC16:
@@ -2092,11 +2170,6 @@ bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const {
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::isTlsGlobalDynamicRel(uint32_t Type) const {
- return Type == R_MIPS_TLS_GD;
-}
-
-template <class ELFT>
void MipsTargetInfo<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
write32<ELFT::TargetEndianness>(Buf, In<ELFT>::Plt->getVA());
}
@@ -2161,18 +2234,20 @@ void MipsTargetInfo<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0])
write32<E>(Buf + 12, 0x031cc023); // subu $24, $24, $28
}
+
write32<E>(Buf + 16, 0x03e07825); // move $15, $31
write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
write32<E>(Buf + 24, 0x0320f809); // jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
- uint64_t Got = In<ELFT>::GotPlt->getVA();
- writeMipsHi16<E>(Buf, Got);
- writeMipsLo16<E>(Buf + 4, Got);
- writeMipsLo16<E>(Buf + 8, Got);
+
+ uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
+ writeMipsHi16<E>(Buf, GotPlt);
+ writeMipsLo16<E>(Buf + 4, GotPlt);
+ writeMipsLo16<E>(Buf + 8, GotPlt);
}
template <class ELFT>
-void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
+void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const {
const endianness E = ELFT::TargetEndianness;
@@ -2181,37 +2256,37 @@ void MipsTargetInfo<ELFT>::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
// jr $25
write32<E>(Buf + 8, isMipsR6<ELFT>() ? 0x03200009 : 0x03200008);
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
- writeMipsHi16<E>(Buf, GotEntryAddr);
- writeMipsLo16<E>(Buf + 4, GotEntryAddr);
- writeMipsLo16<E>(Buf + 12, GotEntryAddr);
+ writeMipsHi16<E>(Buf, GotPltEntryAddr);
+ writeMipsLo16<E>(Buf + 4, GotPltEntryAddr);
+ writeMipsLo16<E>(Buf + 12, GotPltEntryAddr);
}
template <class ELFT>
-RelExpr MipsTargetInfo<ELFT>::getThunkExpr(RelExpr Expr, uint32_t Type,
- const InputFile &File,
- const SymbolBody &S) const {
+bool MipsTargetInfo<ELFT>::needsThunk(RelExpr Expr, uint32_t Type,
+ const InputFile *File,
+ const SymbolBody &S) const {
// Any MIPS PIC code function is invoked with its address in register $t9.
// So if we have a branch instruction from non-PIC code to the PIC one
// we cannot make the jump directly and need to create a small stubs
// to save the target function address.
// See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
if (Type != R_MIPS_26)
- return Expr;
- auto *F = dyn_cast<ELFFileBase<ELFT>>(&File);
+ return false;
+ auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
if (!F)
- return Expr;
+ return false;
// If current file has PIC code, LA25 stub is not required.
if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC)
- return Expr;
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&S);
+ return false;
+ auto *D = dyn_cast<DefinedRegular>(&S);
// LA25 is required if target file has PIC code
// or target symbol is a PIC symbol.
- return D && D->isMipsPIC() ? R_THUNK_ABS : Expr;
+ return D && D->isMipsPIC<ELFT>();
}
template <class ELFT>
-uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
- uint32_t Type) const {
+int64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
+ uint32_t Type) const {
const endianness E = ELFT::TargetEndianness;
switch (Type) {
default:
@@ -2220,7 +2295,7 @@ uint64_t MipsTargetInfo<ELFT>::getImplicitAddend(const uint8_t *Buf,
case R_MIPS_GPREL32:
case R_MIPS_TLS_DTPREL32:
case R_MIPS_TLS_TPREL32:
- return read32<E>(Buf);
+ return SignExtend64<32>(read32<E>(Buf));
case R_MIPS_26:
// FIXME (simon): If the relocation target symbol is not a PLT entry
// we should use another expression for calculation:
@@ -2303,9 +2378,19 @@ void MipsTargetInfo<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type,
case R_MIPS_26:
write32<E>(Loc, (read32<E>(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff));
break;
+ case R_MIPS_GOT16:
+ // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode
+ // is updated addend (not a GOT index). In that case write high 16 bits
+ // to store a correct addend value.
+ if (Config->Relocatable)
+ writeMipsHi16<E>(Loc, Val);
+ else {
+ checkInt<16>(Loc, Val, Type);
+ writeMipsLo16<E>(Loc, Val);
+ }
+ break;
case R_MIPS_GOT_DISP:
case R_MIPS_GOT_PAGE:
- case R_MIPS_GOT16:
case R_MIPS_GPREL16:
case R_MIPS_TLS_GD:
case R_MIPS_TLS_LDM: