aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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