summaryrefslogtreecommitdiff
path: root/ELF/Arch/Mips.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Arch/Mips.cpp')
-rw-r--r--ELF/Arch/Mips.cpp175
1 files changed, 83 insertions, 92 deletions
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index 495e2567006f..dc70401c0b0e 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -32,7 +32,6 @@ public:
RelExpr getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const override;
int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override;
- bool isPicRel(RelType Type) const override;
RelType getDynRel(RelType Type) const override;
void writeGotPlt(uint8_t *Buf, const Symbol &S) const override;
void writePltHeader(uint8_t *Buf) const override;
@@ -50,6 +49,7 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
DefaultMaxPageSize = 65536;
GotEntrySize = sizeof(typename ELFT::uint);
GotPltEntrySize = sizeof(typename ELFT::uint);
+ GotBaseSymInGotPlt = false;
PltEntrySize = 16;
PltHeaderSize = 32;
CopyRel = R_MIPS_COPY;
@@ -101,8 +101,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_HIGHEST:
case R_MICROMIPS_HI16:
case R_MICROMIPS_LO16:
- case R_MICROMIPS_HIGHER:
- case R_MICROMIPS_HIGHEST:
// 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
@@ -124,8 +122,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_TLS_TPREL_LO16:
case R_MIPS_TLS_TPREL32:
case R_MIPS_TLS_TPREL64:
- case R_MICROMIPS_GOT_OFST:
- case R_MICROMIPS_SUB:
case R_MICROMIPS_TLS_DTPREL_HI16:
case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_TPREL_HI16:
@@ -155,7 +151,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MIPS_GOT_DISP:
case R_MIPS_TLS_GOTTPREL:
case R_MICROMIPS_CALL16:
- case R_MICROMIPS_GOT_DISP:
case R_MICROMIPS_TLS_GOTTPREL:
return R_MIPS_GOT_OFF;
case R_MIPS_CALL_HI16:
@@ -168,7 +163,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
case R_MICROMIPS_GOT_LO16:
return R_MIPS_GOT_OFF32;
case R_MIPS_GOT_PAGE:
- case R_MICROMIPS_GOT_PAGE:
return R_MIPS_GOT_LOCAL_PAGE;
case R_MIPS_TLS_GD:
case R_MICROMIPS_TLS_GD:
@@ -183,12 +177,10 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S,
}
}
-template <class ELFT> bool MIPS<ELFT>::isPicRel(RelType Type) const {
- return Type == R_MIPS_32 || Type == R_MIPS_64;
-}
-
template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
- return RelativeRel;
+ if (Type == R_MIPS_32 || Type == R_MIPS_64)
+ return RelativeRel;
+ return R_MIPS_NONE;
}
template <class ELFT>
@@ -213,8 +205,8 @@ template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) {
}
template <endianness E>
-static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
- uint8_t Shift) {
+static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
uint32_t Instr = read32<E>(Loc);
uint32_t Mask = 0xffffffff >> (32 - BitsSize);
uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
@@ -222,14 +214,14 @@ static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
}
template <endianness E>
-static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
- uint8_t Shift) {
+static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
+ uint8_t Shift) {
// See comments in readShuffle for purpose of this code.
uint16_t *Words = (uint16_t *)Loc;
if (E == support::little)
std::swap(Words[0], Words[1]);
- writeRelocation<E>(Loc, V, BitsSize, Shift);
+ writeValue<E>(Loc, V, BitsSize, Shift);
if (E == support::little)
std::swap(Words[0], Words[1]);
@@ -296,13 +288,14 @@ template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2
}
- write32<E>(Buf + 24, 0x0320f809); // jalr $25
+ uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809;
+ write32<E>(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25
write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2
uint64_t GotPlt = InX::GotPlt->getVA();
- writeRelocation<E>(Buf, GotPlt + 0x8000, 16, 16);
- writeRelocation<E>(Buf + 4, GotPlt, 16, 0);
- writeRelocation<E>(Buf + 8, GotPlt, 16, 0);
+ writeValue<E>(Buf, GotPlt + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPlt, 16, 0);
+ writeValue<E>(Buf + 8, GotPlt, 16, 0);
}
template <class ELFT>
@@ -330,13 +323,16 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
return;
}
+ uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009)
+ : (Config->ZHazardplt ? 0x03200408 : 0x03200008);
+
write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
- write32<E>(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25
+ write32<E>(Buf + 8, JrInst); // jr $25 / jr.hb $25
write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry)
- writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
- writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0);
- writeRelocation<E>(Buf + 12, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16);
+ writeValue<E>(Buf + 4, GotPltEntryAddr, 16, 0);
+ writeValue<E>(Buf + 12, GotPltEntryAddr, 16, 0);
}
template <class ELFT>
@@ -455,9 +451,6 @@ calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) {
return std::make_pair(Type2, Val);
if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16))
return std::make_pair(Type3, -Val);
- if (Type2 == R_MICROMIPS_SUB &&
- (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16))
- return std::make_pair(Type3, -Val);
error(getErrorLocation(Loc) + "unsupported relocations combination " +
Twine(Type));
return std::make_pair(Type & 0xff, Val);
@@ -467,6 +460,9 @@ template <class ELFT>
void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
const endianness E = ELFT::TargetEndianness;
+ if (ELFT::Is64Bits || Config->MipsN32Abi)
+ std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
+
// Thread pointer and DRP offsets from the start of TLS data area.
// https://www.linux-mips.org/wiki/NPTL
if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 ||
@@ -481,9 +477,6 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
Val -= 0x7000;
}
- if (ELFT::Is64Bits || Config->MipsN32Abi)
- std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
-
switch (Type) {
case R_MIPS_32:
case R_MIPS_GPREL32:
@@ -497,25 +490,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
write64<E>(Loc, Val);
break;
case R_MIPS_26:
- writeRelocation<E>(Loc, Val, 26, 2);
+ writeValue<E>(Loc, Val, 26, 2);
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) {
- writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
} else {
- checkInt<16>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeValue<E>(Loc, Val, 16, 0);
}
break;
case R_MICROMIPS_GOT16:
if (Config->Relocatable) {
- writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
} else {
- checkInt<16>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
}
break;
case R_MIPS_CALL16:
@@ -525,7 +518,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_TLS_GD:
case R_MIPS_TLS_GOTTPREL:
case R_MIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
+ checkInt(Loc, Val, 16, Type);
LLVM_FALLTHROUGH;
case R_MIPS_CALL_LO16:
case R_MIPS_GOT_LO16:
@@ -534,28 +527,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_PCLO16:
case R_MIPS_TLS_DTPREL_LO16:
case R_MIPS_TLS_TPREL_LO16:
- writeRelocation<E>(Loc, Val, 16, 0);
+ writeValue<E>(Loc, Val, 16, 0);
break;
- case R_MICROMIPS_GOT_DISP:
- case R_MICROMIPS_GOT_PAGE:
case R_MICROMIPS_GPREL16:
case R_MICROMIPS_TLS_GD:
case R_MICROMIPS_TLS_LDM:
- checkInt<16>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ checkInt(Loc, Val, 16, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
break;
case R_MICROMIPS_CALL16:
case R_MICROMIPS_CALL_LO16:
- case R_MICROMIPS_GOT_OFST:
case R_MICROMIPS_LO16:
case R_MICROMIPS_TLS_DTPREL_LO16:
case R_MICROMIPS_TLS_GOTTPREL:
case R_MICROMIPS_TLS_TPREL_LO16:
- writeMicroRelocation32<E>(Loc, Val, 16, 0);
+ writeShuffleValue<E>(Loc, Val, 16, 0);
break;
case R_MICROMIPS_GPREL7_S2:
- checkInt<7>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 7, 2);
+ checkInt(Loc, Val, 7, Type);
+ writeShuffleValue<E>(Loc, Val, 7, 2);
break;
case R_MIPS_CALL_HI16:
case R_MIPS_GOT_HI16:
@@ -563,86 +553,80 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_MIPS_PCHI16:
case R_MIPS_TLS_DTPREL_HI16:
case R_MIPS_TLS_TPREL_HI16:
- writeRelocation<E>(Loc, Val + 0x8000, 16, 16);
+ writeValue<E>(Loc, Val + 0x8000, 16, 16);
break;
case R_MICROMIPS_CALL_HI16:
case R_MICROMIPS_GOT_HI16:
case R_MICROMIPS_HI16:
case R_MICROMIPS_TLS_DTPREL_HI16:
case R_MICROMIPS_TLS_TPREL_HI16:
- writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
+ writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16);
break;
case R_MIPS_HIGHER:
- writeRelocation<E>(Loc, Val + 0x80008000, 16, 32);
+ writeValue<E>(Loc, Val + 0x80008000, 16, 32);
break;
case R_MIPS_HIGHEST:
- writeRelocation<E>(Loc, Val + 0x800080008000, 16, 48);
- break;
- case R_MICROMIPS_HIGHER:
- writeMicroRelocation32<E>(Loc, Val + 0x80008000, 16, 32);
- break;
- case R_MICROMIPS_HIGHEST:
- writeMicroRelocation32<E>(Loc, Val + 0x800080008000, 16, 48);
+ writeValue<E>(Loc, Val + 0x800080008000, 16, 48);
break;
case R_MIPS_JALR:
case R_MICROMIPS_JALR:
// Ignore this optimization relocation for now
break;
case R_MIPS_PC16:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<18>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 16, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 18, Type);
+ writeValue<E>(Loc, Val, 16, 2);
break;
case R_MIPS_PC19_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<21>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 19, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 21, Type);
+ writeValue<E>(Loc, Val, 19, 2);
break;
case R_MIPS_PC21_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<23>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 21, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 23, Type);
+ writeValue<E>(Loc, Val, 21, 2);
break;
case R_MIPS_PC26_S2:
- checkAlignment<4>(Loc, Val, Type);
- checkInt<28>(Loc, Val, Type);
- writeRelocation<E>(Loc, Val, 26, 2);
+ checkAlignment(Loc, Val, 4, Type);
+ checkInt(Loc, Val, 28, Type);
+ writeValue<E>(Loc, Val, 26, 2);
break;
case R_MIPS_PC32:
- writeRelocation<E>(Loc, Val, 32, 0);
+ writeValue<E>(Loc, Val, 32, 0);
break;
case R_MICROMIPS_26_S1:
case R_MICROMIPS_PC26_S1:
- checkInt<27>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 26, 1);
+ checkInt(Loc, Val, 27, Type);
+ writeShuffleValue<E>(Loc, Val, 26, 1);
break;
case R_MICROMIPS_PC7_S1:
- checkInt<8>(Loc, Val, Type);
+ checkInt(Loc, Val, 8, Type);
writeMicroRelocation16<E>(Loc, Val, 7, 1);
break;
case R_MICROMIPS_PC10_S1:
- checkInt<11>(Loc, Val, Type);
+ checkInt(Loc, Val, 11, Type);
writeMicroRelocation16<E>(Loc, Val, 10, 1);
break;
case R_MICROMIPS_PC16_S1:
- checkInt<17>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 16, 1);
+ checkInt(Loc, Val, 17, Type);
+ writeShuffleValue<E>(Loc, Val, 16, 1);
break;
case R_MICROMIPS_PC18_S3:
- checkInt<21>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 18, 3);
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 18, 3);
break;
case R_MICROMIPS_PC19_S2:
- checkInt<21>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 19, 2);
+ checkInt(Loc, Val, 21, Type);
+ writeShuffleValue<E>(Loc, Val, 19, 2);
break;
case R_MICROMIPS_PC21_S1:
- checkInt<22>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 21, 1);
+ checkInt(Loc, Val, 22, Type);
+ writeShuffleValue<E>(Loc, Val, 21, 1);
break;
case R_MICROMIPS_PC23_S2:
- checkInt<25>(Loc, Val, Type);
- writeMicroRelocation32<E>(Loc, Val, 23, 2);
+ checkInt(Loc, Val, 25, Type);
+ writeShuffleValue<E>(Loc, Val, 23, 2);
break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
@@ -651,19 +635,26 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const {
return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST ||
- Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST;
+ Type == R_MICROMIPS_LO16;
}
// Return true if the symbol is a PIC function.
template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) {
- typedef typename ELFT::Ehdr Elf_Ehdr;
- if (!Sym->Section || !Sym->isFunc())
+ if (!Sym->isFunc())
+ return false;
+
+ if (Sym->StOther & STO_MIPS_PIC)
+ return true;
+
+ if (!Sym->Section)
+ return false;
+
+ ObjFile<ELFT> *File =
+ cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>();
+ if (!File)
return false;
- auto *Sec = cast<InputSectionBase>(Sym->Section);
- const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader();
- return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC ||
- (Hdr->e_flags & EF_MIPS_PIC);
+ return File->getObj().getHeader()->e_flags & EF_MIPS_PIC;
}
template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {