diff options
-rw-r--r-- | gas/config/tc-riscv.c | 108 | ||||
-rw-r--r-- | gas/config/tc-riscv.h | 3 | ||||
-rw-r--r-- | gas/testsuite/gas/riscv/fixup-local-norelax.d | 22 | ||||
-rw-r--r-- | gas/testsuite/gas/riscv/fixup-local-relax.d | 41 | ||||
-rw-r--r-- | gas/testsuite/gas/riscv/fixup-local.s | 13 |
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 |