[MIPS] Generate thunks for microMIPS code

If symbol has the STO_MIPS_MICROMIPS flag and requires a thunk to perform
call PIC from non-PIC functions, we need to generate a thunk with microMIPS
code.

llvm-svn: 314797
This commit is contained in:
Simon Atanasyan 2017-10-03 13:30:02 +00:00
parent 736bf0020f
commit f8db45361e
5 changed files with 133 additions and 7 deletions

View File

@ -240,11 +240,6 @@ static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
static bool isMicroMips() { return Config->MipsEFlags & EF_MIPS_MICROMIPS; }
static bool isMipsR6() {
uint32_t Arch = Config->MipsEFlags & EF_MIPS_ARCH;
return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
}
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
if (isMicroMips()) {

View File

@ -364,6 +364,11 @@ bool elf::isMipsN32Abi(const InputFile *F) {
}
}
bool elf::isMipsR6() {
uint32_t Arch = Config->MipsEFlags & EF_MIPS_ARCH;
return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6;
}
template uint32_t elf::calcMipsEFlags<ELF32LE>();
template uint32_t elf::calcMipsEFlags<ELF32BE>();
template uint32_t elf::calcMipsEFlags<ELF64LE>();

View File

@ -101,6 +101,28 @@ public:
InputSection *getTargetInputSection() const override;
};
// microMIPS R2-R5 LA25 thunk
class MicroMipsThunk final : public Thunk {
public:
MicroMipsThunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 14; }
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
// microMIPS R6 LA25 thunk
class MicroMipsR6Thunk final : public Thunk {
public:
MicroMipsR6Thunk(const SymbolBody &Dest) : Thunk(Dest) {}
uint32_t size() const override { return 12; }
void writeTo(uint8_t *Buf, ThunkSection &IS) const override;
void addSymbols(ThunkSection &IS) override;
InputSection *getTargetInputSection() const override;
};
} // end anonymous namespace
// ARM Target Thunks
@ -235,6 +257,56 @@ InputSection *MipsThunk::getTargetInputSection() const {
return dyn_cast<InputSection>(DR->Section);
}
// Write microMIPS R2-R5 LA25 thunk code
// to call PIC function from the non-PIC one.
void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const {
uint64_t S = Destination.getVA();
write16(Buf, 0x41b9, Config->Endianness); // lui $25, %hi(func)
write16(Buf + 4, 0xd400, Config->Endianness); // j func
write16(Buf + 8, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func)
write16(Buf + 12, 0x0c00, Config->Endianness); // nop
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 &IS) {
ThunkSym =
addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
STT_FUNC, Offset, size(), &IS);
ThunkSym->StOther |= STO_MIPS_MICROMIPS;
}
InputSection *MicroMipsThunk::getTargetInputSection() const {
auto *DR = dyn_cast<DefinedRegular>(&Destination);
return dyn_cast<InputSection>(DR->Section);
}
// Write microMIPS R6 LA25 thunk code
// to call PIC function from the non-PIC one.
void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const {
uint64_t S = Destination.getVA();
uint64_t P = ThunkSym->getVA();
write16(Buf, 0x1320, Config->Endianness); // lui $25, %hi(func)
write16(Buf + 4, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func)
write16(Buf + 8, 0x9400, Config->Endianness); // bc func
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 &IS) {
ThunkSym =
addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()),
STT_FUNC, Offset, size(), &IS);
ThunkSym->StOther |= STO_MIPS_MICROMIPS;
}
InputSection *MicroMipsR6Thunk::getTargetInputSection() const {
auto *DR = dyn_cast<DefinedRegular>(&Destination);
return dyn_cast<InputSection>(DR->Section);
}
Thunk::Thunk(const SymbolBody &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
@ -260,13 +332,19 @@ static Thunk *addThunkArm(uint32_t Reloc, SymbolBody &S) {
fatal("unrecognized relocation type");
}
static Thunk *addThunkMips(SymbolBody &S) { return make<MipsThunk>(S); }
static Thunk *addThunkMips(uint32_t Reloc, SymbolBody &S) {
if ((S.StOther & STO_MIPS_MICROMIPS) && isMipsR6())
return make<MicroMipsR6Thunk>(S);
if (S.StOther & STO_MIPS_MICROMIPS)
return make<MicroMipsThunk>(S);
return make<MipsThunk>(S);
}
Thunk *addThunk(uint32_t RelocType, SymbolBody &S) {
if (Config->EMachine == EM_ARM)
return addThunkArm(RelocType, S);
else if (Config->EMachine == EM_MIPS)
return addThunkMips(S);
return addThunkMips(RelocType, S);
llvm_unreachable("add Thunk only supported for ARM and Mips");
return nullptr;
}

View File

@ -54,6 +54,7 @@ uint8_t getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag,
llvm::StringRef FileName);
bool isMipsN32Abi(const InputFile *F);
bool isMipsR6();
} // namespace elf
} // namespace lld

View File

@ -0,0 +1,47 @@
# Check microMIPS thunk generation.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -mattr=micromips %s -o %t-eb.o
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: -position-independent -mattr=micromips \
# RUN: %S/Inputs/mips-micro.s -o %t-eb-pic.o
# RUN: ld.lld -o %t-eb.exe %t-eb.o %t-eb-pic.o
# RUN: llvm-objdump -d -mattr=+micromips %t-eb.exe \
# RUN: | FileCheck --check-prefix=EB %s
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -mattr=micromips %s -o %t-el.o
# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \
# RUN: -position-independent -mattr=micromips \
# RUN: %S/Inputs/mips-micro.s -o %t-el-pic.o
# RUN: ld.lld -o %t-el.exe %t-el.o %t-el-pic.o
# RUN: llvm-objdump -d -mattr=+micromips %t-el.exe \
# RUN: | FileCheck --check-prefix=EL %s
# REQUIRES: mips
# EB: __start:
# EB-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo>
# EB-NEXT: 20004: 00 00 00 00 nop
# EB: __microLA25Thunk_foo:
# EB-NEXT: 20008: 41 b9 00 02 lui $25, 2
# EB-NEXT: 2000c: d4 01 00 10 j 131104
# EB-NEXT: 20010: 33 39 00 20 addiu $25, $25, 32
# EB-NEXT: 20014: 0c 00 nop
# EL: __start:
# EL-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo>
# EL-NEXT: 20004: 00 00 00 00 nop
# EL: __microLA25Thunk_foo:
# EL-NEXT: 20008: b9 41 02 00 lui $25, 2
# EL-NEXT: 2000c: 01 d4 10 00 j 131104
# EL-NEXT: 20010: 39 33 20 00 addiu $25, $25, 32
# EL-NEXT: 20014: 00 0c nop
.text
.set micromips
.global __start
__start:
jal foo