forked from OSchip/llvm-project
[MIPS] Initial support of microMIPS code linking
The patch implements initial support of microMIPS code linking: - Handle microMIPS specific relocations. - Emit both R1-R5 and R6 microMIPS PLT records. For now linking mixed set of regular and microMIPS object files is not supported. Also the patch does not handle (setup and clear) the least-significant bit of an address which is utilized as the ISA mode bit and allows to make jump between regular and microMIPS code without any thunks. Differential revision: https://reviews.llvm.org/D37335 llvm-svn: 313028
This commit is contained in:
parent
2420122fbb
commit
4f70b30d6f
|
@ -80,14 +80,23 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
|
|||
default:
|
||||
return R_ABS;
|
||||
case R_MIPS_JALR:
|
||||
case R_MICROMIPS_JALR:
|
||||
return R_HINT;
|
||||
case R_MIPS_GPREL16:
|
||||
case R_MIPS_GPREL32:
|
||||
case R_MICROMIPS_GPREL16:
|
||||
case R_MICROMIPS_GPREL7_S2:
|
||||
return R_MIPS_GOTREL;
|
||||
case R_MIPS_26:
|
||||
return R_PLT;
|
||||
case R_MICROMIPS_26_S1:
|
||||
return R_PLT;
|
||||
case R_MICROMIPS_PC26_S1:
|
||||
return R_PLT_PC;
|
||||
case R_MIPS_HI16:
|
||||
case R_MIPS_LO16:
|
||||
case R_MICROMIPS_HI16:
|
||||
case R_MICROMIPS_LO16:
|
||||
// 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
|
||||
|
@ -98,6 +107,7 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
|
|||
return R_MIPS_GOT_GP;
|
||||
LLVM_FALLTHROUGH;
|
||||
case R_MIPS_GOT_OFST:
|
||||
case R_MICROMIPS_GOT_OFST:
|
||||
return R_ABS;
|
||||
case R_MIPS_PC32:
|
||||
case R_MIPS_PC16:
|
||||
|
@ -106,25 +116,43 @@ RelExpr MIPS<ELFT>::getRelExpr(uint32_t Type, const SymbolBody &S,
|
|||
case R_MIPS_PC26_S2:
|
||||
case R_MIPS_PCHI16:
|
||||
case R_MIPS_PCLO16:
|
||||
case R_MICROMIPS_PC7_S1:
|
||||
case R_MICROMIPS_PC10_S1:
|
||||
case R_MICROMIPS_PC16_S1:
|
||||
case R_MICROMIPS_PC18_S3:
|
||||
case R_MICROMIPS_PC19_S2:
|
||||
case R_MICROMIPS_PC23_S2:
|
||||
case R_MICROMIPS_PC21_S1:
|
||||
return R_PC;
|
||||
case R_MIPS_GOT16:
|
||||
case R_MICROMIPS_GOT16:
|
||||
if (S.isLocal())
|
||||
return R_MIPS_GOT_LOCAL_PAGE;
|
||||
LLVM_FALLTHROUGH;
|
||||
case R_MIPS_CALL16:
|
||||
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:
|
||||
case R_MIPS_CALL_LO16:
|
||||
case R_MIPS_GOT_HI16:
|
||||
case R_MIPS_GOT_LO16:
|
||||
case R_MICROMIPS_CALL_HI16:
|
||||
case R_MICROMIPS_CALL_LO16:
|
||||
case R_MICROMIPS_GOT_HI16:
|
||||
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:
|
||||
return R_MIPS_TLSGD;
|
||||
case R_MIPS_TLS_LDM:
|
||||
case R_MICROMIPS_TLS_LDM:
|
||||
return R_MIPS_TLSLD;
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +170,19 @@ void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const SymbolBody &) const {
|
|||
write32<ELFT::TargetEndianness>(Buf, InX::Plt->getVA());
|
||||
}
|
||||
|
||||
template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) {
|
||||
// The major opcode of a microMIPS instruction needs to appear
|
||||
// in the first 16-bit word (lowest address) for efficient hardware
|
||||
// decode so that it knows if the instruction is 16-bit or 32-bit
|
||||
// as early as possible. To do so, little-endian binaries keep 16-bit
|
||||
// words in a big-endian order. That is why we have to swap these
|
||||
// words to get a correct value.
|
||||
uint32_t V = read32<E>(Loc);
|
||||
if (E == support::little)
|
||||
return (V << 16) | (V >> 16);
|
||||
return V;
|
||||
}
|
||||
|
||||
template <endianness E>
|
||||
static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
|
||||
uint8_t Shift) {
|
||||
|
@ -151,6 +192,37 @@ static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
|
|||
write32<E>(Loc, Data);
|
||||
}
|
||||
|
||||
template <endianness E>
|
||||
static void writeMicroRelocation32(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);
|
||||
|
||||
if (E == support::little)
|
||||
std::swap(Words[0], Words[1]);
|
||||
}
|
||||
|
||||
template <endianness E>
|
||||
static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
|
||||
uint8_t Shift) {
|
||||
uint16_t Instr = read16<E>(Loc);
|
||||
uint16_t Mask = 0xffff >> (16 - BitsSize);
|
||||
uint16_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask);
|
||||
write16<E>(Loc, Data);
|
||||
}
|
||||
|
||||
template <class ELFT> static bool isMicroMips() {
|
||||
// FIXME (simon): This code does not support the case when both
|
||||
// microMIPS and MIPS object files are linked together.
|
||||
const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
|
||||
uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH_ASE;
|
||||
return Arch == EF_MIPS_MICROMIPS;
|
||||
}
|
||||
|
||||
template <class ELFT> static bool isMipsR6() {
|
||||
const auto &FirstObj = cast<ELFFileBase<ELFT>>(*Config->FirstElf);
|
||||
uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH;
|
||||
|
@ -159,6 +231,34 @@ template <class ELFT> static bool isMipsR6() {
|
|||
|
||||
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
if (isMicroMips<ELFT>()) {
|
||||
uint64_t GotPlt = In<ELFT>::GotPlt->getVA();
|
||||
uint64_t Plt = In<ELFT>::Plt->getVA();
|
||||
// Overwrite trap instructions written by Writer::writeTrapInstr.
|
||||
memset(Buf, 0, PltHeaderSize);
|
||||
|
||||
write16<E>(Buf, isMipsR6<ELFT>() ? 0x7860 : 0x7980);
|
||||
// addiupc v1, (GOTPLT) - .
|
||||
write16<E>(Buf + 4, 0xff23); // lw $25, 0($3)
|
||||
write16<E>(Buf + 8, 0x0535); // subu16 $2, $2, $3
|
||||
write16<E>(Buf + 10, 0x2525); // srl16 $2, $2, 2
|
||||
write16<E>(Buf + 12, 0x3302); // addiu $24, $2, -2
|
||||
write16<E>(Buf + 14, 0xfffe);
|
||||
write16<E>(Buf + 16, 0x0dff); // move $15, $31
|
||||
if (isMipsR6<ELFT>()) {
|
||||
write16<E>(Buf + 18, 0x0f83); // move $28, $3
|
||||
write16<E>(Buf + 20, 0x472b); // jalrc $25
|
||||
write16<E>(Buf + 22, 0x0c00); // nop
|
||||
relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPlt - Plt);
|
||||
} else {
|
||||
write16<E>(Buf + 18, 0x45f9); // jalrc $25
|
||||
write16<E>(Buf + 20, 0x0f83); // move $28, $3
|
||||
write16<E>(Buf + 22, 0x0c00); // nop
|
||||
relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPlt - Plt);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Config->MipsN32Abi) {
|
||||
write32<E>(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0])
|
||||
write32<E>(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14)
|
||||
|
@ -187,6 +287,26 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
|
|||
uint64_t PltEntryAddr, int32_t Index,
|
||||
unsigned RelOff) const {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
if (isMicroMips<ELFT>()) {
|
||||
// Overwrite trap instructions written by Writer::writeTrapInstr.
|
||||
memset(Buf, 0, PltEntrySize);
|
||||
|
||||
if (isMipsR6<ELFT>()) {
|
||||
write16<E>(Buf, 0x7840); // addiupc $2, (GOTPLT) - .
|
||||
write16<E>(Buf + 4, 0xff22); // lw $25, 0($2)
|
||||
write16<E>(Buf + 8, 0x0f02); // move $24, $2
|
||||
write16<E>(Buf + 10, 0x4723); // jrc $25 / jr16 $25
|
||||
relocateOne(Buf, R_MICROMIPS_PC19_S2, GotPltEntryAddr - PltEntryAddr);
|
||||
} else {
|
||||
write16<E>(Buf, 0x7900); // addiupc $2, (GOTPLT) - .
|
||||
write16<E>(Buf + 4, 0xff22); // lw $25, 0($2)
|
||||
write16<E>(Buf + 8, 0x4599); // jrc $25 / jr16 $25
|
||||
write16<E>(Buf + 10, 0x0f02); // move $24, $2
|
||||
relocateOne(Buf, R_MICROMIPS_PC23_S2, GotPltEntryAddr - PltEntryAddr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry)
|
||||
write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15)
|
||||
// jr $25
|
||||
|
@ -205,7 +325,8 @@ bool MIPS<ELFT>::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File,
|
|||
// 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)
|
||||
if (Type != R_MIPS_26 && Type != R_MICROMIPS_26_S1 &&
|
||||
Type != R_MICROMIPS_PC26_S1)
|
||||
return false;
|
||||
auto *F = dyn_cast_or_null<ELFFileBase<ELFT>>(File);
|
||||
if (!F)
|
||||
|
@ -247,6 +368,18 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
|
|||
case R_MIPS_TLS_TPREL_HI16:
|
||||
case R_MIPS_TLS_TPREL_LO16:
|
||||
return SignExtend64<16>(read32<E>(Buf));
|
||||
case R_MICROMIPS_GOT16:
|
||||
case R_MICROMIPS_HI16:
|
||||
return SignExtend64<16>(readShuffle<E>(Buf)) << 16;
|
||||
case R_MICROMIPS_GPREL16:
|
||||
case R_MICROMIPS_LO16:
|
||||
case R_MICROMIPS_TLS_DTPREL_HI16:
|
||||
case R_MICROMIPS_TLS_DTPREL_LO16:
|
||||
case R_MICROMIPS_TLS_TPREL_HI16:
|
||||
case R_MICROMIPS_TLS_TPREL_LO16:
|
||||
return SignExtend64<16>(readShuffle<E>(Buf));
|
||||
case R_MICROMIPS_GPREL7_S2:
|
||||
return SignExtend64<9>(readShuffle<E>(Buf) << 2);
|
||||
case R_MIPS_PC16:
|
||||
return SignExtend64<18>(read32<E>(Buf) << 2);
|
||||
case R_MIPS_PC19_S2:
|
||||
|
@ -257,6 +390,24 @@ int64_t MIPS<ELFT>::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const {
|
|||
return SignExtend64<28>(read32<E>(Buf) << 2);
|
||||
case R_MIPS_PC32:
|
||||
return SignExtend64<32>(read32<E>(Buf));
|
||||
case R_MICROMIPS_26_S1:
|
||||
return SignExtend64<27>(readShuffle<E>(Buf) << 1);
|
||||
case R_MICROMIPS_PC7_S1:
|
||||
return SignExtend64<8>(read16<E>(Buf) << 1);
|
||||
case R_MICROMIPS_PC10_S1:
|
||||
return SignExtend64<11>(read16<E>(Buf) << 1);
|
||||
case R_MICROMIPS_PC16_S1:
|
||||
return SignExtend64<17>(readShuffle<E>(Buf) << 1);
|
||||
case R_MICROMIPS_PC18_S3:
|
||||
return SignExtend64<21>(readShuffle<E>(Buf) << 3);
|
||||
case R_MICROMIPS_PC19_S2:
|
||||
return SignExtend64<21>(readShuffle<E>(Buf) << 2);
|
||||
case R_MICROMIPS_PC21_S1:
|
||||
return SignExtend64<22>(readShuffle<E>(Buf) << 1);
|
||||
case R_MICROMIPS_PC23_S2:
|
||||
return SignExtend64<25>(readShuffle<E>(Buf) << 2);
|
||||
case R_MICROMIPS_PC26_S1:
|
||||
return SignExtend64<27>(readShuffle<E>(Buf) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -282,6 +433,9 @@ calculateMipsRelChain(uint8_t *Loc, uint32_t 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);
|
||||
|
@ -293,10 +447,14 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
|
|||
// 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 ||
|
||||
Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64)
|
||||
Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64 ||
|
||||
Type == R_MICROMIPS_TLS_DTPREL_HI16 ||
|
||||
Type == R_MICROMIPS_TLS_DTPREL_LO16)
|
||||
Val -= 0x8000;
|
||||
else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 ||
|
||||
Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64)
|
||||
Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64 ||
|
||||
Type == R_MICROMIPS_TLS_TPREL_HI16 ||
|
||||
Type == R_MICROMIPS_TLS_TPREL_LO16)
|
||||
Val -= 0x7000;
|
||||
if (ELFT::Is64Bits || Config->MipsN32Abi)
|
||||
std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val);
|
||||
|
@ -326,6 +484,14 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
|
|||
writeRelocation<E>(Loc, Val, 16, 0);
|
||||
}
|
||||
break;
|
||||
case R_MICROMIPS_GOT16:
|
||||
if (Config->Relocatable) {
|
||||
writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16);
|
||||
} else {
|
||||
checkInt<16>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 16, 0);
|
||||
}
|
||||
break;
|
||||
case R_MIPS_GOT_DISP:
|
||||
case R_MIPS_GOT_PAGE:
|
||||
case R_MIPS_GPREL16:
|
||||
|
@ -344,6 +510,27 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
|
|||
case R_MIPS_TLS_TPREL_LO16:
|
||||
writeRelocation<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);
|
||||
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);
|
||||
break;
|
||||
case R_MICROMIPS_GPREL7_S2:
|
||||
checkInt<7>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 7, 2);
|
||||
break;
|
||||
case R_MIPS_CALL_HI16:
|
||||
case R_MIPS_GOT_HI16:
|
||||
case R_MIPS_HI16:
|
||||
|
@ -352,13 +539,27 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
|
|||
case R_MIPS_TLS_TPREL_HI16:
|
||||
writeRelocation<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);
|
||||
break;
|
||||
case R_MIPS_HIGHER:
|
||||
writeRelocation<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);
|
||||
break;
|
||||
case R_MIPS_JALR:
|
||||
case R_MICROMIPS_JALR:
|
||||
// Ignore this optimization relocation for now
|
||||
break;
|
||||
case R_MIPS_PC16:
|
||||
|
@ -384,6 +585,39 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
|
|||
case R_MIPS_PC32:
|
||||
writeRelocation<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);
|
||||
break;
|
||||
case R_MICROMIPS_PC7_S1:
|
||||
checkInt<8>(Loc, Val, Type);
|
||||
writeMicroRelocation16<E>(Loc, Val, 7, 1);
|
||||
break;
|
||||
case R_MICROMIPS_PC10_S1:
|
||||
checkInt<11>(Loc, Val, Type);
|
||||
writeMicroRelocation16<E>(Loc, Val, 10, 1);
|
||||
break;
|
||||
case R_MICROMIPS_PC16_S1:
|
||||
checkInt<17>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 16, 1);
|
||||
break;
|
||||
case R_MICROMIPS_PC18_S3:
|
||||
checkInt<21>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 18, 3);
|
||||
break;
|
||||
case R_MICROMIPS_PC19_S2:
|
||||
checkInt<21>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 19, 2);
|
||||
break;
|
||||
case R_MICROMIPS_PC21_S1:
|
||||
checkInt<22>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 21, 1);
|
||||
break;
|
||||
case R_MICROMIPS_PC23_S2:
|
||||
checkInt<25>(Loc, Val, Type);
|
||||
writeMicroRelocation32<E>(Loc, Val, 23, 2);
|
||||
break;
|
||||
default:
|
||||
error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type));
|
||||
}
|
||||
|
@ -391,7 +625,8 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const {
|
|||
|
||||
template <class ELFT>
|
||||
bool MIPS<ELFT>::usesOnlyLowPageBits(uint32_t Type) const {
|
||||
return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST;
|
||||
return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST ||
|
||||
Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST;
|
||||
}
|
||||
|
||||
template <class ELFT> TargetInfo *elf::getMipsTargetInfo() {
|
||||
|
|
|
@ -534,7 +534,7 @@ static uint64_t getRelocTargetVA(uint32_t Type, int64_t A, uint64_t P,
|
|||
// formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
|
||||
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
|
||||
uint64_t V = InX::MipsGot->getGp() + A - P;
|
||||
if (Type == R_MIPS_LO16)
|
||||
if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16)
|
||||
V += 4;
|
||||
return V;
|
||||
}
|
||||
|
|
|
@ -91,8 +91,12 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
|
|||
// relocation types occupy eight bit. In case of N64 ABI we extract first
|
||||
// relocation from 3-in-1 packet because only the first relocation can
|
||||
// be against a real symbol.
|
||||
if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16)
|
||||
return false;
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
Type &= 0xff;
|
||||
if (Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 ||
|
||||
Type == R_MICROMIPS_GPREL7_S2)
|
||||
return false;
|
||||
}
|
||||
return Body.isPreemptible();
|
||||
}
|
||||
|
||||
|
@ -301,6 +305,8 @@ static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) {
|
|||
return R_MIPS_LO16;
|
||||
case R_MIPS_GOT16:
|
||||
return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE;
|
||||
case R_MICROMIPS_GOT16:
|
||||
return Sym.isLocal() ? R_MICROMIPS_LO16 : R_MIPS_NONE;
|
||||
case R_MIPS_PCHI16:
|
||||
return R_MIPS_PCLO16;
|
||||
case R_MICROMIPS_HI16:
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
.text
|
||||
.set micromips
|
||||
.global foo
|
||||
.type foo,@function
|
||||
foo:
|
||||
nop
|
||||
|
||||
.set nomicromips
|
||||
.global bar
|
||||
.type bar,@function
|
||||
bar:
|
||||
nop
|
|
@ -0,0 +1,46 @@
|
|||
# Check microMIPS GOT relocations for O32 ABI.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
|
||||
# RUN: %s -o %t1.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \
|
||||
# RUN: %S/Inputs/mips-dynamic.s -o %t2.o
|
||||
# RUN: ld.lld %t2.o -shared -o %t.so
|
||||
# RUN: ld.lld %t1.o %t.so -o %t.exe
|
||||
# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# CHECK: Local entries [
|
||||
# CHECK-NEXT: Entry {
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Access: -32744
|
||||
# CHECK-NEXT: Initial: 0x30000
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Entry {
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Access: -32740
|
||||
# CHECK-NEXT: Initial: 0x40000
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Global entries [
|
||||
# CHECK-NEXT: Entry {
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Access: -32736
|
||||
# CHECK-NEXT: Initial: 0x0
|
||||
# CHECK-NEXT: Value: 0x0
|
||||
# CHECK-NEXT: Type: Function
|
||||
# CHECK-NEXT: Section: Undefined
|
||||
# CHECK-NEXT: Name: foo0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
.text
|
||||
.global __start
|
||||
__start:
|
||||
lw $4, %got(data)($28)
|
||||
addiu $4, $4, %lo(data)
|
||||
lw $25, %call16(foo0)($28)
|
||||
|
||||
.data
|
||||
data:
|
||||
.word 0
|
|
@ -0,0 +1,48 @@
|
|||
# Check microMIPS GOT relocations for N64 ABI.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
|
||||
# RUN: %s -o %t1.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \
|
||||
# RUN: %S/Inputs/mips-dynamic.s -o %t2.o
|
||||
# RUN: ld.lld %t2.o -shared -o %t.so
|
||||
# RUN: ld.lld %t1.o %t.so -o %t.exe
|
||||
# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# CHECK: Local entries [
|
||||
# CHECK-NEXT: Entry {
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Access: -32736
|
||||
# CHECK-NEXT: Initial: 0x30000
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: Entry {
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Access: -32728
|
||||
# CHECK-NEXT: Initial: 0x40000
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: Global entries [
|
||||
# CHECK-NEXT: Entry {
|
||||
# CHECK-NEXT: Address:
|
||||
# CHECK-NEXT: Access: -32720
|
||||
# CHECK-NEXT: Initial: 0x0
|
||||
# CHECK-NEXT: Value: 0x0
|
||||
# CHECK-NEXT: Type: Function
|
||||
# CHECK-NEXT: Section: Undefined
|
||||
# CHECK-NEXT: Name: foo0
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
|
||||
.text
|
||||
.global __start
|
||||
__start:
|
||||
lui $28, %hi(%neg(%gp_rel(foo0)))
|
||||
addiu $28, $28, %lo(%neg(%gp_rel(foo0)))
|
||||
lw $4, %got_page(data)($28)
|
||||
addiu $4, $4, %got_ofst(data)
|
||||
lw $25, %call16(foo0)($28)
|
||||
|
||||
.data
|
||||
data:
|
||||
.word 0
|
|
@ -0,0 +1,125 @@
|
|||
# Check PLT creation for microMIPS to microMIPS calls.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
|
||||
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
|
||||
# RUN: ld.lld -shared -o %teb.so %t1eb.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
|
||||
# RUN: -mattr=micromips %s -o %t2eb.o
|
||||
# RUN: ld.lld -o %teb.exe %t2eb.o %teb.so
|
||||
# RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EB %s
|
||||
# RUN: llvm-readobj -mips-plt-got %teb.exe | FileCheck --check-prefix=PLT %s
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
|
||||
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o
|
||||
# RUN: ld.lld -shared -o %tel.so %t1el.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
|
||||
# RUN: -mattr=micromips %s -o %t2el.o
|
||||
# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
|
||||
# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=EL %s
|
||||
# RUN: llvm-readobj -mips-plt-got %tel.exe | FileCheck --check-prefix=PLT %s
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
|
||||
# RUN: -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1eb.o
|
||||
# RUN: ld.lld -shared -o %teb.so %t1eb.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
|
||||
# RUN: -mattr=micromips -mcpu=mips32r6 %s -o %t2eb.o
|
||||
# RUN: ld.lld -o %teb.exe %t2eb.o %teb.so
|
||||
# RUN: llvm-objdump -d -mattr=micromips %teb.exe | FileCheck --check-prefix=EBR6 %s
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
|
||||
# RUN: -mattr=micromips -mcpu=mips32r6 %S/Inputs/mips-micro.s -o %t1el.o
|
||||
# RUN: ld.lld -shared -o %tel.so %t1el.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
|
||||
# RUN: -mattr=micromips -mcpu=mips32r6 %s -o %t2el.o
|
||||
# RUN: ld.lld -o %tel.exe %t2el.o %tel.so
|
||||
# RUN: llvm-objdump -d -mattr=micromips %tel.exe | FileCheck --check-prefix=ELR6 %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# EB: Disassembly of section .plt:
|
||||
# EB-NEXT: .plt:
|
||||
# EB-NEXT: 20010: 79 80 3f fd addiupc $3, 65524
|
||||
# EB-NEXT: 20014: ff 23 00 00 lw $25, 0($3)
|
||||
# EB-NEXT: 20018: 05 35 subu16 $2, $2, $3
|
||||
# EB-NEXT: 2001a: 25 25 srl16 $2, $2, 2
|
||||
# EB-NEXT: 2001c: 33 02 ff fe addiu $24, $2, -2
|
||||
# EB-NEXT: 20020: 0d ff move $15, $ra
|
||||
# EB-NEXT: 20022: 45 f9 jalrs16 $25
|
||||
# EB-NEXT: 20024: 0f 83 move $gp, $3
|
||||
# EB-NEXT: 20026: 0c 00 nop
|
||||
# EB-NEXT: 20028: 00 00 00 00 nop
|
||||
# EB-NEXT: 2002c: 00 00 00 00 nop
|
||||
|
||||
# EB-NEXT: 20030: 79 00 3f f7 addiupc $2, 65500
|
||||
# EB-NEXT: 20034: ff 22 00 00 lw $25, 0($2)
|
||||
# EB-NEXT: 20038: 45 99 jr16 $25
|
||||
# EB-NEXT: 2003a: 0f 02 move $24, $2
|
||||
|
||||
# EL: Disassembly of section .plt:
|
||||
# EL-NEXT: .plt:
|
||||
# EL-NEXT: 20010: 80 79 fd 3f addiupc $3, 65524
|
||||
# EL-NEXT: 20014: 23 ff 00 00 lw $25, 0($3)
|
||||
# EL-NEXT: 20018: 35 05 subu16 $2, $2, $3
|
||||
# EL-NEXT: 2001a: 25 25 srl16 $2, $2, 2
|
||||
# EL-NEXT: 2001c: 02 33 fe ff addiu $24, $2, -2
|
||||
# EL-NEXT: 20020: ff 0d move $15, $ra
|
||||
# EL-NEXT: 20022: f9 45 jalrs16 $25
|
||||
# EL-NEXT: 20024: 83 0f move $gp, $3
|
||||
# EL-NEXT: 20026: 00 0c nop
|
||||
# EL-NEXT: 20028: 00 00 00 00 nop
|
||||
# EL-NEXT: 2002c: 00 00 00 00 nop
|
||||
|
||||
# EL-NEXT: 20030: 00 79 f7 3f addiupc $2, 65500
|
||||
# EL-NEXT: 20034: 22 ff 00 00 lw $25, 0($2)
|
||||
# EL-NEXT: 20038: 99 45 jr16 $25
|
||||
# EL-NEXT: 2003a: 02 0f move $24, $2
|
||||
|
||||
# EBR6: Disassembly of section .plt:
|
||||
# EBR6-NEXT: .plt:
|
||||
# EBR6-NEXT: 20010: 78 60 3f fd lapc $3, 65524
|
||||
# EBR6-NEXT: 20014: ff 23 00 00 lw $25, 0($3)
|
||||
# EBR6-NEXT: 20018: 05 35 subu16 $2, $2, $3
|
||||
# EBR6-NEXT: 2001a: 25 25 srl16 $2, $2, 2
|
||||
# EBR6-NEXT: 2001c: 33 02 ff fe addiu $24, $2, -2
|
||||
# EBR6-NEXT: 20020: 0d ff move16 $15, $ra
|
||||
# EBR6-NEXT: 20022: 0f 83 move16 $gp, $3
|
||||
# EBR6-NEXT: 20024: 47 2b jalr $25
|
||||
|
||||
# EBR6: 20030: 78 40 3f f7 lapc $2, 65500
|
||||
# EBR6-NEXT: 20034: ff 22 00 00 lw $25, 0($2)
|
||||
# EBR6-NEXT: 20038: 0f 02 move16 $24, $2
|
||||
# EBR6-NEXT: 2003a: 47 23 jrc16 $25
|
||||
|
||||
# ELR6: Disassembly of section .plt:
|
||||
# ELR6-NEXT: .plt:
|
||||
# ELR6-NEXT: 20010: 60 78 fd 3f lapc $3, 65524
|
||||
# ELR6-NEXT: 20014: 23 ff 00 00 lw $25, 0($3)
|
||||
# ELR6-NEXT: 20018: 35 05 subu16 $2, $2, $3
|
||||
# ELR6-NEXT: 2001a: 25 25 srl16 $2, $2, 2
|
||||
# ELR6-NEXT: 2001c: 02 33 fe ff addiu $24, $2, -2
|
||||
# ELR6-NEXT: 20020: ff 0d move16 $15, $ra
|
||||
# ELR6-NEXT: 20022: 83 0f move16 $gp, $3
|
||||
# ELR6-NEXT: 20024: 2b 47 jalr $25
|
||||
|
||||
# ELR6: 20030: 40 78 f7 3f lapc $2, 65500
|
||||
# ELR6-NEXT: 20034: 22 ff 00 00 lw $25, 0($2)
|
||||
# ELR6-NEXT: 20038: 02 0f move16 $24, $2
|
||||
# ELR6-NEXT: 2003a: 23 47 jrc16 $25
|
||||
|
||||
# PLT: Entries [
|
||||
# PLT-NEXT: Entry {
|
||||
# PLT-NEXT: Address: 0x3000C
|
||||
# ^ 0x20030 + 65500
|
||||
# PLT-NEXT: Initial:
|
||||
# PLT-NEXT: Value: 0x0
|
||||
# PLT-NEXT: Type: Function
|
||||
# PLT-NEXT: Section: Undefined
|
||||
# PLT-NEXT: Name: foo
|
||||
# PLT-NEXT: }
|
||||
# PLT-NEXT: ]
|
||||
|
||||
.text
|
||||
.set micromips
|
||||
.global __start
|
||||
__start:
|
||||
jal foo
|
|
@ -0,0 +1,59 @@
|
|||
# Check handling of microMIPS relocations.
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
|
||||
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1eb.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
|
||||
# RUN: -mattr=micromips %s -o %t2eb.o
|
||||
# RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o
|
||||
# RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \
|
||||
# RUN: | FileCheck --check-prefixes=EB,SYM %s
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
|
||||
# RUN: -mattr=micromips %S/Inputs/mips-micro.s -o %t1el.o
|
||||
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
|
||||
# RUN: -mattr=micromips %s -o %t2el.o
|
||||
# RUN: ld.lld -o %tel.exe %t1el.o %t2el.o
|
||||
# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \
|
||||
# RUN: | FileCheck --check-prefixes=EL,SYM %s
|
||||
|
||||
# REQUIRES: mips
|
||||
|
||||
# EB: __start:
|
||||
# EB-NEXT: 20010: 41 a3 00 01 lui $3, 1
|
||||
# EB-NEXT: 20014: 30 63 7f e0 addiu $3, $3, 32736
|
||||
# EB-NEXT: 20018: fc 7c 80 18 lw $3, -32744($gp)
|
||||
# EB-NEXT: 2001c: fc 63 80 18 lw $3, -32744($3)
|
||||
# EB-NEXT: 20020: 8f 70 beqz16 $6, -32
|
||||
# EB-NEXT: 20022: 00 7e 00 00 sll $3, $fp, 0
|
||||
# EB-NEXT: 20026: cf ec b16 -40
|
||||
# EB-NEXT: 20028: 00 00 00 00 nop
|
||||
# EB-NEXT: 2002c: 94 00 ff e8 b -44
|
||||
|
||||
# EL: __start:
|
||||
# EL-NEXT: 20010: a3 41 01 00 lui $3, 1
|
||||
# EL-NEXT: 20014: 63 30 e0 7f addiu $3, $3, 32736
|
||||
# EL-NEXT: 20018: 7c fc 18 80 lw $3, -32744($gp)
|
||||
# EL-NEXT: 2001c: 63 fc 18 80 lw $3, -32744($3)
|
||||
# EL-NEXT: 20020: 70 8f beqz16 $6, -32
|
||||
# EL-NEXT: 20022: 7e 00 00 00 sll $3, $fp, 0
|
||||
# EL-NEXT: 20026: ec cf b16 -40
|
||||
# EL-NEXT: 20028: 00 00 00 00 nop
|
||||
# EL-NEXT: 2002c: 00 94 e8 ff b -44
|
||||
|
||||
# SYM: 00037ff0 *ABS* 00000000 .hidden _gp
|
||||
# SYM: 00020000 g F .text 00000000 foo
|
||||
# SYM: 00020010 .text 00000000 __start
|
||||
|
||||
.text
|
||||
.set micromips
|
||||
.global __start
|
||||
__start:
|
||||
lui $3, %hi(_gp_disp) # R_MICROMIPS_HI16
|
||||
addiu $3, $3, %lo(_gp_disp) # R_MICROMIPS_LO16
|
||||
|
||||
lw $3, %call16(foo)($gp) # R_MICROMIPS_CALL16
|
||||
lw $3, %got(foo)($3) # R_MICROMIPS_GOT16
|
||||
|
||||
beqz16 $6, foo # R_MICROMIPS_PC7_S1
|
||||
b16 foo # R_MICROMIPS_PC10_S1
|
||||
b foo # R_MICROMIPS_PC16_S1
|
Loading…
Reference in New Issue