public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] RISC-V: Clarify the behaviors of SET/ADD/SUB relocations.
@ 2023-10-19  9:17 Nelson Chu
  2023-10-20 17:58 ` Charlie Jenkins
  0 siblings, 1 reply; 3+ messages in thread
From: Nelson Chu @ 2023-10-19  9:17 UTC (permalink / raw)
  To: binutils, kito.cheng, palmer, charlie; +Cc: nelson

We are used to generate these kinds of relocations by data directives.
Considering the following example,
.word (A + 3) - (B + 2)
The GAS will generate a pair of ADD/SUB for this,
R_RISCV_ADD, A + 1
R_RISCV_SUB, 0

The addend of R_RISCV_SUB will always be zero, and the summary of the
constants will be stored in the addend of R_RISCV_ADD/SET.  Therefore,
we can always add the addend of these data relocations when doing relocations.

But unfortunately, I had heard that if we are using .reloc to generate
the data relocations will make the relocations failed.  Refer to this,
.reloc offset, R_RISCV_ADD32, A + 3
.reloc offset, R_RISCV_SUB32, B + 2
.word 0
Then we can get the relocations as follows,
R_RISCV_ADD, A + 3
R_RISCV_SUB, B + 2
Then...  Current LD does the relocation, B - A + 3 + 2, which is wrong
obviously...

So first of all, this patch fixes the wrong relocation behavior of
R_RISCV_SUB* relocations.

Afterwards, considering the uleb128 direcitve, we will get a pair of
SET_ULEB128/SUB_ULEB128 relocations for it for now,
.uleb128 (A + 3) - (B + 2)
R_RISCV_SET_ULEB128, A + 1
R_RISCV_SUB_ULEB128, B + 1

Which looks also wrong obviously, the summary of the constants should only
be stored into the addend of SET_ULEB128, and the addend of SUB_ULEB128 should
be zero like other SUB relocations.  But the current LD will still get the right
relocation values since we only add the addend of SUB_ULEB128 by accident...
Anyway, this patch also fixes the behaviors above, to make sure that no matter
using .uleb128 or .reloc directives, we should always get the right values.

bfd/
	* elfnn-riscv.c (perform_relocation):  Clarify that SUB relocations
	should substract the addend, rather than add.
	(riscv_elf_relocate_section): Since SET_ULEB128 won't go into
	perform_relocation, we should add it's addend here in advance.
gas/
	* config/tc-riscv.c (riscv_insert_uleb128_fixes): Set the addend of
	SUB_ULEB128 to zero since it should already be added into the addend
	of SET_ULEB128.
---
 bfd/elfnn-riscv.c     | 22 ++++++++++++++++------
 gas/config/tc-riscv.c |  1 +
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 3edf68e3e30..00e5c69dbec 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -1737,7 +1737,20 @@ perform_relocation (const reloc_howto_type *howto,
 {
   if (howto->pc_relative)
     value -= sec_addr (input_section) + rel->r_offset;
-  value += rel->r_addend;
+
+  switch (ELFNN_R_TYPE (rel->r_info))
+    {
+    case R_RISCV_SUB6:
+    case R_RISCV_SUB8:
+    case R_RISCV_SUB16:
+    case R_RISCV_SUB32:
+    case R_RISCV_SUB64:
+    case R_RISCV_SUB_ULEB128:
+      value -= rel->r_addend;
+      break;
+    default:
+      value += rel->r_addend;
+    }
 
   switch (ELFNN_R_TYPE (rel->r_info))
     {
@@ -1818,10 +1831,7 @@ perform_relocation (const reloc_howto_type *howto,
 	value = ENCODE_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value));
       break;
 
-    /* SUB_ULEB128 must be applied after SET_ULEB128, so we only write the
-       value back for SUB_ULEB128 should be enough.  */
-    case R_RISCV_SET_ULEB128:
-      break;
+    /* R_RISCV_SET_ULEB128 won't go into here.  */
     case R_RISCV_SUB_ULEB128:
       {
 	unsigned int len = 0;
@@ -2523,7 +2533,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
 	  if (uleb128_set_rel != NULL
 	      && uleb128_set_rel->r_offset == rel->r_offset)
 	    {
-	      relocation = uleb128_set_vma - relocation;
+	      relocation = uleb128_set_vma - relocation + uleb128_set_rel->r_addend;
 	      uleb128_set_vma = 0;
 	      uleb128_set_rel = NULL;
 	    }
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 5759d3a5fc4..09f2ea17c17 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -4999,6 +4999,7 @@ riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
       fix_new_exp (fragP, fragP->fr_fix, 0,
 		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
       exp_dup->X_add_symbol = exp->X_op_symbol;
+      exp_dup->X_add_number = 0; /* Set addend of SUB_ULEB128 to zero.  */
       fix_new_exp (fragP, fragP->fr_fix, 0,
 		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
       free ((void *) exp_dup);
-- 
2.39.3 (Apple Git-145)


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] RISC-V: Clarify the behaviors of SET/ADD/SUB relocations.
  2023-10-19  9:17 [PATCH] RISC-V: Clarify the behaviors of SET/ADD/SUB relocations Nelson Chu
@ 2023-10-20 17:58 ` Charlie Jenkins
  2023-10-27  0:37   ` Nelson Chu
  0 siblings, 1 reply; 3+ messages in thread
From: Charlie Jenkins @ 2023-10-20 17:58 UTC (permalink / raw)
  To: Nelson Chu; +Cc: binutils, kito.cheng, palmer

On Thu, Oct 19, 2023 at 05:17:26PM +0800, Nelson Chu wrote:
> We are used to generate these kinds of relocations by data directives.
> Considering the following example,
> .word (A + 3) - (B + 2)
> The GAS will generate a pair of ADD/SUB for this,
> R_RISCV_ADD, A + 1
> R_RISCV_SUB, 0
> 
> The addend of R_RISCV_SUB will always be zero, and the summary of the
> constants will be stored in the addend of R_RISCV_ADD/SET.  Therefore,
> we can always add the addend of these data relocations when doing relocations.
> 
> But unfortunately, I had heard that if we are using .reloc to generate
> the data relocations will make the relocations failed.  Refer to this,
> .reloc offset, R_RISCV_ADD32, A + 3
> .reloc offset, R_RISCV_SUB32, B + 2
> .word 0
> Then we can get the relocations as follows,
> R_RISCV_ADD, A + 3
> R_RISCV_SUB, B + 2
> Then...  Current LD does the relocation, B - A + 3 + 2, which is wrong
> obviously...
> 
> So first of all, this patch fixes the wrong relocation behavior of
> R_RISCV_SUB* relocations.
> 
> Afterwards, considering the uleb128 direcitve, we will get a pair of
> SET_ULEB128/SUB_ULEB128 relocations for it for now,
> .uleb128 (A + 3) - (B + 2)
> R_RISCV_SET_ULEB128, A + 1
> R_RISCV_SUB_ULEB128, B + 1
> 
> Which looks also wrong obviously, the summary of the constants should only
> be stored into the addend of SET_ULEB128, and the addend of SUB_ULEB128 should
> be zero like other SUB relocations.  But the current LD will still get the right
> relocation values since we only add the addend of SUB_ULEB128 by accident...
> Anyway, this patch also fixes the behaviors above, to make sure that no matter
> using .uleb128 or .reloc directives, we should always get the right values.
> 
> bfd/
> 	* elfnn-riscv.c (perform_relocation):  Clarify that SUB relocations
> 	should substract the addend, rather than add.
> 	(riscv_elf_relocate_section): Since SET_ULEB128 won't go into
> 	perform_relocation, we should add it's addend here in advance.
> gas/
> 	* config/tc-riscv.c (riscv_insert_uleb128_fixes): Set the addend of
> 	SUB_ULEB128 to zero since it should already be added into the addend
> 	of SET_ULEB128.
> ---
>  bfd/elfnn-riscv.c     | 22 ++++++++++++++++------
>  gas/config/tc-riscv.c |  1 +
>  2 files changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> index 3edf68e3e30..00e5c69dbec 100644
> --- a/bfd/elfnn-riscv.c
> +++ b/bfd/elfnn-riscv.c
> @@ -1737,7 +1737,20 @@ perform_relocation (const reloc_howto_type *howto,
>  {
>    if (howto->pc_relative)
>      value -= sec_addr (input_section) + rel->r_offset;
> -  value += rel->r_addend;
> +
> +  switch (ELFNN_R_TYPE (rel->r_info))
> +    {
> +    case R_RISCV_SUB6:
> +    case R_RISCV_SUB8:
> +    case R_RISCV_SUB16:
> +    case R_RISCV_SUB32:
> +    case R_RISCV_SUB64:
> +    case R_RISCV_SUB_ULEB128:
> +      value -= rel->r_addend;
> +      break;
> +    default:
> +      value += rel->r_addend;
> +    }
>  
>    switch (ELFNN_R_TYPE (rel->r_info))
>      {
> @@ -1818,10 +1831,7 @@ perform_relocation (const reloc_howto_type *howto,
>  	value = ENCODE_CITYPE_LUI_IMM (RISCV_CONST_HIGH_PART (value));
>        break;
>  
> -    /* SUB_ULEB128 must be applied after SET_ULEB128, so we only write the
> -       value back for SUB_ULEB128 should be enough.  */
> -    case R_RISCV_SET_ULEB128:
> -      break;
> +    /* R_RISCV_SET_ULEB128 won't go into here.  */
>      case R_RISCV_SUB_ULEB128:
>        {
>  	unsigned int len = 0;
> @@ -2523,7 +2533,7 @@ riscv_elf_relocate_section (bfd *output_bfd,
>  	  if (uleb128_set_rel != NULL
>  	      && uleb128_set_rel->r_offset == rel->r_offset)
>  	    {
> -	      relocation = uleb128_set_vma - relocation;
> +	      relocation = uleb128_set_vma - relocation + uleb128_set_rel->r_addend;
>  	      uleb128_set_vma = 0;
>  	      uleb128_set_rel = NULL;
>  	    }
> diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> index 5759d3a5fc4..09f2ea17c17 100644
> --- a/gas/config/tc-riscv.c
> +++ b/gas/config/tc-riscv.c
> @@ -4999,6 +4999,7 @@ riscv_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED,
>        fix_new_exp (fragP, fragP->fr_fix, 0,
>  		   exp_dup, 0, BFD_RELOC_RISCV_SET_ULEB128);
>        exp_dup->X_add_symbol = exp->X_op_symbol;
> +      exp_dup->X_add_number = 0; /* Set addend of SUB_ULEB128 to zero.  */
>        fix_new_exp (fragP, fragP->fr_fix, 0,
>  		   exp_dup, 0, BFD_RELOC_RISCV_SUB_ULEB128);
>        free ((void *) exp_dup);
> -- 
> 2.39.3 (Apple Git-145)
> 

I am not familiar enough with the codebase to properly review, but this
appears to fix the problem that I was having.

Acked-by: Charlie Jenkins <charlie@rivosinc.com>


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] RISC-V: Clarify the behaviors of SET/ADD/SUB relocations.
  2023-10-20 17:58 ` Charlie Jenkins
