The idea looks good to me. Passed regressions of riscv-gnu-toolchain, so committed with some minor changes and indent fixes. There are some TODOs, but no rush to do for now, 1. The implementation is based on the code from bfd/elfnn-riscv.c. We probably can move the code to bfd/elfxx-riscv.c, so that can reduce duplicate code, just like what we did for the architecture parser. Before that, I renamed functions and variables from *reloc* to *fixup*, to distinguish the code from bfd/elfnn-riscv.c, since they are still a little bit different. 2. Maybe not only pcrel_hi/lo12 relocation with local symbols can be resolved at assembler time. Other pc-relative relocation, like branch, may also be able to perform related optimizations. Thanks Nelson On Wed, Nov 29, 2023 at 5:17 PM wrote: > From: Lifang Xia > > In the scenario of generating .ko files, the kernel does not relax the .ko > files. However, due to the large amount of relax and local relocation > information, this increases the size of the .ko files. > > In this patch, it will finish the fixup of the local relocations while with > "-mno-relax" option. This can reduce the size of the relocation table. > > gas/ > * config/tc-riscv.c (struct riscv_pcrel_hi_reloc): New, reference > from bfd/elfnn-riscv.c. > (riscv_pcrel_hi_reloc_hash): Likewise. > (riscv_pcrel_reloc_hash): Likewise. > (riscv_pcrel_reloc_eq): Likewise. > (riscv_record_pcrel_reolc): Likewise. > (md_begin): Init pcrel_hi hash. > (md_apply_fix) : Do fixup and > record the pcrel_hi relocs, mark as done while with > "-mno-relax". > (md_apply_fix) : > (md_apply_fix) : Do fixup > and mark as done while with "-mno-relax". > (riscv_md_end): New, delete riscv_pcrel_hi_reloc_hash. > * config/tc-riscv.h (md_end): Define md_end with riscv_md_end. > gas/ > * testsuite/gas/riscv/fixup-local*: New tests. > --- > gas/config/tc-riscv.c | 111 +++++++++++++++++- > gas/config/tc-riscv.h | 3 + > gas/testsuite/gas/riscv/fixup-local-norelax.d | 23 ++++ > gas/testsuite/gas/riscv/fixup-local-relax.d | 41 +++++++ > gas/testsuite/gas/riscv/fixup-local.s | 13 ++ > 5 files changed, 190 insertions(+), 1 deletion(-) > create mode 100644 gas/testsuite/gas/riscv/fixup-local-norelax.d > create mode 100644 gas/testsuite/gas/riscv/fixup-local-relax.d > create mode 100644 gas/testsuite/gas/riscv/fixup-local.s > > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c > index 04738d5e00c..332103574fe 100644 > --- a/gas/config/tc-riscv.c > +++ b/gas/config/tc-riscv.c > @@ -1569,6 +1569,58 @@ init_opcode_hash (const struct riscv_opcode > *opcodes, > return hash; > } > > +/* Record all PC-relative high-part relocs we've encountered to help us > + later resolve the corresponding low-part relocs. */ > +struct riscv_pcrel_hi_reloc > +{ > + bfd_vma address; > + symbolS *symbol; > + bfd_vma target; > +}; > + > +/* Handle of the pcrel_hi hash table. */ > +static htab_t riscv_pcrel_hi_reloc_hash; > + > +/* Get the key of a entry from the pcrel_hi hash table. */ > + > +static hashval_t > +riscv_pcrel_reloc_hash (const void *entry) > +{ > + const struct riscv_pcrel_hi_reloc *e = entry; > + return (hashval_t) (e->address); > +} > + > +/* Compare the keys between two entries fo the pcrel_hi hash table. */ > + > +static int > +riscv_pcrel_reloc_eq (const void *entry1, const void *entry2) > +{ > + const struct riscv_pcrel_hi_reloc *e1 = entry1, *e2 = entry2; > + return e1->address == e2->address; > +} > + > +/* Record the pcrel_hi relocs. */ > + > +static bool > +riscv_record_pcrel_reolc (htab_t p, bfd_vma address, symbolS *symbol, > + bfd_vma target) > +{ > + struct riscv_pcrel_hi_reloc entry = { address, symbol, target }; > + struct riscv_pcrel_hi_reloc **slot > + = (struct riscv_pcrel_hi_reloc **)htab_find_slot (p, &entry, > INSERT); > + if (slot == NULL) > + return false; > + > + *slot = (struct riscv_pcrel_hi_reloc *)xmalloc ( > + sizeof (struct riscv_pcrel_hi_reloc)); > + if (*slot != NULL) > + { > + **slot = entry; > + return true; > + } > + return false; > +} > + > /* This function is called once, at assembler startup time. It should > set up > all the tables, etc. that the MD part of the assembler will need. */ > > @@ -1605,6 +1657,11 @@ md_begin (void) > opcode_names_hash = str_htab_create (); > init_opcode_names_hash (); > > + /* Create pcrel_hi hash table to resolve the relocation while with > + -mno-relax. */ > + riscv_pcrel_hi_reloc_hash > + = htab_create (1024, riscv_pcrel_reloc_hash, riscv_pcrel_reloc_eq, > free); > + > /* Set the default alignment for the text section. */ > record_alignment (text_section, riscv_opts.rvc ? 1 : 2); > } > @@ -4213,9 +4270,52 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg > ATTRIBUTE_UNUSED) > break; > > case BFD_RELOC_RISCV_PCREL_HI20: > + /* record the pcrel_hi relocs of the local symbols. And evaluate > the hi20 > + of the lcoal symbols. Fill in a tentative value to improve > objdump > + readability for -mrelax, and set fx_done for -mno-relax. */ > + if (S_IS_LOCAL (fixP->fx_addsy) && fixP->fx_addsy > + && S_GET_SEGMENT (fixP->fx_addsy) == seg) > + { > + bfd_vma target = S_GET_VALUE (fixP->fx_addsy) + *valP; > + bfd_vma value = target - md_pcrel_from (fixP); > + > + /* Record PCREL_HI20. */ > + if (!riscv_record_pcrel_reolc (riscv_pcrel_hi_reloc_hash, > + md_pcrel_from (fixP), > fixP->fx_addsy, > + target)) > + { > + as_warn ("too many pcrel_hi"); > + } > + > + bfd_putl32 (bfd_getl32 (buf) > + | ENCODE_UTYPE_IMM (RISCV_CONST_HIGH_PART > (value)), > + buf); > + if (!riscv_opts.relax) > + fixP->fx_done = 1; > + } > + relaxable = riscv_opts.relax; > + break; > case BFD_RELOC_RISCV_PCREL_LO12_S: > case BFD_RELOC_RISCV_PCREL_LO12_I: > - relaxable = riscv_opts.relax; > + { > + /* Resolve the low12 of the local symboles with the pcrel_hi > relocs. > + Fill in a tentative value to improve objdump readability for > + -mrelax, and set fx_done for -mno-relax. */ > + bfd_vma location_pcrel_hi = S_GET_VALUE (fixP->fx_addsy) + *valP; > + struct riscv_pcrel_hi_reloc search = { location_pcrel_hi, 0, 0 }; > + struct riscv_pcrel_hi_reloc *entry > + = htab_find (riscv_pcrel_hi_reloc_hash, &search); > + if (entry && entry->symbol && S_IS_LOCAL (entry->symbol) > + && S_GET_SEGMENT (entry->symbol) == seg) > + { > + bfd_vma target = entry->target; > + bfd_vma value = target - entry->address; > + bfd_putl32 (bfd_getl32 (buf) | ENCODE_ITYPE_IMM (value), buf); > + if (!riscv_opts.relax) > + fixP->fx_done = 1; > + } > + relaxable = riscv_opts.relax; > + } > break; > > case BFD_RELOC_RISCV_ALIGN: > @@ -4980,6 +5080,15 @@ riscv_md_finish (void) > riscv_set_public_attributes (); > if (riscv_opts.relax) > bfd_map_over_sections (stdoutput, riscv_insert_uleb128_fixes, NULL); > + > +} > + > +/* Called just before the assembler exits. */ > + > +void > +riscv_md_end (void) > +{ > + htab_delete (riscv_pcrel_hi_reloc_hash); > } > > /* Adjust the symbol table. */ > diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h > index 0c70c7d4739..9d2f05a4241 100644 > --- a/gas/config/tc-riscv.h > +++ b/gas/config/tc-riscv.h > @@ -80,6 +80,9 @@ extern int riscv_parse_long_option (const char *); > extern void riscv_pre_output_hook (void); > #define GAS_SORT_RELOCS 1 > > +#define md_end riscv_md_end > +extern void riscv_md_end (void); > + > /* Let the linker resolve all the relocs due to relaxation. */ > #define tc_fix_adjustable(fixp) 0 > #define md_allow_local_subtract(l,r,s) 0 > diff --git a/gas/testsuite/gas/riscv/fixup-local-norelax.d > b/gas/testsuite/gas/riscv/fixup-local-norelax.d > new file mode 100644 > index 00000000000..22132a32f91 > --- /dev/null > +++ b/gas/testsuite/gas/riscv/fixup-local-norelax.d > @@ -0,0 +1,23 @@ > +#as: -march=rv64i -mno-relax > +#source: fixup-local.s > +#objdump: -dr > + > +tmpdir/fixup-local.o: file format elf64-littleriscv > + > + > +Disassembly of section .text: > + > +0+0000 : > +[ ]+0:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+4:[ ]+00850513[ ]+addi a0,a0,8 # 8 > +[ ]+8:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+8: R_RISCV_PCREL_HI20 bar > +[ ]+c:[ ]+00050513[ ]+mv a0,a0 > +[ ]+c: R_RISCV_PCREL_LO12_I .L0 > +[ ]+10:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+10: R_RISCV_PCREL_HI20 foo > +[ ]+14:[ ]+00050513[ ]+mv a0,a0 > +[ ]+14: R_RISCV_PCREL_LO12_I .L0 > +[ ]+18:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+1c:[ ]+00852503[ ]+lw a0,8\(a0\) # 20 > +[ ]+20:[ ]+00008067[ ]+ret > diff --git a/gas/testsuite/gas/riscv/fixup-local-relax.d > b/gas/testsuite/gas/riscv/fixup-local-relax.d > new file mode 100644 > index 00000000000..49c475c5dcb > --- /dev/null > +++ b/gas/testsuite/gas/riscv/fixup-local-relax.d > @@ -0,0 +1,41 @@ > +#as: -march=rv64i > +#source: fixup-local.s > +#objdump: -dr > + > +tmpdir/fixup-local.o: file format elf64-littleriscv > + > + > +Disassembly of section .text: > + > +0+0000 : > +[ ]+0:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+0: R_RISCV_PCREL_HI20 .LL0 > +[ ]+0: R_RISCV_RELAX \*ABS\* > +[ ]+4:[ ]+00850513[ ]+addi a0,a0,8 # 8 <.LL0> > +[ ]+4: R_RISCV_PCREL_LO12_I .L0 > +[ ]+4: R_RISCV_RELAX \*ABS\* > + > +0000000000000008 <.LL0>: > +[ ]+8:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+8: R_RISCV_PCREL_HI20 bar > +[ ]+8: R_RISCV_RELAX \*ABS\* > +[ ]+c:[ ]+00050513[ ]+mv a0,a0 > +[ ]+c: R_RISCV_PCREL_LO12_I .L0 > +[ ]+c: R_RISCV_RELAX \*ABS\* > +[ ]+10:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+10: R_RISCV_PCREL_HI20 foo > +[ ]+10: R_RISCV_RELAX \*ABS\* > +[ ]+14:[ ]+00050513[ ]+mv a0,a0 > +[ ]+14: R_RISCV_PCREL_LO12_I .L0 > +[ ]+14: R_RISCV_RELAX \*ABS\* > + > +0000000000000018 <.LL1>: > +[ ]+18:[ ]+00000517[ ]+auipc a0,0x0 > +[ ]+18: R_RISCV_PCREL_HI20 .LL2 > +[ ]+18: R_RISCV_RELAX \*ABS\* > +[ ]+1c:[ ]+00852503[ ]+lw a0,8\(a0\) # 20 <.LL2> > +[ ]+1c: R_RISCV_PCREL_LO12_I .LL1 > +[ ]+1c: R_RISCV_RELAX \*ABS\* > + > +0000000000000020 <.LL2>: > +[ ]+20:[ ]+00008067[ ]+ret > diff --git a/gas/testsuite/gas/riscv/fixup-local.s > b/gas/testsuite/gas/riscv/fixup-local.s > new file mode 100644 > index 00000000000..44b47311235 > --- /dev/null > +++ b/gas/testsuite/gas/riscv/fixup-local.s > @@ -0,0 +1,13 @@ > +.global foo > +.global bar > +foo: > + la a0, .LL0 > +.LL0: > + la a0, bar > + la a0, foo > +.LL1: > + auipc a0, %pcrel_hi(.LL2) > + lw a0, %pcrel_lo(.LL1)(a0) > + > +.LL2: > + ret > -- > 2.39.2 (Apple Git-143) > >