RISC-V: Clarify link behaviors of R_RISCV_32/64 relocations with ABS symbol.
authorNelson Chu <nelson@rivosinc.com>
Sat, 25 Mar 2023 00:41:12 +0000 (08:41 +0800)
committerNelson Chu <nelson@rivosinc.com>
Wed, 29 Mar 2023 23:40:14 +0000 (07:40 +0800)
There are two improvements, which are all referenced to aarch64,

* R_RISCV_32 with non ABS symbol cannot be used under RV64 when making
  shard objects.

* Don't need dynamic relocation for R_RISCV_32/64 under RV32/RV64 when
  making shared objects, if the referenced symbol is local ABS symbol.

However, considering this link,
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/341

Seems like we should makes all R_RISCV_32/64 relocs with ABS symbol
that don't need any dynamic relocations when making the shared objects.
But anyway, I just sync the current behavior as aarch64 ld, in case
there are any unexpected behaviors happen.

Passed the gcc/binutils regressions in riscv-gnu-toolchain.

bfd/
    * elfnn-riscv.c (riscv_elf_check_relocs): Only allow R_RISCV_32 with ABS
    symbol under RV64.
    (riscv_elf_relocate_section): R_RISCV_32/64 with local ABS symbol under
    RV32/RV64 doesn't need any dynamic relocation when making shared objects.
    I just make the implementations similar to other targets, so that will be
    more easy to mainatain.
ld/
    * testsuite/ld-riscv-elf/data-reloc*: New testcases.
    * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Added new data-reloc* testcases,
    and need to make ifunc-seperate* testcases work for rv32.
    * testsuite/ld-riscv-elf/ifunc-seperate-caller-nonplt.s: Likewise.
    * testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s: Likewise.

