[PATCH] RISC-V: PR28509, the default visibility symbol cannot be referenced by R_RISCV_JAL.

Nelson Chu nelson.chu@sifive.com
Thu Nov 4 04:15:13 GMT 2021


On Thu, Nov 4, 2021 at 1:19 AM Fangrui Song <i@maskray.me> wrote:
>
> On 2021-11-03, Nelson Chu wrote:
> >When generating the shared object, the default visibility symbols may bind
> >externally, which means they will be exported to the dynamic symbol table,
> >and are preemptible by default.  These symbols cannot be referenced by the
> >non-pic R_RISCV_JAL and R_RISCV_RVC_JUMP.  However, consider that linker
> >may relax the R_RISCV_CALL relocations to R_RISCV_JAL or R_RISCV_RVC_JUMP,
> >if these relocations are relocated to the plt entries, then we won't report
> >error for them.  Perhaps we also need the similar checks for the
> >R_RISCV_BRANCH and R_RISCV_RVC_BRANCH relocations.
> >
> >After applying this patch, and revert the following glibc patch,
> >https://sourceware.org/git/?p=glibc.git;a=commit;h=68389203832ab39dd0dbaabbc4059e7fff51c29b
> >
> >I get the expected errors as follows,
> >
> >/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/lib/gcc/riscv64-unknown-linux-gnu/11.1.0/../../../../riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_RVC_JUMP against `__sigsetjmp' which may bind externally can not be used when making a shared object; recompile with -fPIC
> >
> >/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/lib/gcc/riscv64-unknown-linux-gnu/11.1.0/../../../../riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `exit' which may bind externally can not be used when making a shared object; recompile with -fPIC
> >
> >But unfortunately, I also get the unexpected error when building libgcc,
> >
> >/scratch/nelsonc/riscv-gnu-toolchain/riscv-gcc/libgcc/config/riscv/div.S:42:
> >/scratch/nelsonc/build-upstream/rv64gc-linux/build-install/riscv64-unknown-linux-gnu/bin/ld: relocation R_RISCV_JAL against `__udivdi3' which may bind externally can not be used when making a shared object; recompile with -fPIC
> >
> >However, if I report warnings rather than errors for these cases, then I
> >can build the rv64-linux toolchain with glibc successfully.  I believe
> >this patch is what we need, and lld should have the same behavior, so we
> >probably need to update the div.S for libgcc, before applying this patch.
> >Maybe change the jal to call?  Or maybe we also need to disallow the branch
> >instructions which may refer to the default visibility symbol.
>
> Thanks for working on this!
>
> bfd/elf64-x86-64.c:elf_x86_64_need_pic and bfd/elfnn-aarch64.c:5889 ("externally can not be used when making a shared object; ")
> can be used as references.
>
> >bfd/
> >       pr 28509
> >       * elfnn-riscv.c (riscv_elf_relocate_section): Report errors when
> >       makeing a shard object, and the referenced symbols of R_RISCV_JAL
> >       relocations are default visibility.  Besides, we should handle most
> >       of the cases here, so don't need the unresolvable check later for
> >       R_RISCV_JAL and R_RISCV_RVC_JUMP.
> >ld/
> >       pr 28509
> >       * testsuite/ld-riscv-elf/ld-riscv-elf.exp: Updated.
> >       * testsuite/ld-riscv-elf/lib-nopic-01a.s: Removed.
> >       * testsuite/ld-riscv-elf/lib-nopic-01b.d: Likewise.
> >       * testsuite/ld-riscv-elf/lib-nopic-01b.s: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-01.d: New testcase.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-01.s: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-02.d: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-02.s: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-03.d: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-03.s: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-04.d: Likewise.
> >       * testsuite/ld-riscv-elf/shared-lib-nopic-04.s: Likewise.
> >---
> > bfd/elfnn-riscv.c                               | 71 +++++++++++++++----------
> > ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp      | 10 ++--
> > ld/testsuite/ld-riscv-elf/lib-nopic-01a.s       |  9 ----
> > ld/testsuite/ld-riscv-elf/lib-nopic-01b.d       |  5 --
> > ld/testsuite/ld-riscv-elf/lib-nopic-01b.s       |  9 ----
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.d |  4 ++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.s |  3 ++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.d |  4 ++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.s | 12 +++++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.d | 14 +++++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.s | 13 +++++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.d | 15 ++++++
> > ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.s | 14 +++++
> > 13 files changed, 126 insertions(+), 57 deletions(-)
> > delete mode 100644 ld/testsuite/ld-riscv-elf/lib-nopic-01a.s
> > delete mode 100644 ld/testsuite/ld-riscv-elf/lib-nopic-01b.d
> > delete mode 100644 ld/testsuite/ld-riscv-elf/lib-nopic-01b.s
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.d
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.s
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.d
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.s
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.d
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.s
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.d
> > create mode 100644 ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.s
> >
> >diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
> >index 2bae1e9..2e7d8b0 100644
> >--- a/bfd/elfnn-riscv.c
> >+++ b/bfd/elfnn-riscv.c
> >@@ -2467,12 +2467,44 @@ riscv_elf_relocate_section (bfd *output_bfd,
> >
> >       case R_RISCV_JAL:
> >       case R_RISCV_RVC_JUMP:
> >-        /* This line has to match the check in _bfd_riscv_relax_section.  */
> >-        if (bfd_link_pic (info) && h != NULL && h->plt.offset != MINUS_ONE)
> >+        if (bfd_link_pic (info) && h != NULL)
> >           {
> >-            /* Refer to the PLT entry.  */
> >-            relocation = sec_addr (htab->elf.splt) + h->plt.offset;
> >-            unresolved_reloc = false;
> >+            if (h->plt.offset != MINUS_ONE)
> >+              {
> >+                /* Refer to the PLT entry.  This check has to match the
> >+                   check in _bfd_riscv_relax_section.  */
> >+                relocation = sec_addr (htab->elf.splt) + h->plt.offset;
> >+                unresolved_reloc = false;
> >+              }
> >+            else if (!SYMBOL_REFERENCES_LOCAL (info, h)
> >+                     && (input_section->flags & SEC_ALLOC) != 0
> >+                     && (input_section->flags & SEC_READONLY) != 0
> >+                     && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
>
> I am not familiar with the BFD rules, but
> bfd/elfnn-aarch64.c:5889 doesn't appear to test STV_DEFAULT.
> Is the condition covered by !SYMBOL_REFERENCES_LOCAL  ?
>
> I assume that SYMBOL_REFERENCES_LOCAL  handles correctly

Yes you are right, after checking the SYMBOL_REFERENCES_LOCAL  in
detail, it should have checked the STV_DEFAULT.  Thanks.

> * -shared -Bsymbolic  (if defined => non-preemptible)
> * -shared --dynamic-list  (if defined && not listed in the dynamic list => non-preemptible)
>
>
> `(input_section->flags & SEC_READONLY) != 0` is an interesting condition
> which is used by aarch64 and x86 as well. It means "awx" text section
> can use text relocations without the diagnostic. ld.lld will probably
> just never allow such text relocations.
>
> >+              {
> >+                /* PR 28509, when generating the shared object, these
> >+                   referenced symbols may bind externally, which means
> >+                   they will be exported to the dynamic symbol table,
> >+                   and are preemptible by default.  These symbols cannot
> >+                   be referenced by the non-pic relocations, like
> >+                   R_RISCV_JAL and R_RISCV_RVC_JUMP relocations.
> >+
> >+                   However, consider that linker may relax the R_RISCV_CALL
> >+                   relocations to R_RISCV_JAL or R_RISCV_RVC_JUMP, if
> >+                   these relocations are relocated to the plt entries,
> >+                   then we won't report error for them.
> >+
> >+                   Perhaps we also need the similar checks for the
> >+                   R_RISCV_BRANCH and R_RISCV_RVC_BRANCH relocations.  */
> >+                if (asprintf (&msg_buf,
> >+                              _("%%X%%P: relocation %s against `%s' which "
> >+                                "may bind externally can not be used when "
> >+                                "making a shared object; recompile "
> >+                                "with -fPIC\n"),
> >+                              howto->name, h->root.root.string) == -1)
>
> You may want to extract the message into a function (a la
> bfd/elf64-x86-64.c:elf_x86_64_need_pic) because it is likely needed by
> some other relocation types.

