mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-07 08:34:59 +00:00
[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:
parent
736bf0020f
commit
f8db45361e
@ -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()) {
|
||||
|
@ -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>();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
47
lld/test/ELF/mips-micro-thunks.s
Normal file
47
lld/test/ELF/mips-micro-thunks.s
Normal 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
|
Loading…
Reference in New Issue
Block a user