Skip to content

Commit

Permalink
Remove range extension support from LoongArch
Browse files Browse the repository at this point in the history
It looks like emitting PCADDU18I + JIRL instead of just BL for function
calls is a way to go, so we don't want to bother to maintain range
extension thunks for the psABI.

Since no other linkers support range extension thunks for LoongArch other
than us, removing the support should be OK.
  • Loading branch information
rui314 committed Jul 31, 2024
1 parent 4e6b4c4 commit 47c092a
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 48 deletions.
35 changes: 4 additions & 31 deletions elf/arch-loongarch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// Speaking of the ISA, all instructions are 4 byte long and aligned to 4
// byte boundaries in LoongArch. It has 32 general-purpose registers.
// Among these, $t0 - $t8 (aliases for $r12 - $r20) are temporary
// registers that we can use in our PLT and range extension thunks.
// registers that we can use in our PLT.
//
// Just like RISC-V, LoongArch supports section-shrinking relaxations.
// That is, it allows linkers to rewrite certain instruction sequences to
Expand Down Expand Up @@ -320,13 +320,10 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
check_branch(S + A - P, -(1 << 22), 1 << 22);
write_d5k16(loc, (S + A - P) >> 2);
break;
case R_LARCH_B26: {
i64 val = S + A - P;
if (val < -(1 << 27) || (1 << 27) <= val)
val = get_thunk_addr(i) + A - P;
write_d10k16(loc, val >> 2);
case R_LARCH_B26:
check_branch(S + A - P, -(1 << 27), 1 << 27);
write_d10k16(loc, (S + A - P) >> 2);
break;
}
case R_LARCH_ABS_LO12:
write_k12(loc, S + A);
break;
Expand Down Expand Up @@ -826,30 +823,6 @@ void shrink_section(Context<E> &ctx, InputSection<E> &isec, bool use_rvc) {
isec.sh_size -= delta;
}

template <>
void Thunk<E>::copy_buf(Context<E> &ctx) {
constexpr ul32 insn[] = {
0x1e00'000c, // pcaddu18i $t0, 0
0x4c00'0180, // jirl $zero, $t0, 0
};

static_assert(E::thunk_size == sizeof(insn));

u8 *buf = ctx.buf + output_section.shdr.sh_offset + offset;
u64 P = output_section.shdr.sh_addr + offset;

for (Symbol<E> *sym : symbols) {
u64 S = sym->get_addr(ctx);

memcpy(buf, insn, sizeof(insn));
write_j20(buf, (S - P + 0x20000) >> 18);
write_k16(buf + 4, (S - P) >> 2);

buf += sizeof(insn);
P += sizeof(insn);
}
}

} // namespace mold::elf

#endif
4 changes: 0 additions & 4 deletions elf/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -2271,8 +2271,6 @@ struct LOONGARCH64 {
static constexpr u32 plt_hdr_size = 32;
static constexpr u32 plt_size = 16;
static constexpr u32 pltgot_size = 16;
static constexpr u32 thunk_hdr_size = 0;
static constexpr u32 thunk_size = 8;
static constexpr u8 filler[] = { 0x00, 0x00, 0x2a, 0x00 }; // break 0

static constexpr u32 R_COPY = R_LARCH_COPY;
Expand All @@ -2297,8 +2295,6 @@ struct LOONGARCH32 {
static constexpr u32 plt_hdr_size = 32;
static constexpr u32 plt_size = 16;
static constexpr u32 pltgot_size = 16;
static constexpr u32 thunk_hdr_size = 0;
static constexpr u32 thunk_size = 8;
static constexpr u8 filler[] = { 0x00, 0x00, 0x2a, 0x00 }; // break 0

static constexpr u32 R_COPY = R_LARCH_COPY;
Expand Down
10 changes: 2 additions & 8 deletions elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,22 +232,16 @@ struct FdeRecord {
template <typename E>
struct InputSectionExtras {};

template <typename E> requires (needs_thunk<E> && !is_loongarch<E>)
template <needs_thunk E>
struct InputSectionExtras<E> {
std::vector<ThunkRef> thunk_refs;
};

template <is_riscv E>
template <typename E> requires is_riscv<E> || is_loongarch<E>
struct InputSectionExtras<E> {
std::vector<i32> r_deltas;
};

template <is_loongarch E>
struct InputSectionExtras<E> {
std::vector<ThunkRef> thunk_refs;
std::vector<i32> r_deltas;
};

// InputSection represents a section in an input object file.
template <typename E>
class __attribute__((aligned(4))) InputSection {
Expand Down
7 changes: 2 additions & 5 deletions elf/thunks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
// we don't need to try too hard to reduce thunk size to the absolute
// minimum.

#if MOLD_ARM32 || MOLD_ARM64 || MOLD_PPC32 || MOLD_PPC64V1 || MOLD_PPC64V2 || \
MOLD_LOONGARCH64 || MOLD_LOONGARCH32
#if MOLD_ARM32 || MOLD_ARM64 || MOLD_PPC32 || MOLD_PPC64V1 || MOLD_PPC64V2

#include "mold.h"

Expand All @@ -39,9 +38,7 @@ static consteval i64 max_distance() {
// and therefore the least two bits are always zero. So the branch
// operand is effectively 28 bits long. That means the branch range is
// [-2^27, 2^27) or PC ± 128 MiB.
//
// LoongArch's BR instruction also takes a 26 bit immediate.
if (is_arm64<E> || is_loongarch<E>)
if (is_arm64<E>)
return 1 << 27;

// ARM32's Thumb branch has 24 bits immediate, and the instructions are
Expand Down
5 changes: 5 additions & 0 deletions test/elf/range-extension-thunk.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
# It looks like SPARC's runtime can't handle PLT if it's too far from GOT.
[ $MACHINE = sparc64 ] && skip

# Current LoongArch compilers emit BL for function calls, but I believe
# they'll emit PCADDU18I + JIRL (which is addressable PC ± 128 GiB) in the
# future.
[[ $MACHINE = loongarch* ]] && skip

# qemu aborts with the "Unknown exception 0x5" error, although this
# test passes on a real POWER10 machine.
on_qemu && [ "$CPU" = power10 ] && skip
Expand Down

0 comments on commit 47c092a

Please sign in to comment.