@ 2023-10-27  0:37   ` Nelson Chu
  0 siblings, 0 replies; 3+ messages in thread
From: Nelson Chu @ 2023-10-27  0:37 UTC (permalink / raw)
  To: Charlie Jenkins; +Cc: binutils, kito.cheng, palmer

[-- Attachment #1: Type: text/plain, Size: 2824 bytes --]

On Sat, Oct 21, 2023 at 1:58 AM Charlie Jenkins <charlie@rivosinc.com>
wrote:

> On Thu, Oct 19, 2023 at 05:17:26PM +0800, Nelson Chu wrote:
> > We are used to generate these kinds of relocations by data directives.
> > Considering the following example,
> > .word (A + 3) - (B + 2)
> > The GAS will generate a pair of ADD/SUB for this,
> > R_RISCV_ADD, A + 1
> > R_RISCV_SUB, 0
> >
> > The addend of R_RISCV_SUB will always be zero, and the summary of the
> > constants will be stored in the addend of R_RISCV_ADD/SET.  Therefore,
> > we can always add the addend of these data relocations when doing
> relocations.
> >
> > But unfortunately, I had heard that if we are using .reloc to generate
> > the data relocations will make the relocations failed.  Refer to this,
> > .reloc offset, R_RISCV_ADD32, A + 3
> > .reloc offset, R_RISCV_SUB32, B + 2
> > .word 0
> > Then we can get the relocations as follows,
> > R_RISCV_ADD, A + 3
> > R_RISCV_SUB, B + 2
> > Then...  Current LD does the relocation, B - A + 3 + 2, which is wrong
> > obviously...
> >
> > So first of all, this patch fixes the wrong relocation behavior of
> > R_RISCV_SUB* relocations.
> >
> > Afterwards, considering the uleb128 direcitve, we will get a pair of
> > SET_ULEB128/SUB_ULEB128 relocations for it for now,
> > .uleb128 (A + 3) - (B + 2)
> > R_RISCV_SET_ULEB128, A + 1
> > R_RISCV_SUB_ULEB128, B + 1
> >
> > Which looks also wrong obviously, the summary of the constants should
> only
> > be stored into the addend of SET_ULEB128, and the addend of SUB_ULEB128
> should
> > be zero like other SUB relocations.  But the current LD will still get
> the right
> > relocation values since we only add the addend of SUB_ULEB128 by
> accident...
> > Anyway, this patch also fixes the behaviors above, to make sure that no
> matter
> > using .uleb128 or .reloc directives, we should always get the right
> values.
> >
> > bfd/
> >       * elfnn-riscv.c (perform_relocation):  Clarify that SUB relocations
> >       should substract the addend, rather than add.
> >       (riscv_elf_relocate_section): Since SET_ULEB128 won't go into
> >       perform_relocation, we should add it's addend here in advance.
> > gas/
> >       * config/tc-riscv.c (riscv_insert_uleb128_fixes): Set the addend of
> >       SUB_ULEB128 to zero since it should already be added into the
> addend
> >       of SET_ULEB128.
> > ---
> >  bfd/elfnn-riscv.c     | 22 ++++++++++++++++------
> >  gas/config/tc-riscv.c |  1 +
> >  2 files changed, 17 insertions(+), 6 deletions(-)
>
> I am not familiar enough with the codebase to properly review, but this
> appears to fix the problem that I was having.
>
> Acked-by: Charlie Jenkins <charlie@rivosinc.com>
>

Thanks for the feedback, committed.

Nelson

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-10-27  0:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-19  9:17 [PATCH] RISC-V: Clarify the behaviors of SET/ADD/SUB relocations Nelson Chu
2023-10-20 17:58 ` Charlie Jenkins
2023-10-27  0:37   ` Nelson Chu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).