aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLifang Xia <lifang_xia@linux.alibaba.com>2023-11-29 17:17:22 +0800
committerNelson Chu <nelson@rivosinc.com>2023-12-12 17:04:23 +0800
commitdff565fcca8137954d6ad571ef39f6aec5c0429c (patch)
tree6a14ffd97a42d3ad207503ee84b1ae732b26b3a7
parente61ea34e74f1c29f320906c11300697d15b1a1c0 (diff)
downloadgdb-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.
-rw-r--r--gas/config/tc-riscv.c108
-rw-r--r--gas/config/tc-riscv.h3
-rw-r--r--gas/testsuite/gas/riscv/fixup-local-norelax.d22
-rw-r--r--gas/testsuite/gas/riscv/fixup-local-relax.d41
-rw-r--r--gas/testsuite/gas/riscv/fixup-local.s13
5 files changed, 187 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
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 0000000..3169c69
--- /dev/null
+++ b/gas/testsuite/gas/riscv/fixup-local-norelax.d
@@ -0,0 +1,22 @@
+#as: -march=rv64i -mno-relax
+#source: fixup-local.s
+#objdump: -dr
+
+.*:[ ]+file format .*
+
+Disassembly of section .text:
+
+0+0000 <foo>:
+[ ]+0:[ ]+00000517[ ]+auipc[ ]+a0,0x0
+[ ]+4:[ ]+00850513[ ]+addi[ ]+a0,a0,8 # 8 <foo\+0x8>
+[ ]+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 <foo\+0x20>
+[ ]+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 0000000..3738de1
--- /dev/null
+++ b/gas/testsuite/gas/riscv/fixup-local-relax.d
@@ -0,0 +1,41 @@
+#as: -march=rv64i -mrelax
+#source: fixup-local.s
+#objdump: -dr
+
+.*:[ ]+file format .*
+
+
+Disassembly of section .text:
+
+0+0000 <foo>:
+[ ]+0:[ ]+00000517[ ]+auipc[ ]+a0,0x0
+[ ]+0:[ ]+R_RISCV_PCREL_HI20[ ]+.LL0.*
+[ ]+0:[ ]+R_RISCV_RELAX.*
+[ ]+4:[ ]+00850513[ ]+addi[ ]+a0,a0,8 # 8 <.LL0>
+[ ]+4:[ ]+R_RISCV_PCREL_LO12_I[ ]+.L0.*
+[ ]+4:[ ]+R_RISCV_RELAX.*
+
+0+0008 <.LL0>:
+[ ]+8:[ ]+00000517[ ]+auipc[ ]+a0,0x0
+[ ]+8:[ ]+R_RISCV_PCREL_HI20[ ]+bar.*
+[ ]+8:[ ]+R_RISCV_RELAX.*
+[ ]+c:[ ]+00050513[ ]+mv[ ]+a0,a0
+[ ]+c:[ ]+R_RISCV_PCREL_LO12_I[ ]+.L0.*
+[ ]+c:[ ]+R_RISCV_RELAX.*
+[ ]+10:[ ]+00000517[ ]+auipc[ ]+a0,0x0
+[ ]+10:[ ]+R_RISCV_PCREL_HI20[ ]+foo.*
+[ ]+10:[ ]+R_RISCV_RELAX.*
+[ ]+14:[ ]+00050513[ ]+mv[ ]+a0,a0
+[ ]+14:[ ]+R_RISCV_PCREL_LO12_I[ ]+.L0.*
+[ ]+14:[ ]+R_RISCV_RELAX.*
+
+0+0018 <.LL1>:
+[ ]+18:[ ]+00000517[ ]+auipc[ ]a0,0x0
+[ ]+18:[ ]+R_RISCV_PCREL_HI20[ ]+.LL2.*
+[ ]+18:[ ]R_RISCV_RELAX.*
+[ ]+1c:[ ]+00852503[ ]+lw[ ]+a0,8\(a0\) # 20 <.LL2>
+[ ]+1c:[ ]+R_RISCV_PCREL_LO12_I[ ]+.LL1.*
+[ ]+1c:[ ]+R_RISCV_RELAX.*
+
+0+0020 <.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 0000000..44b4731
--- /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