Umm this makes me think that I should move the message to the place
where we are used to setting the bfd_reloc_notsupported messages,
since we probably need the similar check for R_RISCV_BRANCH.

> >+                  msg_buf = NULL;
> >+                msg = msg_buf;
> >+                r = bfd_reloc_notsupported;
> >+              }
> >           }
> >         break;
> >
> >@@ -2765,29 +2797,12 @@ riscv_elf_relocate_section (bfd *output_bfd,
> >         && _bfd_elf_section_offset (output_bfd, info, input_section,
> >                                     rel->r_offset) != (bfd_vma) -1)
> >       {
> >-        switch (r_type)
> >-          {
> >-          case R_RISCV_JAL:
> >-          case R_RISCV_RVC_JUMP:
> >-            if (asprintf (&msg_buf,
> >-                          _("%%X%%P: relocation %s against `%s' can "
> >-                            "not be used when making a shared object; "
> >-                            "recompile with -fPIC\n"),
> >-                          howto->name,
> >-                          h->root.root.string) == -1)
> >-              msg_buf = NULL;
> >-            break;
> >-
> >-          default:
> >-            if (asprintf (&msg_buf,
> >-                          _("%%X%%P: unresolvable %s relocation against "
> >-                            "symbol `%s'\n"),
> >-                          howto->name,
> >-                          h->root.root.string) == -1)
> >-              msg_buf = NULL;
> >-            break;
> >-          }
> >-
> >+        if (asprintf (&msg_buf,
> >+                      _("%%X%%P: unresolvable %s relocation against "
> >+                        "symbol `%s'\n"),
> >+                      howto->name,
> >+                      h->root.root.string) == -1)
> >+          msg_buf = NULL;
> >         msg = msg_buf;
> >         r = bfd_reloc_notsupported;
> >       }
> >diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> >index 78a7134..6bc6c6f 100644
> >--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> >+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
> >@@ -192,12 +192,10 @@ if [istarget "riscv*-*-*"] {
> >                                   "gp-test-${abi}"]]
> >     }
> >
> >-    run_ld_link_tests {
> >-      { "Link non-pic code into a shared library (setup)"
> >-          "-shared" "" "" {lib-nopic-01a.s}
> >-          {} "lib-nopic-01a.so" }
> >-    }
> >-    run_dump_test "lib-nopic-01b"
> >+    run_dump_test "shared-lib-nopic-01"
> >+    run_dump_test "shared-lib-nopic-02"
> >+    run_dump_test "shared-lib-nopic-03"
> >+    run_dump_test "shared-lib-nopic-04"
> >
> >     # IFUNC testcases.
> >     # Check IFUNC by single type relocs.
> >diff --git a/ld/testsuite/ld-riscv-elf/lib-nopic-01a.s b/ld/testsuite/ld-riscv-elf/lib-nopic-01a.s
> >deleted file mode 100644
> >index 632875d..0000000
> >--- a/ld/testsuite/ld-riscv-elf/lib-nopic-01a.s
> >+++ /dev/null
> >@@ -1,9 +0,0 @@
> >-        .option nopic
> >-      .text
> >-      .align  1
> >-      .globl  func1
> >-      .type   func1, @function
> >-func1:
> >-      jal     func2
> >-      jr      ra
> >-      .size   func1, .-func1
> >diff --git a/ld/testsuite/ld-riscv-elf/lib-nopic-01b.d b/ld/testsuite/ld-riscv-elf/lib-nopic-01b.d
> >deleted file mode 100644
> >index 1c2c907..0000000
> >--- a/ld/testsuite/ld-riscv-elf/lib-nopic-01b.d
> >+++ /dev/null
> >@@ -1,5 +0,0 @@
> >-#name: link non-pic code into a shared library
> >-#source: lib-nopic-01b.s
> >-#as:
> >-#ld: -shared tmpdir/lib-nopic-01a.so
> >-#error: .*relocation R_RISCV_JAL against `func1' can not be used when making a shared object; recompile with -fPIC
> >diff --git a/ld/testsuite/ld-riscv-elf/lib-nopic-01b.s b/ld/testsuite/ld-riscv-elf/lib-nopic-01b.s
> >deleted file mode 100644
> >index ea7b029..0000000
> >--- a/ld/testsuite/ld-riscv-elf/lib-nopic-01b.s
> >+++ /dev/null
> >@@ -1,9 +0,0 @@
> >-        .option nopic
> >-      .text
> >-      .align  1
> >-      .globl  func2
> >-      .type   func2, @function
> >-func2:
> >-      jal     func1
> >-      jr      ra
> >-      .size   func2, .-func2
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.d b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.d
> >new file mode 100644
> >index 0000000..2ea8512
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.d
> >@@ -0,0 +1,4 @@
> >+#source: shared-lib-nopic-01.s
> >+#as:
> >+#ld: -shared
> >+#error: .*relocation R_RISCV_JAL against `foo' which may bind externally can not be used when making a shared object; recompile with -fPIC
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.s b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.s
> >new file mode 100644
> >index 0000000..8d85c17
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-01.s
> >@@ -0,0 +1,3 @@
> >+        .option nopic
> >+      .text
> >+      jal     foo     # undefined
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.d b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.d
> >new file mode 100644
> >index 0000000..f866d01
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.d
> >@@ -0,0 +1,4 @@
> >+#source: shared-lib-nopic-02.s
> >+#as:
> >+#ld: -shared
> >+#error: .*relocation R_RISCV_JAL against `foo_default' which may bind externally can not be used when making a shared object; recompile with -fPIC
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.s b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.s
> >new file mode 100644
> >index 0000000..61a8cc1
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-02.s
> >@@ -0,0 +1,12 @@
> >+        .option nopic
> >+      .text
> >+      .align  1
> >+
> >+      jal     foo_default
> >+
> >+      .globl  foo_default
> >+      .type   foo_default, @function
> >+foo_default:
> >+      nop
> >+      ret
> >+      .size   foo_default, .-foo_default
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.d b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.d
> >new file mode 100644
> >index 0000000..182a557
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.d
> >@@ -0,0 +1,14 @@
> >+#source: shared-lib-nopic-03.s
> >+#as:
> >+#ld: -shared
> >+#objdump: -d
> >+
> >+.*:[  ]+file format .*
> >+
> >+Disassembly of section \.text:
> >+
> >+#...
> >+.*:[  ]+[0-9a-f]+[    ]+jal[  ]+.* <foo_default>
> >+
> >+0+[0-9a-f]+ <foo_default>:
> >+#...
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.s b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.s
> >new file mode 100644
> >index 0000000..d1855f8
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-03.s
> >@@ -0,0 +1,13 @@
> >+        .option nopic
> >+      .text
> >+      .align  1
> >+
> >+      jal     foo_default
> >+
> >+      .globl  foo_default
> >+      .hidden foo_default
> >+      .type   foo_default, @function
> >+foo_default:
> >+      nop
> >+      ret
> >+      .size   foo_default, .-foo_default
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.d b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.d
> >new file mode 100644
> >index 0000000..e66b721
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.d
> >@@ -0,0 +1,15 @@
> >+#source: shared-lib-nopic-04.s
> >+#as:
> >+#ld: -shared
> >+#objdump: -d
> >+
> >+.*:[  ]+file format .*
> >+
> >+#...
> >+Disassembly of section \.text:
> >+#...
> >+.*:[  ]+[0-9a-f]+[    ]+jal[  ]+.* <foo_default@plt>
> >+.*:[  ]+[0-9a-f]+[    ]+jal[  ]+.* <foo_default@plt>
> >+
> >+0+[0-9a-f]+ <foo_default>:
> >+#...
> >diff --git a/ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.s b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.s
> >new file mode 100644
> >index 0000000..46760f8
> >--- /dev/null
> >+++ b/ld/testsuite/ld-riscv-elf/shared-lib-nopic-04.s
> >@@ -0,0 +1,14 @@
> >+        .option nopic
> >+      .text
> >+      .align  1
> >+
> >+      call    foo_default
> >+      jal     foo_default
> >+
> >+
> >+      .globl  foo_default
> >+      .type   foo_default, @function
> >+foo_default:
> >+      nop
> >+      ret
> >+      .size   foo_default, .-foo_default
> >--
> >2.7.4
> >
>
> I wish there were a way to place multiple connected tests in one file ;-)
>
> https://llvm.org/docs/TestingGuide.html#extra-files

Yeah I know that llvm is more convenient since the related testcases
can be placed into one file.  For gnu as I know, since we are used to
stop assembling or linking files once we find an error, so if there
are multiple errors in a file, then only the first one will be
reported, and the rest will be ignored.  That's why we need multiple
files to test the error.  But yes, you are right, it would be good to
combine them into only one file, and I'm also happy to see it, but I
don’t know what to do at the moment.  However, the
shared-lib-nopic-03.s and shared-lib-nopic-04.s can be combined into
one file, so I will merge them at this time.  Thanks!

Besides, I figured that I should try to update the libgcc, before
applying this patch.  So I will find time to do this first.

Thank you very much
Nelson


More information about the Binutils mailing list