Re: [PATCH 1/3] RISC-V: Add ZCMT table jump relaxation

"Bigmagic" <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
Hi RISC-V maintainers and contributors,

When testing ZCMT functionality, I found that .option norelax does not actually prevent ZCMT instruction generation. Here's the test case I wrote:


Assembly
.section .text
.globl _start
.type _start, %function
_start:
&nbsp; &nbsp; .option push
&nbsp; &nbsp; .option norelax
&nbsp; &nbsp; .rept 70
&nbsp; &nbsp; call local_func
&nbsp; &nbsp; .endr
&nbsp; &nbsp; .option pop
&nbsp; &nbsp; .rept 70
&nbsp; &nbsp; call global_func
&nbsp; &nbsp; .endr
&nbsp; &nbsp; li a7, 93 &nbsp; &nbsp; &nbsp; &nbsp;# sys_exit
&nbsp; &nbsp; li a0, 0 &nbsp; &nbsp; &nbsp; &nbsp; # exit code
&nbsp; &nbsp; ecall
.type local_func, %function
local_func:
&nbsp; &nbsp; ret
.globl global_func
.type global_func, %function
global_func:
&nbsp; &nbsp; ret
With the following linker script:


Text
ENTRY(_start)
SECTIONS
{
&nbsp; &nbsp; .text 0x80000000 : {
&nbsp; &nbsp; &nbsp; &nbsp; *(.text)
&nbsp; &nbsp; }
&nbsp; &nbsp; .riscv.jvt : {
&nbsp; &nbsp; &nbsp; &nbsp; *(.riscv.jvt)
&nbsp; &nbsp; }
&nbsp; &nbsp; .data : {
&nbsp; &nbsp; &nbsp; &nbsp; *(.data)
&nbsp; &nbsp; }
}
Observation:
The .option push / .option norelax / .option pop block should prevent relaxation for the enclosed call instructions, but ZCMT transformations are still being applied.


Root Cause:
In _bfd_riscv_relax_section(), the ZCMT relaxation path does not check whether the relocation is paired with R_RISCV_RELAX. When .option norelax is used, the assembler does not emit R_RISCV_RELAX relocations alongside the call instructions, but the linker still applies ZCMT relaxation unconditionally.


Proposed Fix:
Skip ZCMT relaxation if the call relocation is not paired with R_RISCV_RELAX:


Diff
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -6067,6 +6067,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; relax_func = _bfd_riscv_jvt_record;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Skip if not paired with R_RISCV_RELAX (i.e. .option norelax). &nbsp;*/
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (i == sec-&gt;reloc_count - 1
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|| ELFNN_R_TYPE ((rel + 1)-&gt;r_info) != R_RISCV_RELAX
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|| rel-&gt;r_offset != (rel + 1)-&gt;r_offset)
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;continue;
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i++;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *again = true;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else if (info-&gt;relax_trip == JVT_PROFILING_DETERMINE)
@@ -6076,6 +6082,12 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; relax_func = _bfd_riscv_jvt_mark;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Skip if not paired with R_RISCV_RELAX (i.e. .option norelax). &nbsp;*/
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (i == sec-&gt;reloc_count - 1
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|| ELFNN_R_TYPE ((rel + 1)-&gt;r_info) != R_RISCV_RELAX
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;|| rel-&gt;r_offset != (rel + 1)-&gt;r_offset)
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;continue;
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;i++;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp;else if (info-&gt;relax_pass == RELAX_PASS_SHORTEN_LUI_CALL_TRREL_PCREL)
Explanation of the check:


i == sec-&gt;reloc_count - 1 — ensure there's a next relocation to check
ELFNN_R_TYPE ((rel + 1)-&gt;r_info) != R_RISCV_RELAX — verify the next relocation is R_RISCV_RELAX
rel-&gt;r_offset != (rel + 1)-&gt;r_offset — ensure the relax relocation is at the same offset (paired)
Testing:
With this patch applied, the test case correctly preserves the call instructions inside the .option norelax block while still applying ZCMT relaxation to the unprotected calls outside the block.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.