Skip to content

Commit b654958

Browse files
committed
[RISCV] Add zero-page relaxation
Signed-off-by: Yang Liu <[email protected]>
1 parent e58f559 commit b654958

File tree

2 files changed

+54
-12
lines changed

2 files changed

+54
-12
lines changed

elf/arch-riscv.cc

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,12 @@ static void write_jtype(u8 *loc, u32 val) {
7575
}
7676

7777
static void write_cbtype(u8 *loc, u32 val) {
78-
u32 mask = 0b1110001110000011;
78+
u32 mask = 0b111'000'111'00000'11;
7979
*(ul16 *)loc = (*(ul16 *)loc & mask) | cbtype(val);
8080
}
8181

8282
static void write_cjtype(u8 *loc, u32 val) {
83-
u32 mask = 0b1110000000000011;
83+
u32 mask = 0b111'00000000000'11;
8484
*(ul16 *)loc = (*(ul16 *)loc & mask) | cjtype(val);
8585
}
8686

@@ -322,16 +322,29 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
322322
*(ul32 *)loc = S + A - P;
323323
}
324324
break;
325-
case R_RISCV_LO12_I:
326-
write_itype(loc, S + A);
327-
break;
328-
case R_RISCV_LO12_S:
329-
write_stype(loc, S + A);
330-
break;
331325
case R_RISCV_HI20: {
326+
assert(delta == 0 || delta == 4);
332327
i64 val = S + A;
333328
overflow_check(val, -(1LL << 31), 1LL << 31);
334-
write_utype(loc, val);
329+
330+
if (delta == 0) {
331+
write_utype(loc, val);
332+
}
333+
break;
334+
}
335+
case R_RISCV_LO12_I:
336+
case R_RISCV_LO12_S: {
337+
i64 val = S + A;
338+
if (rel.r_type == R_RISCV_LO12_I)
339+
write_itype(loc, val);
340+
else
341+
write_stype(loc, val);
342+
343+
// Rewrite `lw t1, 0(t0)` with `lw t1, 0(x0)` if the address is
344+
// x0-relative accessible.
345+
if (sign_extend(val, 11) == val)
346+
*(ul32 *)loc = (*(ul32 *)loc & 0b111111'11111'00000'111'11111'1111111);
347+
335348
break;
336349
}
337350
case R_RISCV_TPREL_HI20:
@@ -732,12 +745,17 @@ static void shrink_section(Context<E> &ctx, InputSection<E> &isec, bool use_rvc)
732745
isec.extra.r_deltas.resize(rels.size() + 1);
733746

734747
i64 delta = 0;
748+
i64 frag_idx = 0;
735749

736750
for (i64 i = 0; i < rels.size(); i++) {
737751
const ElfRel<E> &r = rels[i];
738752
Symbol<E> &sym = *isec.file.symbols[r.r_sym];
739753
isec.extra.r_deltas[i] = delta;
740754

755+
const SectionFragmentRef<E> *frag_ref = nullptr;
756+
if (isec.rel_fragments && isec.rel_fragments[frag_idx].idx == i)
757+
frag_ref = &isec.rel_fragments[frag_idx++];
758+
741759
// Handling R_RISCV_ALIGN is mandatory.
742760
//
743761
// R_RISCV_ALIGN refers NOP instructions. We need to eliminate some
@@ -812,6 +830,31 @@ static void shrink_section(Context<E> &ctx, InputSection<E> &isec, bool use_rvc)
812830
delta += 4;
813831
break;
814832
}
833+
case R_RISCV_HI20: {
834+
// This relocation refers to an LUI instruction containing the high
835+
// 20-bits to be relocated to an absolute symbol address.
836+
// In some cases, LUI can be removed.
837+
838+
// val = S + A
839+
i64 val = frag_ref
840+
? frag_ref->frag->get_addr(ctx) + (u64)frag_ref->addend
841+
: sym.get_addr(ctx) + (u64)r.r_addend;
842+
if (val % 2)
843+
break;
844+
845+
// Here we need to skip undefined & weak symbols as well as symbols in the
846+
// internal object.
847+
if (sym.esym().is_undef_weak() || sym.file == ctx.internal_obj) {
848+
break;
849+
}
850+
851+
// The symbol address located within ±2 KiB, we can remove LUI.
852+
if (sign_extend(val, 11) == val) {
853+
delta += 4;
854+
break;
855+
}
856+
break;
857+
}
815858
}
816859
}
817860

elf/mold.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ class InputSection {
306306
std::span<ElfRel<E>> get_rels(Context<E> &ctx) const;
307307
std::span<FdeRecord<E>> get_fdes() const;
308308
std::string_view get_func_name(Context<E> &ctx, i64 offset);
309+
std::pair<SectionFragment<E> *, i64>
310+
get_fragment(Context<E> &ctx, const ElfRel<E> &rel);
309311
bool is_relr_reloc(Context<E> &ctx, const ElfRel<E> &rel);
310312

311313
void record_undef_error(Context<E> &ctx, const ElfRel<E> &rel);
@@ -355,9 +357,6 @@ class InputSection {
355357

356358
void copy_contents_riscv(Context<E> &ctx, u8 *buf);
357359

358-
std::pair<SectionFragment<E> *, i64>
359-
get_fragment(Context<E> &ctx, const ElfRel<E> &rel);
360-
361360
std::optional<u64> get_tombstone(Symbol<E> &sym);
362361
};
363362

0 commit comments

Comments
 (0)