@@ -4168,6 +4168,31 @@ typedef bool (*relax_func_t) (bfd *, asection *, asection *,
riscv_pcgp_relocs *,
bool undefined_weak);
+/* Check the mapping symbol with architecture string in the R_RISCV_RELAX,
+ to see if rvc is enabled or not. If we don't find any mapping symbols,
+ then just check the elf header flag as usual. */
+
+static int
+_bfd_riscv_enable_rvc (bfd *abfd, Elf_Internal_Rela *rel)
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
+ int rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
+ if (ELFNN_R_SYM (rel->r_info) < symtab_hdr->sh_info)
+ {
+ Elf_Internal_Sym *isym = ((Elf_Internal_Sym *) symtab_hdr->contents
+ + ELFNN_R_SYM (rel->r_info));
+
+ if (isym->st_shndx == SHN_UNDEF
+ || isym->st_shndx >= elf_numsections (abfd))
+ return rvc;
+
+ const char *name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
+ rvc = (name && strncmp (name, "$xrv", 4) == 0
+ && strstr (name, "_c") != NULL) ? 1 : 0;
+ }
+ return rvc;
+}
+
/* Relax AUIPC + JALR into JAL. */
static bool
@@ -4185,7 +4210,8 @@ _bfd_riscv_relax_call (bfd *abfd, asection *sec, asection *sym_sec,
bfd_vma foff = symval - (sec_addr (sec) + rel->r_offset);
bool near_zero = (symval + RISCV_IMM_REACH / 2) < RISCV_IMM_REACH;
bfd_vma auipc, jalr;
- int rd, r_type, len = 4, rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
+ int rd, r_type, len = 4;
+ int rvc = _bfd_riscv_enable_rvc (abfd, rel + 1);
/* If the call crosses section boundaries, an alignment directive could
cause the PC-relative offset to later increase, so we need to add in the
@@ -4279,7 +4305,6 @@ _bfd_riscv_relax_lui (bfd *abfd,
{
bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
bfd_vma gp = riscv_global_pointer_value (link_info);
- int use_rvc = elf_elfheader (abfd)->e_flags & EF_RISCV_RVC;
BFD_ASSERT (rel->r_offset + 4 <= sec->size);
@@ -4347,7 +4372,7 @@ _bfd_riscv_relax_lui (bfd *abfd,
account for this assuming page alignment at worst. In the presence of
RELRO segment the linker aligns it by one page size, therefore sections
after the segment can be moved more than one page. */
-
+ int use_rvc = _bfd_riscv_enable_rvc (abfd, rel + 1);
if (use_rvc
&& ELFNN_R_TYPE (rel->r_info) == R_RISCV_HI20
&& VALID_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (symval))
@@ -511,7 +511,8 @@ make_mapping_symbol (enum riscv_seg_mstate state,
symbol_get_bfdsym (symbol)->flags |= (BSF_NO_FLAGS | BSF_LOCAL);
if (reset_seg_arch_str)
{
- /* Store current $x+arch into tc_segment_info. */
+ /* Store current $x+arch into tc_segment_info, so that we can
+ refer to the correct $x+arch for each R_RISCV_RELAX. */
seg_info (now_seg)->tc_segment_info_data.arch_map_symbol = symbol;
xfree ((void *) buff);
}
@@ -1558,6 +1559,8 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
address_expr, false, reloc_type);
ip->fixp->fx_tcbit = riscv_opts.relax;
+ ip->fixp->tc_fix_data.arch_map_symbol =
+ seg_info (now_seg)->tc_segment_info_data.arch_map_symbol;
}
}
@@ -3731,6 +3734,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
unsigned int subtype;
bfd_byte *buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where);
bool relaxable = false;
+ bool rvc_relaxable = false;
offsetT loc;
segT sub_segment;
@@ -3747,6 +3751,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
if (fixP->fx_addsy == NULL)
fixP->fx_done = true;
relaxable = true;
+ rvc_relaxable = true;
break;
case BFD_RELOC_RISCV_GOT_HI20:
@@ -3940,6 +3945,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
case BFD_RELOC_RISCV_CALL:
case BFD_RELOC_RISCV_CALL_PLT:
relaxable = true;
+ rvc_relaxable = true;
break;
case BFD_RELOC_RISCV_PCREL_HI20:
@@ -3964,9 +3970,14 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
if (relaxable && fixP->fx_tcbit && fixP->fx_addsy != NULL)
{
fixP->fx_next = xmemdup (fixP, sizeof (*fixP), sizeof (*fixP));
- fixP->fx_next->fx_addsy = fixP->fx_next->fx_subsy = NULL;
+ /* Currently only rvc relaxations need $x+arch. */
+ fixP->fx_next->fx_addsy = (need_arch_map_symbol && rvc_relaxable)
+ ? fixP->tc_fix_data.arch_map_symbol : NULL;
+ fixP->fx_next->fx_subsy = NULL;
fixP->fx_next->fx_r_type = BFD_RELOC_RISCV_RELAX;
fixP->fx_next->fx_size = 0;
+ /* Set addend to zero. */
+ fixP->fx_next->fx_offset = 0;
}
}
@@ -152,6 +152,13 @@ struct riscv_frag_type
#define TC_FRAG_INIT(fragp, max_bytes) riscv_init_frag (fragp, max_bytes)
extern void riscv_init_frag (struct frag *, int);
+#define TC_FIX_TYPE struct riscv_fixup_type
+struct riscv_fixup_type
+{
+ symbolS *arch_map_symbol;
+};
+#define TC_INIT_FIX_DATA(FIX) ((FIX)->tc_fix_data.arch_map_symbol = NULL)
+
#define obj_adjust_symtab() riscv_adjust_symtab ()
extern void riscv_adjust_symtab (void);
new file mode 100644
@@ -0,0 +1,23 @@
+#name:
+#source: mapping-relax.s
+#as:
+#readelf: -rW
+
+Relocation section '.rela.text' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_HI20[ ]+[0-9a-f]+[ ]+foo \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+[0-9a-f]+[ ]+\$xrv32i2p1 \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_LO12_I[ ]+[0-9a-f]+[ ]+foo \+ 4
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+[0-9a-f]+[ ]+\$xrv32i2p1 \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_TPREL_HI20[ ]+[0-9a-f]+[ ]+i \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_TPREL_ADD[ ]+[0-9a-f]+[ ]+i \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_TPREL_LO12_I[ ]+[0-9a-f]+[ ]+i \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_PCREL_HI20[ ]+[0-9a-f]+[ ]+foo \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_PCREL_LO12_I[ ]+[0-9a-f]+[ ]+L1 \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_CALL_PLT[ ]+[0-9a-f]+[ ]+foo \+ 0
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_RISCV_RELAX[ ]+[0-9a-f]+[ ]+\$xrv32i2p1_c2p0 \+ 0
new file mode 100644
@@ -0,0 +1,21 @@
+.attribute arch, "rv32i"
+.option relax
+foo:
+.align 2
+lui a0, %hi (foo)
+addi a0, a0, %lo (foo + 4)
+.option arch, +a
+lui a0, %tprel_hi (i)
+add a0, a0, tp, %tprel_add (i)
+lw a1, %tprel_lo (i) (a0)
+.option arch, -a, +c
+L1: auipc a0, %pcrel_hi (foo)
+addi a0, a0, %pcrel_lo (L1)
+call foo
+
+.globl i
+.section .tbss, "awT", @nobits
+.type i, @object
+.size i, 4
+i:
+.zero 4
new file mode 100644
@@ -0,0 +1,16 @@
+#source: c-relax.s
+#ld: --relax
+#objdump: -d -Mno-aliases
+
+.*:[ ]+file format .*
+
+
+Disassembly of section .text:
+
+0+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+lui[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+c\.lui[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+addi[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+c\.j[ ]+.*
+.*:[ ]+[0-9a-f]+[ ]+jal[ ]+.*
new file mode 100644
@@ -0,0 +1,12 @@
+.option relax
+.option arch, -c
+.globl _start
+_start:
+lui a0, %hi (_start)
+addi a0, a0, %lo (_start)
+.option arch, +c
+lui a0, %hi (_start)
+addi a0, a0, %lo (_start)
+call zero, _start
+.option arch, -c
+call zero, _start
@@ -125,6 +125,7 @@ if [istarget "riscv*-*-*"] {
run_dump_test "pcgp-relax-02"
run_dump_test "c-lui"
run_dump_test "c-lui-2"
+ run_dump_test "c-relax"
run_dump_test "disas-jalr"
run_dump_test "pcrel-lo-addend"
run_dump_test "pcrel-lo-addend-2a"