[2/2] riscv: Let compiler handle unaligned access when fixing R_RISCV_RELATIVE

Message ID 20220623154705.14416-3-kito.cheng@sifive.com
State Superseded
Headers
Series riscv: Prevent potential unaligned memory access during dynamic relocation |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686

Commit Message

Kito Cheng June 23, 2022, 3:47 p.m. UTC
  Explicitly say that might be unaligned, so that the compiler will generate
appropriate code sequence for this relocation fix-up.

Although RISC-V Linux will enable the unaligned memory access handler by
default, that is quite expensive in general, letting the compiler solve this
will be much cheaper - just break down that into several store byte
instructions.

ARM and MIPS has similar issue:

ARM: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51456
MIPS: https://gcc.gnu.org/legacy-ml/gcc-help/2005-07/msg00325.html
---
 sysdeps/riscv/dl-machine.h | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
  

Comments

Adhemerval Zanella Netto June 23, 2022, 4:47 p.m. UTC | #1
> On 23 Jun 2022, at 12:47, Kito Cheng <kito.cheng@sifive.com> wrote:
> 
> Explicitly say that might be unaligned, so that the compiler will generate
> appropriate code sequence for this relocation fix-up.
> 
> Although RISC-V Linux will enable the unaligned memory access handler by
> default, that is quite expensive in general, letting the compiler solve this
> will be much cheaper - just break down that into several store byte
> instructions.
> 
> ARM and MIPS has similar issue:
> 
> ARM: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51456
> MIPS: https://gcc.gnu.org/legacy-ml/gcc-help/2005-07/msg00325.html
> ---
> sysdeps/riscv/dl-machine.h | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
> index 4bb858adaa..c83513e5b8 100644
> --- a/sysdeps/riscv/dl-machine.h
> +++ b/sysdeps/riscv/dl-machine.h
> @@ -157,7 +157,14 @@ __attribute__ ((always_inline))
> elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
> 			  void *const reloc_addr)
> {
> -  *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend;
> +  /* R_RISCV_RELATIVE might located in debug info section which might not
> +     aligned to XLEN bytes. */
> +  struct unaligned
> +    {
> +      ElfW(Addr) x;
> +    } __attribute__ ((packed, may_alias));
> +  /* Support relocations on unaligned offsets.  */
> +  ((struct unaligned *) reloc_addr)->x = l_addr + reloc->r_addend;
> }

Although the same strategy on arm dl-machine.h, I think the most usual way
is to use a a memcpy since it avoid the type cast (which strictly is a UB):

  /* R_RISCV_RELATIVE might located in debug info section which might not
     aligned to XLEN bytes.  Also support relocations on unaligned offsets.  */
  ElfW(Addr) value = l_addr + relic->r_addend;
  memcpy (reloc_addr, &value, sizeof value);
  

> 
> /* Perform a relocation described by R_INFO at the location pointed to
> -- 
> 2.34.0
>
  
Palmer Dabbelt June 23, 2022, 9:50 p.m. UTC | #2
On Thu, 23 Jun 2022 09:47:20 PDT (-0700), adhemerval.zanella@linaro.org wrote:
>
>
>> On 23 Jun 2022, at 12:47, Kito Cheng <kito.cheng@sifive.com> wrote:
>> 
>> Explicitly say that might be unaligned, so that the compiler will generate
>> appropriate code sequence for this relocation fix-up.
>> 
>> Although RISC-V Linux will enable the unaligned memory access handler by
>> default, that is quite expensive in general, letting the compiler solve this
>> will be much cheaper - just break down that into several store byte
>> instructions.
>> 
>> ARM and MIPS has similar issue:
>> 
>> ARM: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51456
>> MIPS: https://gcc.gnu.org/legacy-ml/gcc-help/2005-07/msg00325.html
>> ---
>> sysdeps/riscv/dl-machine.h | 9 ++++++++-
>> 1 file changed, 8 insertions(+), 1 deletion(-)
>> 
>> diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
>> index 4bb858adaa..c83513e5b8 100644
>> --- a/sysdeps/riscv/dl-machine.h
>> +++ b/sysdeps/riscv/dl-machine.h
>> @@ -157,7 +157,14 @@ __attribute__ ((always_inline))
>> elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
>> 			  void *const reloc_addr)
>> {
>> -  *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend;
>> +  /* R_RISCV_RELATIVE might located in debug info section which might not
>> +     aligned to XLEN bytes. */
>> +  struct unaligned
>> +    {
>> +      ElfW(Addr) x;
>> +    } __attribute__ ((packed, may_alias));
>> +  /* Support relocations on unaligned offsets.  */
>> +  ((struct unaligned *) reloc_addr)->x = l_addr + reloc->r_addend;
>> }
>
> Although the same strategy on arm dl-machine.h, I think the most usual way
> is to use a a memcpy since it avoid the type cast (which strictly is a UB):
>
>   /* R_RISCV_RELATIVE might located in debug info section which might not
>      aligned to XLEN bytes.  Also support relocations on unaligned offsets.  */
>   ElfW(Addr) value = l_addr + relic->r_addend;
>   memcpy (reloc_addr, &value, sizeof value);

Presumably we should fix the other ports as well?  I just see

$ git grep '((struct unaligned \*) reloc_addr)' | cat
sysdeps/arm/dl-machine.h:	   ((struct unaligned *) reloc_addr)->x += value;

I'm not super partial to either behavior, but your suggestion is shorter 
and avoiding UB is always a good bet so that sounds better to me as 
well.  With that

Acked-by: Palmer Dabbelt <palmer@rivosinc.com>

I just sent along the arm version of this, figured that's easier than 
waiting.

Thanks!

>   
>
>> 
>> /* Perform a relocation described by R_INFO at the location pointed to
>> -- 
>> 2.34.0
>>
  

Patch

diff --git a/sysdeps/riscv/dl-machine.h b/sysdeps/riscv/dl-machine.h
index 4bb858adaa..c83513e5b8 100644
--- a/sysdeps/riscv/dl-machine.h
+++ b/sysdeps/riscv/dl-machine.h
@@ -157,7 +157,14 @@  __attribute__ ((always_inline))
 elf_machine_rela_relative (ElfW(Addr) l_addr, const ElfW(Rela) *reloc,
 			  void *const reloc_addr)
 {
-  *(ElfW(Addr) *) reloc_addr = l_addr + reloc->r_addend;
+  /* R_RISCV_RELATIVE might located in debug info section which might not
+     aligned to XLEN bytes. */
+  struct unaligned
+    {
+      ElfW(Addr) x;
+    } __attribute__ ((packed, may_alias));
+  /* Support relocations on unaligned offsets.  */
+  ((struct unaligned *) reloc_addr)->x = l_addr + reloc->r_addend;
 }
 
 /* Perform a relocation described by R_INFO at the location pointed to