@@ -75,12 +75,12 @@ static void write_jtype(u8 *loc, u32 val) {
75
75
}
76
76
77
77
static void write_cbtype (u8 *loc, u32 val) {
78
- u32 mask = 0b1110001110000011 ;
78
+ u32 mask = 0b111'000'111'00000'11 ;
79
79
*(ul16 *)loc = (*(ul16 *)loc & mask) | cbtype (val);
80
80
}
81
81
82
82
static void write_cjtype (u8 *loc, u32 val) {
83
- u32 mask = 0b1110000000000011 ;
83
+ u32 mask = 0b111'00000000000'11 ;
84
84
*(ul16 *)loc = (*(ul16 *)loc & mask) | cjtype (val);
85
85
}
86
86
@@ -322,16 +322,29 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
322
322
*(ul32 *)loc = S + A - P;
323
323
}
324
324
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 ;
331
325
case R_RISCV_HI20: {
326
+ assert (delta == 0 || delta == 4 );
332
327
i64 val = S + A;
333
328
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
+
335
348
break ;
336
349
}
337
350
case R_RISCV_TPREL_HI20:
@@ -732,12 +745,17 @@ static void shrink_section(Context<E> &ctx, InputSection<E> &isec, bool use_rvc)
732
745
isec.extra .r_deltas .resize (rels.size () + 1 );
733
746
734
747
i64 delta = 0 ;
748
+ i64 frag_idx = 0 ;
735
749
736
750
for (i64 i = 0 ; i < rels.size (); i++) {
737
751
const ElfRel<E> &r = rels[i];
738
752
Symbol<E> &sym = *isec.file .symbols [r.r_sym ];
739
753
isec.extra .r_deltas [i] = delta;
740
754
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
+
741
759
// Handling R_RISCV_ALIGN is mandatory.
742
760
//
743
761
// 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)
812
830
delta += 4 ;
813
831
break ;
814
832
}
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
+ }
815
858
}
816
859
}
817
860
0 commit comments