diff options
author | Lifang Xia <lifang_xia@linux.alibaba.com> | 2023-11-29 17:17:22 +0800 |
---|---|---|
committer | Nelson Chu <nelson@rivosinc.com> | 2023-12-12 17:04:23 +0800 |
commit | dff565fcca8137954d6ad571ef39f6aec5c0429c (patch) | |
tree | 6a14ffd97a42d3ad207503ee84b1ae732b26b3a7 /gas/config | |
parent | e61ea34e74f1c29f320906c11300697d15b1a1c0 (diff) | |
download | gdb-dff565fcca8137954d6ad571ef39f6aec5c0429c.zip gdb-dff565fcca8137954d6ad571ef39f6aec5c0429c.tar.gz gdb-dff565fcca8137954d6ad571ef39f6aec5c0429c.tar.bz2 |
RISC-V: Resolve PCREL_HI20/LO12_I/S fixups with local symbols while `-mno-relax'
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.
The implemntation 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.
Besides, 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.
Passed the gcc/binutils regressions of riscv-gnu-toolchain.
gas/
* config/tc-riscv.c (riscv_pcrel_hi_reloc): New structure. Record all
PC-relative high-part relocation that we have encountered to help us
resolve the corresponding low-part relocation later.
(riscv_pcrel_hi_fixup_hash): The hash table to record pcrel_hi fixups.
(riscv_pcrel_fixup_hash): New function. Likewise.
(riscv_pcrel_fixup_eq): Likewise.
(riscv_record_pcrel_fixup): Likewise.
(md_begin): Init pcrel_hi hash table.
(md_apply_fix): For PCREL_HI20 relocation, do fixup and record
the pcrel_hi relocs, mark as done while with `-mno-relax'. For
PCREL_LO12_I/S relocation, do fixup and mark as done while with
`-mno-relax'.
(riscv_md_end): New function. Free pcrel_hi hash table.
* config/tc-riscv.h (md_end): Define md_end with riscv_md_end.
gas/
* testsuite/gas/riscv/fixup-local*: New tests.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-riscv.c | 108 | ||||
-rw-r--r-- | gas/config/tc-riscv.h | 3 |
2 files changed, 111 insertions, 0 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index d3b6543..10f1ac7 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -1587,6 +1587,55 @@ init_opcode_hash (const struct riscv_opcode *opcodes, return hash; } +/* Record all PC-relative high-part relocation that we have encountered to + help us resolve the corresponding low-part relocation later. */ +typedef struct +{ + bfd_vma address; + symbolS *symbol; + bfd_vma target; +} riscv_pcrel_hi_fixup; + +/* Handle of the pcrel_hi hash table. */ +static htab_t riscv_pcrel_hi_fixup_hash; + +/* Get the key of a entry from the pcrel_hi hash table. */ + +static hashval_t +riscv_pcrel_fixup_hash (const void *entry) +{ + const riscv_pcrel_hi_fixup *e = entry; + return (hashval_t) (e->address); +} + +/* Compare the keys between two entries fo the pcrel_hi hash table. */ + +static int +riscv_pcrel_fixup_eq (const void *entry1, const void *entry2) +{ + const riscv_pcrel_hi_fixup *e1 = entry1, *e2 = entry2; + return e1->address == e2->address; +} + +/* Record the pcrel_hi relocation. */ + +static bool +riscv_record_pcrel_fixup (htab_t p, bfd_vma address, symbolS *symbol, + bfd_vma target) +{ + riscv_pcrel_hi_fixup entry = {address, symbol, target}; + riscv_pcrel_hi_fixup **slot = + (riscv_pcrel_hi_fixup **) htab_find_slot (p, &entry, INSERT); + if (slot == NULL) + return false; + + *slot = (riscv_pcrel_hi_fixup *) xmalloc (sizeof (riscv_pcrel_hi_fixup)); + if (*slot == NULL) + return false; + **slot = entry; + return true; +} + /* 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. */ @@ -1623,6 +1672,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_fixup_hash = htab_create (1024, riscv_pcrel_fixup_hash, + riscv_pcrel_fixup_eq, free); + /* Set the default alignment for the text section. */ record_alignment (text_section, riscv_opts.rvc ? 1 : 2); } @@ -4281,8 +4335,54 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) break; case BFD_RELOC_RISCV_PCREL_HI20: + /* Record and evaluate the pcrel_hi relocation with local symbol. + Fill in a tentative value to improve objdump readability for -mrelax, + and set fx_done for -mno-relax. */ + if (fixP->fx_addsy + && S_IS_LOCAL (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_fixup (riscv_pcrel_hi_fixup_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 = true; + break; + case BFD_RELOC_RISCV_PCREL_LO12_S: case BFD_RELOC_RISCV_PCREL_LO12_I: + /* Resolve the pcrel_lo relocation with local symbol. + 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; + riscv_pcrel_hi_fixup search = {location_pcrel_hi, 0, 0}; + riscv_pcrel_hi_fixup *entry = htab_find (riscv_pcrel_hi_fixup_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); + /* Relaxations should never be enabled by `.option relax'. */ + if (!riscv_opts.relax) + fixP->fx_done = 1; + } + } relaxable = true; break; @@ -5050,6 +5150,14 @@ riscv_md_finish (void) 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_fixup_hash); +} + /* Adjust the symbol table. */ void diff --git a/gas/config/tc-riscv.h b/gas/config/tc-riscv.h index 0c70c7d..9d2f05a 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 |