14 files changed:
bfd/elfnn-riscv.c
ld/testsuite/ld-riscv-elf/data-reloc-rv32-pic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv32-pie.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv32-symbolic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv64-abs32-pic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv64-addr32-pic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv64-pic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv64-pie.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv64-symbolic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc-rv64-undef32-pic.d [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/data-reloc.s [new file with mode: 0644]
ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-nonplt.s
ld/testsuite/ld-riscv-elf/ifunc-seperate-caller-plt.s
ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp

index 59e949a2cb5f6c92848a9643f3873073d6852263..00f034a67513bd9df29b892516c392135d438d56 100644 (file)
@@ -734,6 +734,7 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       unsigned int r_type;
       unsigned int r_symndx;
       struct elf_link_hash_entry *h;
+      bool is_abs_symbol = false;
 
       r_symndx = ELFNN_R_SYM (rel->r_info);
       r_type = ELFNN_R_TYPE (rel->r_info);
@@ -753,6 +754,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          if (isym == NULL)
            return false;
 
+         is_abs_symbol = isym->st_shndx == SHN_ABS ? true : false;
+
          /* Check relocation against local STT_GNU_IFUNC symbol.  */
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
            {
@@ -778,6 +781,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+         is_abs_symbol = bfd_is_abs_symbol (&h->root) ? true : false;
        }
 
       if (h != NULL)
@@ -879,13 +884,31 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_RISCV_HI20:
          if (bfd_link_pic (info))
            return bad_static_reloc (abfd, r_type, h);
-         /* Fall through.  */
+         goto static_reloc;
+
+       case R_RISCV_32:
+         if (ARCH_SIZE > 32
+             && bfd_link_pic (info)
+             && (sec->flags & SEC_ALLOC) != 0)
+           {
+             if (is_abs_symbol)
+               break;
+
+             reloc_howto_type *r_t = riscv_elf_rtype_to_howto (abfd, r_type);
+             _bfd_error_handler
+               (_("%pB: relocation %s against non-absolute symbol `%s' can "
+                  "not be used in RVNN when making a shared object"),
+                abfd, r_t ? r_t->name : _("<unknown>"),
+                h != NULL ? h->root.root.string : "a local symbol");
+             bfd_set_error (bfd_error_bad_value);
+             return false;
+           }
+         goto static_reloc;
 
        case R_RISCV_COPY:
        case R_RISCV_JUMP_SLOT:
        case R_RISCV_RELATIVE:
        case R_RISCV_64:
-       case R_RISCV_32:
          /* Fall through.  */
 
        static_reloc:
@@ -2630,6 +2653,11 @@ riscv_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_RISCV_32:
+         /* Non ABS symbol should be blocked in check_relocs.  */
+         if (ARCH_SIZE > 32)
+           break;
+         /* Fall through.  */
+
        case R_RISCV_64:
          if ((input_section->flags & SEC_ALLOC) == 0)
            break;
@@ -2639,7 +2667,6 @@ riscv_elf_relocate_section (bfd *output_bfd,
            {
              Elf_Internal_Rela outrel;
              asection *sreloc;
-             bool skip_static_relocation, skip_dynamic_relocation;
 
              /* When generating a shared object, these relocations
                 are copied into the output file to be resolved at run
@@ -2648,26 +2675,44 @@ riscv_elf_relocate_section (bfd *output_bfd,
              outrel.r_offset =
                _bfd_elf_section_offset (output_bfd, info, input_section,
                                         rel->r_offset);
-             skip_static_relocation = outrel.r_offset != (bfd_vma) -2;
-             skip_dynamic_relocation = outrel.r_offset >= (bfd_vma) -2;
+             bool skip = false;
+             bool relocate = false;
+             if (outrel.r_offset == (bfd_vma) -1)
+               skip = true;
+             else if (outrel.r_offset == (bfd_vma) -2)
+               {
+                 skip = true;
+                 relocate = true;
+               }
+             else if (h != NULL && bfd_is_abs_symbol (&h->root))
+               {
+                 /* Don't need dynamic reloc when the ABS symbol is
+                    non-dynamic or forced to local.  Maybe just use
+                    SYMBOL_REFERENCES_LOCAL to check?  */
+                 skip = (h->forced_local || (h->dynindx == -1));
+                 relocate = skip;
+               }
+
              outrel.r_offset += sec_addr (input_section);
 
-             if (skip_dynamic_relocation)
-               memset (&outrel, 0, sizeof outrel);
+             if (skip)
+               memset (&outrel, 0, sizeof outrel);     /* R_RISCV_NONE.  */
              else if (RISCV_COPY_INPUT_RELOC (info, h))
                {
+                 /* Maybe just use !SYMBOL_REFERENCES_LOCAL to check?  */
                  outrel.r_info = ELFNN_R_INFO (h->dynindx, r_type);
                  outrel.r_addend = rel->r_addend;
                }
              else
                {
+                 /* This symbol is local, or marked to become local.  */
                  outrel.r_info = ELFNN_R_INFO (0, R_RISCV_RELATIVE);
                  outrel.r_addend = relocation + rel->r_addend;
                }
 
              sreloc = elf_section_data (input_section)->sreloc;
              riscv_elf_append_rela (output_bfd, sreloc, &outrel);
-             if (skip_static_relocation)
+             if (!relocate)
                continue;
            }
          break;
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv32-pic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv32-pic.d
new file mode 100644 (file)
index 0000000..13f34e0
--- /dev/null
@@ -0,0 +1,21 @@
+#source: data-reloc.s
+#as: -march=rv32i -mabi=ilp32 -defsym __abs__=1 -defsym __addr__=1 -defsym __undef__=1
+#ld: -m[riscv_choose_ilp32_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -shared
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+8000 <addr_globl>:
+    8000:      00000000                .word   0x00000000
+                       8000: R_RISCV_32        addr_globl
+
+0+8004 <addr_local>:
+       ...
+                       8004: R_RISCV_RELATIVE  \*ABS\*\+0x8004
+                       8008: R_RISCV_32        abs
+    800c:      00000200                .word   0x00000200
+    8010:      00000000                .word   0x00000000
+                       8010: R_RISCV_32        undef
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv32-pie.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv32-pie.d
new file mode 100644 (file)
index 0000000..1e8f35a
--- /dev/null
@@ -0,0 +1,18 @@
+#source: data-reloc.s
+#as: -march=rv32i -mabi=ilp32 -defsym __abs__=1 -defsym __addr__=1
+#ld: -m[riscv_choose_ilp32_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -pie
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+Disassembly of section .text:
+
+0+8000 <addr_globl>:
+    8000:      00000000                .word   0x00000000
+                       8000: R_RISCV_RELATIVE  \*ABS\*\+0x8000
+
+0+8004 <addr_local>:
+    8004:      00000000                .word   0x00000000
+                       8004: R_RISCV_RELATIVE  \*ABS\*\+0x8004
+    8008:      00000100                .word   0x00000100
+    800c:      00000200                .word   0x00000200
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv32-symbolic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv32-symbolic.d
new file mode 100644 (file)
index 0000000..5c947e2
--- /dev/null
@@ -0,0 +1,21 @@
+#source: data-reloc.s
+#as: -march=rv32i -mabi=ilp32 -defsym __abs__=1 -defsym __addr__=1 -defsym __undef__=1
+#ld: -m[riscv_choose_ilp32_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -shared -Bsymbolic
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+8000 <addr_globl>:
+    8000:      00000000                .word   0x00000000
+                       8000: R_RISCV_RELATIVE  \*ABS\*\+0x8000
+
+0+8004 <addr_local>:
+       ...
+                       8004: R_RISCV_RELATIVE  \*ABS\*\+0x8004
+                       8008: R_RISCV_RELATIVE  \*ABS\*\+0x100
+    800c:      00000200                .word   0x00000200
+    8010:      00000000                .word   0x00000000
+                       8010: R_RISCV_32        undef
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv64-abs32-pic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv64-abs32-pic.d
new file mode 100644 (file)
index 0000000..1d3686d
--- /dev/null
@@ -0,0 +1,13 @@
+#source: data-reloc.s
+#as: -march=rv64i -mabi=lp64 -defsym __abs__=1
+#ld: -m[riscv_choose_lp64_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -shared
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+8000 <.text>:
+    8000:      00000100                .word   0x00000100
+    8004:      00000200                .word   0x00000200
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv64-addr32-pic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv64-addr32-pic.d
new file mode 100644 (file)
index 0000000..39b50e3
--- /dev/null
@@ -0,0 +1,4 @@
+#source: data-reloc.s
+#as: -march=rv64i -mabi=lp64 -defsym __addr__=1
+#ld: -m[riscv_choose_lp64_emul] -Ttext 0x8000 --defsym _start=0x0  -shared
+#error: .*relocation R_RISCV_32 against non-absolute symbol `addr_globl' can not be used in RV64 when making a shared object.*
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv64-pic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv64-pic.d
new file mode 100644 (file)
index 0000000..dab0ccc
--- /dev/null
@@ -0,0 +1,21 @@
+#source: data-reloc.s
+#as: -march=rv64i -mabi=lp64 -defsym __64_bit__=1 -defsym __abs__=1 -defsym __addr__=1 -defsym __undef__=1
+#ld: -m[riscv_choose_lp64_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -shared
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+8000 <addr_globl>:
+       ...
+                       8000: R_RISCV_64        addr_globl
+
+0+8008 <addr_local>:
+       ...
+                       8008: R_RISCV_RELATIVE  \*ABS\*\+0x8008
+                       8010: R_RISCV_64        abs
+    8018:      00000200                .word   0x00000200
+       ...
+                       8020: R_RISCV_64        undef
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv64-pie.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv64-pie.d
new file mode 100644 (file)
index 0000000..fd6c470
--- /dev/null
@@ -0,0 +1,21 @@
+#source: data-reloc.s
+#as: -march=rv64i -mabi=lp64 -defsym __64_bit__=1 -defsym __abs__=1 -defsym __addr__=1
+#ld: -m[riscv_choose_lp64_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -pie
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+8000 <addr_globl>:
+       ...
+                       8000: R_RISCV_RELATIVE  \*ABS\*\+0x8000
+
+0+8008 <addr_local>:
+       ...
+                       8008: R_RISCV_RELATIVE  \*ABS\*\+0x8008
+    8010:      00000100                .word   0x00000100
+    8014:      00000000                .word   0x00000000
+    8018:      00000200                .word   0x00000200
+    801c:      00000000                .word   0x00000000
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv64-symbolic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv64-symbolic.d
new file mode 100644 (file)
index 0000000..5d41f86
--- /dev/null
@@ -0,0 +1,21 @@
+#source: data-reloc.s
+#as: -march=rv64i -mabi=lp64 -defsym __64_bit__=1 -defsym __abs__=1 -defsym __addr__=1 -defsym __undef__=1
+#ld: -m[riscv_choose_lp64_emul] -Ttext 0x8000 --defsym _start=0x0 --defsym abs=0x100 --defsym abs_local=0x200 -shared -Bsymbolic
+#objdump: -dR
+
+.*:[   ]+file format .*
+
+
+Disassembly of section .text:
+
+0+8000 <addr_globl>:
+       ...
+                       8000: R_RISCV_RELATIVE  \*ABS\*\+0x8000
+
+0+8008 <addr_local>:
+       ...
+                       8008: R_RISCV_RELATIVE  \*ABS\*\+0x8008
+                       8010: R_RISCV_RELATIVE  \*ABS\*\+0x100
+    8018:      00000200                .word   0x00000200
+       ...
+                       8020: R_RISCV_64        undef
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc-rv64-undef32-pic.d b/ld/testsuite/ld-riscv-elf/data-reloc-rv64-undef32-pic.d
new file mode 100644 (file)
index 0000000..e5de484
--- /dev/null
@@ -0,0 +1,4 @@
+#source: data-reloc.s
+#as: -march=rv64i -mabi=lp64 -defsym __undef__=1
+#ld: -m[riscv_choose_lp64_emul] -Ttext 0x8000 --defsym _start=0x0  -shared
+#error: .*relocation R_RISCV_32 against non-absolute symbol `undef' can not be used in RV64 when making a shared object.*
diff --git a/ld/testsuite/ld-riscv-elf/data-reloc.s b/ld/testsuite/ld-riscv-elf/data-reloc.s
new file mode 100644 (file)
index 0000000..3715150
--- /dev/null
@@ -0,0 +1,22 @@
+       .macro  DATA symbol
+.ifdef __64_bit__
+       .quad   \symbol
+.else
+       .word   \symbol
+.endif
+       .endm
+.ifdef __addr__
+       .globl  addr_globl
+addr_globl:
+       DATA    addr_globl
+addr_local:
+       DATA    addr_local
+.endif
+.ifdef __abs__
+       .hidden abs_local
+       DATA    abs
+       DATA    abs_local
+.endif
+.ifdef __undef__
+       DATA    undef
+.endif
index 23c7254ad5b00dc5fa408096e1188a2faf4e1f5c..df0d33b97e261a9a318d64f3380953f73d129278 100644 (file)
@@ -20,4 +20,4 @@ main:
 
        .data
 foo_addr:
-       .long   foo
+       .quad   foo
index 8aa640347065655d0d275b8ec504b5d5b15609bc..cc1608a9803ce5d492e0b8ea25c290a6e3301eb7 100644 (file)
@@ -23,4 +23,4 @@ main:
 
        .data
 foo_addr:
-       .long   foo
+       .quad   foo
index 5dd6144efd346872a7d638ec4fc21a7805355194..1b2a5ce2cb2d34cb1738fff9d0c91c8b9bf09c51 100644 (file)
@@ -217,6 +217,16 @@ if [istarget "riscv*-*-*"] {
     run_dump_test "shared-lib-nopic-03"
     run_dump_test "shared-lib-nopic-04"
 
+    run_dump_test "data-reloc-rv64-pic"
+    run_dump_test "data-reloc-rv64-pie"
+    run_dump_test "data-reloc-rv64-symbolic"
+    run_dump_test "data-reloc-rv32-pic"
+    run_dump_test "data-reloc-rv32-pie"
+    run_dump_test "data-reloc-rv32-symbolic"
+    run_dump_test "data-reloc-rv64-abs32-pic"
+    run_dump_test "data-reloc-rv64-addr32-pic"
+    run_dump_test "data-reloc-rv64-undef32-pic"
+
     # IFUNC testcases.
     # Check IFUNC by single type relocs.
     run_dump_test_ifunc "ifunc-reloc-call-01" rv32 exe
@@ -270,6 +280,11 @@ if [istarget "riscv*-*-*"] {
     run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 pie
     run_dump_test_ifunc "ifunc-plt-got-overwrite" rv64 pic
 
+    # TODO: Make the following tests work under RV32.
+    if [istarget "riscv32-*-*"] {
+      return
+    }
+
     # Setup shared libraries.
     run_ld_link_tests {
        { "Build shared library for IFUNC non-PLT caller"