public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support
@ 2024-06-26 10:04 Xi Ruoyao
  2024-06-26 10:04 ` [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64 Xi Ruoyao
                   ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-26 10:04 UTC (permalink / raw)
  To: binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy, Xi Ruoyao

This series adds DT_RELR support for LoongArch.

The leading 3 patches pave the way for DT_RELR:

The first patch rejects turning R_LARCH_32 as a runtime reloc in
ELFCLASS64, specifically R_LARCH_32 won't be turned to an
R_LARCH_RELATIVE in ELFCLASS64 silently.  This avoids an OOB write at
runtime, and also simplifies the logic of DT_RELR implementation.

The second patch fixes a long-standing bug causing some relocs missing
(overwritten by another reloc, or written out of the .rela.dyn section)
when multiple STT_GNU_IFUNC symbol is defined locally with different
visibilities and we are linking a shared object.  Without DT_RELR in
most cases an R_LARCH_RELATIVE against __dso_handle is overwritten by
an R_LARCH_JUMP_SLOT and the issue is mostly latent.  But with DT_RELR
the R_LARCH_RELATIVE is packed, and other relocs start to be
overwritten, causing Glibc test failures.  Thus the bug must be fixed
before implementing DT_RELR.

The third patch makes STV_PROTECTED function (STT_FUNC and
STT_GNU_IFUNC) symbols referenced locally when linking a shared library.
The other ports don't do this only because they rely on copy relocation
and -mdirect-extern-access to remove unnecessary GOT access, and with
-mdirect-extern-access locally referencing STV_PROTECTED functions can
break pointer equality.  This is not a problem for us because we don't
and won't support copy relocation, and a programmer shouldn't use
-mdirect-extern-access unless they can make sure no dynamic link is
performed.  So we can just make STV_PROTECTED functions referenced
locally.  This makes the code slightly faster, and also simplifies the
logic of DT_RELR implementation.

The fourth patch implements DT_RELR.  The algorithm is based on the
AArch64 implementation by Szabolcs and simplified because we don't have
as many features as AArch64 (for example we don't have -z
dynamic-undefined-weak).  The linker relaxation pass is adapted to fix
up the relative relocations to be packed when deleting bytes from the
section where the relative relocations are against.

The fifth patch adds tests for DT_RELR.

Besides these tests, the DT_RELR implementation is also tested by:

- Running ld bootstrap test with -z pack-relative-relocs.  The test
  has passed.  The patch adding this test is
  https://sourceware.org/pipermail/binutils/2024-June/135021.html but
  it does not work with old Glibc, thus it cannot be upstreamed until we
  figure out how to skip it for old Glibc.
- Building Glibc (which enables -z pack-relative-relocs by default if
  available) with the patched linker and run its test suite.  All
  relative relocs in libc.so are packed and the test result is all clean.
- Building patched Linux kernel with DT_RELR enabled.  All relative
  relocs in vmlinux is packed, the kernel booted fine and it has been
  running fine for 100+ hours.

Changes from v1:

- No real code change.
- Rebase to current master branch (resolving a conflict with AArch64 ILP32
  DT_RELR commit)
- "preemptable" -> "preemptible", "unpreemptable" -> "non-preemptible"
  for all patches (commit messages & comments)
- Clarify "OOB write", fix a typo, and remove "for DLL [should be DSO] or
  PIE" in the commit message of patch 1: it's not important if the output
  is DSO/PIE or not; even for DSO/PIE the R_LARCH_32 relocs *resolved at
  link time* are perfectly fine and they are massively used in debug
  info.  So the important thing is we cannot leave it unresolved for
  Glibc.
- Reword comment for LARCH_REF_LOCAL in patch 3 to (hopefully) avoid some
  confusion.
- Move the explanation of the test suite from this cover letter to patch
  5 commit message.

Xi Ruoyao (5):
  LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in
    ELFCLASS64
  LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared
    libraries
  LoongArch: Make protected function symbols local for -shared
  LoongArch: Add DT_RELR support
  LoongArch: Add DT_RELR tests

 bfd/elfnn-loongarch.c                         | 652 +++++++++++++++++-
 binutils/testsuite/lib/binutils-common.exp    |   1 +
 ld/emulparams/elf64loongarch.sh               |   1 +
 ld/testsuite/ld-loongarch-elf/ifunc-reloc.d   |  19 +
 ld/testsuite/ld-loongarch-elf/ifunc-reloc.s   |  55 ++
 .../ld-loongarch-elf/ld-loongarch-elf.exp     |  13 +
 .../ld-loongarch-elf/protected-func.d         |   6 +
 .../ld-loongarch-elf/protected-func.s         |  17 +
 .../ld-loongarch-elf/r_larch_32_elf64.d       |   4 +
 .../ld-loongarch-elf/r_larch_32_elf64.s       |   3 +
 ld/testsuite/ld-loongarch-elf/relr-addend.d   |  11 +
 ld/testsuite/ld-loongarch-elf/relr-addend.s   |  17 +
 ld/testsuite/ld-loongarch-elf/relr-align.d    |  22 +
 ld/testsuite/ld-loongarch-elf/relr-align.s    | 106 +++
 ld/testsuite/ld-loongarch-elf/relr-data-pie.d |  18 +
 .../ld-loongarch-elf/relr-data-shared.d       |  18 +
 ld/testsuite/ld-loongarch-elf/relr-data.s     |  71 ++
 .../ld-loongarch-elf/relr-discard-pie.d       |   8 +
 .../ld-loongarch-elf/relr-discard-shared.d    |  11 +
 ld/testsuite/ld-loongarch-elf/relr-discard.ld |  13 +
 ld/testsuite/ld-loongarch-elf/relr-discard.s  |  61 ++
 ld/testsuite/ld-loongarch-elf/relr-got-pie.d  |  15 +
 .../ld-loongarch-elf/relr-got-shared.d        |  15 +
 ld/testsuite/ld-loongarch-elf/relr-got.s      |  27 +
 ld/testsuite/ld-loongarch-elf/relr-relocs.ld  |  24 +
 ld/testsuite/ld-loongarch-elf/relr-text-pie.d |  14 +
 .../ld-loongarch-elf/relr-text-shared.d       |  14 +
 ld/testsuite/ld-loongarch-elf/relr-text.s     |  10 +
 28 files changed, 1213 insertions(+), 33 deletions(-)
 create mode 100644 ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/ifunc-reloc.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/protected-func.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/protected-func.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-addend.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-addend.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-align.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-align.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-data-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-data-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-data.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard.ld
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-got-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-got-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-got.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-relocs.ld
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-text-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-text-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-text.s

-- 
2.45.2


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

* [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-26 10:04 [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support Xi Ruoyao
@ 2024-06-26 10:04 ` Xi Ruoyao
  2024-06-27 10:58   ` Jinyang He
  2024-06-26 10:04 ` [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries Xi Ruoyao
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-26 10:04 UTC (permalink / raw)
  To: binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy, Xi Ruoyao

We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:

    $ cat t.s
    .data
    x:
        .4byte x
	.4byte 0xdeadbeef
    $ as/as-new t.s -o t.o
    $ ld/ld-new -shared t.o
    $ objdump -R
    a.out:     file format elf64-loongarch

    DYNAMIC RELOCATION RECORDS
    OFFSET           TYPE              VALUE
    00000000000001a8 R_LARCH_RELATIVE  *ABS*+0x00000000000001a8

But this is just wrong: at runtime the dynamic linker will run
*(uintptr *)&x += load_address, clobbering the next 4 bytes of data
("0xdeadbeef" in the example).

If we keep the R_LARCH_32 reloc as-is in ELFCLASS64, it'll be rejected
by the Glibc dynamic linker anyway.  And it does not make too much sense
to modify Glibc to support it.  So we can just reject it like x86_64:

    relocation R_X86_64_32 against `.data' can not be used when making a
    shared object; recompile with -fPIC

or RISC-V:

    relocation R_RISCV_32 against non-absolute symbol `a local symbol'
    can not be used in RV64 when making a shared object"

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 bfd/elfnn-loongarch.c                         | 23 ++++++++++++++++++-
 .../ld-loongarch-elf/ld-loongarch-elf.exp     |  1 +
 .../ld-loongarch-elf/r_larch_32_elf64.d       |  4 ++++
 .../ld-loongarch-elf/r_larch_32_elf64.s       |  3 +++
 4 files changed, 30 insertions(+), 1 deletion(-)
 create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index b1720760475..3a55ac93e20 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 	      /* No alloc space of func allocate_dynrelocs.  */
 	      if (unresolved_reloc
 		  && !(h && (h->is_weakalias || !h->dyn_relocs)))
-		loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
+		{
+		  if (is_pic && r_type != R_LARCH_NN)
+		    {
+		      /* Not to use ELFCLASSNN in string literal or it'll
+			 puzzle gettext.  */
+
+		      /* xgettext:c-format  */
+		      char *msg = bfd_asprintf (
+			_("reloc is unresolved and cannot be turned to "
+			  "a runtime reloc in ELFCLASS%d"),
+			NN);
+
+		      /* loongarch_reloc_is_fatal will output
+			 "R_LARCH_32" or "R_LARCH_64" for us.  */
+		      fatal = loongarch_reloc_is_fatal (
+			info, input_bfd, input_section, rel, howto,
+			bfd_reloc_notsupported, is_undefweak, name, msg);
+		    }
+		  else
+		    loongarch_elf_append_rela (output_bfd, sreloc,
+					       &outrel);
+		}
 	    }
 
 	  relocation += rel->r_addend;
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 2d67c4f2668..4d9f4aebaff 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -132,6 +132,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "reloc_le_with_shared"
     run_dump_test "reloc_ler_with_shared"
     run_dump_test "reloc_abs_with_shared"
+    run_dump_test "r_larch_32_elf64"
   }
 
   if [check_pie_support] {
diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
new file mode 100644
index 00000000000..df61f3a36c5
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
@@ -0,0 +1,4 @@
+#name: R_LARCH_32 in ELFCLASS64
+#source: r_larch_32_elf64.s
+#ld: -shared -melf64loongarch
+#error: R_LARCH_32 against `x':\nreloc is unresolved and cannot be turned to a runtime reloc in ELFCLASS64
diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
new file mode 100644
index 00000000000..6649f2bce01
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
@@ -0,0 +1,3 @@
+.data
+x:
+	.4byte x
-- 
2.45.2


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

* [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries
  2024-06-26 10:04 [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support Xi Ruoyao
  2024-06-26 10:04 ` [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64 Xi Ruoyao
@ 2024-06-26 10:04 ` Xi Ruoyao
  2024-06-28  9:40   ` Jinyang He
  2024-06-26 10:04 ` [PATCH v2 3/5] LoongArch: Make protected function symbols local for -shared Xi Ruoyao
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-26 10:04 UTC (permalink / raw)
  To: binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy, Xi Ruoyao

With a simple test case:

    .globl  ifunc
    .globl  ifunc_hidden
    .hidden ifunc_hidden
    .type   ifunc, %gnu_indirect_function
    .type   ifunc_hidden, %gnu_indirect_function

    .text
    .align  2
    ifunc:  ret
    ifunc_hidden: ret

    test:
      bl ifunc
      bl ifunc_hidden

"ld -shared" produces a shared object with one R_LARCH_NONE (instead of
R_LARCH_JUMP_SLOT as we expect) to relocate the GOT entry of "ifunc".
It's because the indices in .plt and .rela.plt mismatches for
STV_DEFAULT STT_IFUNC symbols when another PLT entry exists for a
STV_HIDDEN STT_IFUNC symbol, and such a mismatch breaks the logic of
loongarch_elf_finish_dynamic_symbol.  Fix the issue by reordering .plt
so the indices no longer mismatch.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 bfd/elfnn-loongarch.c                         | 77 ++++++++++++++++---
 ld/testsuite/ld-loongarch-elf/ifunc-reloc.d   | 19 +++++
 ld/testsuite/ld-loongarch-elf/ifunc-reloc.s   | 55 +++++++++++++
 .../ld-loongarch-elf/ld-loongarch-elf.exp     |  1 +
 4 files changed, 140 insertions(+), 12 deletions(-)
 create mode 100644 ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/ifunc-reloc.s

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 3a55ac93e20..c02e3f4bd9c 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -1691,9 +1691,10 @@ local_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
    ifunc dynamic relocs.  */
 
 static bool
-elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
+elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
+				struct bfd_link_info *info,
+				bool ref_local)
 {
-  struct bfd_link_info *info;
   /* An example of a bfd_link_hash_indirect symbol is versioned
      symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
      -> __gxx_personality_v0(bfd_link_hash_defined)
@@ -1709,20 +1710,18 @@ elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   if (h->root.type == bfd_link_hash_warning)
     h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-  info = (struct bfd_link_info *) inf;
-
   /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC && h->def_regular)
     {
-      if (SYMBOL_REFERENCES_LOCAL (info, h))
+      if (ref_local && SYMBOL_REFERENCES_LOCAL (info, h))
 	return local_allocate_ifunc_dyn_relocs (info, h,
 						&h->dyn_relocs,
 						PLT_ENTRY_SIZE,
 						PLT_HEADER_SIZE,
 						GOT_ENTRY_SIZE,
 						false);
-      else
+      else if (!ref_local && !SYMBOL_REFERENCES_LOCAL (info, h))
 	return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
 						   &h->dyn_relocs,
 						   PLT_ENTRY_SIZE,
@@ -1734,6 +1733,23 @@ elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   return true;
 }
 
+static bool
+elfNN_allocate_ifunc_dynrelocs_ref_local (struct elf_link_hash_entry *h,
+					  void *info)
+{
+  return elfNN_allocate_ifunc_dynrelocs (h, (struct bfd_link_info *) info,
+					 true);
+}
+
+static bool
+elfNN_allocate_ifunc_dynrelocs_ref_global (struct elf_link_hash_entry *h,
+					   void *info)
+{
+  return elfNN_allocate_ifunc_dynrelocs (h, (struct bfd_link_info *) info,
+					 false);
+}
+
+
 /* Allocate space in .plt, .got and associated reloc sections for
    ifunc dynamic relocs.  */
 
@@ -1749,7 +1765,7 @@ elfNN_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
       || h->root.type != bfd_link_hash_defined)
     abort ();
 
-  return elfNN_allocate_ifunc_dynrelocs (h, inf);
+  return elfNN_allocate_ifunc_dynrelocs_ref_local (h, inf);
 }
 
 /* Set DF_TEXTREL if we find any dynamic relocs that apply to
@@ -1909,11 +1925,48 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
      sym dynamic relocs.  */
   elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
 
-  /* Allocate global ifunc sym .plt and .got entries, and space for global
-     ifunc sym dynamic relocs.  */
-  elf_link_hash_traverse (&htab->elf, elfNN_allocate_ifunc_dynrelocs, info);
-
-  /* Allocate .plt and .got entries, and space for local ifunc symbols.  */
+  /* Allocate global ifunc sym .plt and .got entries, and space for
+     *preemptible* ifunc sym dynamic relocs.  Note that we must do it
+     for *all* preemptible ifunc (including local ifuncs and STV_HIDDEN
+     ifuncs) before doing it for any non-preemptible ifunc symbol:
+     assuming we are not so careful, when we link a shared library the
+     correlation of .plt and .rela.plt might look like:
+
+				idx in .plt	idx in .rela.plt
+	ext_func1@plt		0		0
+	ext_func2@plt		1		1
+	ext_func3@plt		2		2
+	hidden_ifunc1@plt	3		None: it's in .rela.got
+	hidden_ifunc2@plt	4		None: it's in .rela.got
+	normal_ifunc1@plt	5	!=	3
+	normal_ifunc2@plt	6	!=	4
+	local_ifunc@plt		7		None: it's in .rela.got
+
+     Now oops the indices for normal_ifunc{1,2} in .rela.plt were different
+     from the indices in .plt :(.  This would break finish_dynamic_symbol
+     which assumes the index in .rela.plt matches the index in .plt.
+
+     So let's be careful and make it correct:
+
+				idx in .plt	idx in .rela.plt
+	ext_func1@plt		0		0
+	ext_func2@plt		1		1
+	ext_func3@plt		2		2
+	normal_ifunc1@plt	3		3
+	normal_ifunc2@plt	4		4
+	hidden_ifunc1@plt	5		None: it's in .rela.got
+	hidden_ifunc2@plt	6		None: it's in .rela.got
+	local_ifunc@plt		7		None: it's in .rela.got
+
+     Now normal_ifuncs first.  */
+  elf_link_hash_traverse (&htab->elf,
+			  elfNN_allocate_ifunc_dynrelocs_ref_global, info);
+
+  /* Now hidden_ifuncs ifuncs.  */
+  elf_link_hash_traverse (&htab->elf,
+			  elfNN_allocate_ifunc_dynrelocs_ref_local, info);
+
+  /* Finally local ifuncs.  */
   htab_traverse (htab->loc_hash_table,
 		 elfNN_allocate_local_ifunc_dynrelocs, info);
 
diff --git a/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
new file mode 100644
index 00000000000..cb592874b1e
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
@@ -0,0 +1,19 @@
+#ld: -shared
+#readelf: -Wr
+
+#...
+.*'\.rela\.dyn'.*
+#...
+.* R_LARCH_RELATIVE .*
+.* R_LARCH_IRELATIVE .*
+.* R_LARCH_IRELATIVE .*
+.* R_LARCH_IRELATIVE .*
+#...
+.*'\.rela\.plt'.*
+#...
+.* R_LARCH_JUMP_SLOT .*
+.* R_LARCH_JUMP_SLOT .*
+.* R_LARCH_JUMP_SLOT .*
+.* R_LARCH_JUMP_SLOT .*
+.* R_LARCH_JUMP_SLOT .*
+.* R_LARCH_JUMP_SLOT .*
diff --git a/ld/testsuite/ld-loongarch-elf/ifunc-reloc.s b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.s
new file mode 100644
index 00000000000..e59f2b20e36
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.s
@@ -0,0 +1,55 @@
+.globl	foo
+.globl	foo_hidden1
+.globl	foo_hidden2
+.globl	foo_protected
+
+.type	foo, %gnu_indirect_function
+.type	foo_hidden1, %gnu_indirect_function
+.type	foo_hidden2, %gnu_indirect_function
+.type	foo_protected, %gnu_indirect_function
+.type	foo_internal, %gnu_indirect_function
+
+.hidden	foo_hidden1
+.hidden	foo_hidden2
+
+.protected	foo_protected
+
+.globl	ext_ifunc1
+.globl	ext_ifunc2
+.type	ext_ifunc1, %gnu_indirect_function
+.type	ext_ifunc2, %gnu_indirect_function
+
+.text
+.align	2
+foo:
+	ret
+
+foo_hidden1:
+	ret
+
+foo_hidden2:
+	ret
+
+foo_protected:
+	ret
+
+foo_internal:
+	ret
+
+test:
+	la.got	$a0, num
+	# The order is deliberately shuffled.
+	bl	ext_ifunc1
+	bl	foo
+	bl	foo_hidden1
+	bl	ext_func1
+	bl	foo_protected
+	bl	foo_internal
+	bl	foo_hidden2
+	bl	ext_func2
+	bl	ext_ifunc2
+
+.data
+.align	3
+num:
+	.quad	114514
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 4d9f4aebaff..6cff117e29b 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -133,6 +133,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "reloc_ler_with_shared"
     run_dump_test "reloc_abs_with_shared"
     run_dump_test "r_larch_32_elf64"
+    run_dump_test "ifunc-reloc"
   }
 
   if [check_pie_support] {
-- 
2.45.2


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

* [PATCH v2 3/5] LoongArch: Make protected function symbols local for -shared
  2024-06-26 10:04 [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support Xi Ruoyao
  2024-06-26 10:04 ` [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64 Xi Ruoyao
  2024-06-26 10:04 ` [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries Xi Ruoyao
@ 2024-06-26 10:04 ` Xi Ruoyao
  2024-06-26 10:04 ` [PATCH v2 4/5] LoongArch: Add DT_RELR support Xi Ruoyao
  2024-06-26 10:04 ` [PATCH v2 5/5] LoongArch: Add DT_RELR tests Xi Ruoyao
  4 siblings, 0 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-26 10:04 UTC (permalink / raw)
  To: binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy, Xi Ruoyao

On LoongArch there is no reason to treat STV_PROTECTED STT_FUNC symbols
as preemptible.  See the comment above LARCH_REF_LOCAL for detailed
explanation.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 bfd/elfnn-loongarch.c                         | 76 ++++++++++++++-----
 ld/testsuite/ld-loongarch-elf/ifunc-reloc.d   |  2 +-
 .../ld-loongarch-elf/ld-loongarch-elf.exp     |  1 +
 .../ld-loongarch-elf/protected-func.d         |  6 ++
 .../ld-loongarch-elf/protected-func.s         | 17 +++++
 5 files changed, 81 insertions(+), 21 deletions(-)
 create mode 100644 ld/testsuite/ld-loongarch-elf/protected-func.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/protected-func.s

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index c02e3f4bd9c..1a84b88320b 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -181,6 +181,44 @@ struct loongarch_elf_link_hash_table
     } \
     while (0)
 
+/* TL;DR always use it in this file instead when you want to type
+   SYMBOL_REFERENCES_LOCAL.
+
+   It's like SYMBOL_REFERENCES_LOCAL, but it returns true for local
+   protected functions.  It happens to be same as SYMBOL_CALLS_LOCAL but
+   let's not reuse SYMBOL_CALLS_LOCAL or "CALLS" may puzzle people.
+
+   We do generate a PLT entry when someone attempts to la.pcrel an external
+   function.  But we never really implemented "R_LARCH_COPY", thus we've
+   never supported la.pcrel an external symbol unless the loaded address is
+   only used for locating a function to be called.  Thus the PLT entry is
+   a normal PLT entry, not intended to be a so-called "canonical PLT entry"
+   on the ports supporting copy relocation.  So attempting to la.pcrel an
+   external function will just break pointer equality, even it's a
+   STV_DEFAULT function:
+
+   $ cat t.c
+   #include <assert.h>
+   void check(void *p) {assert(p == check);}
+   $ cat main.c
+   extern void check(void *);
+   int main(void) { check(check); }
+   $ cc t.c -fPIC -shared -o t.so
+   $ cc main.c -mdirect-extern-access t.so -Wl,-rpath=. -fpie -pie
+   $ ./a.out
+   a.out: t.c:2: check: Assertion `p == check' failed.
+   Aborted
+
+   Thus handling STV_PROTECTED function specially just fixes nothing:
+   adding -fvisibility=protected compiling t.c will not magically fix
+   the inequality.  The only possible and correct fix is not to use
+   -mdirect-extern-access.
+
+   So we should remove this special handling, because it's only an
+   unsuccessful workaround for invalid code and it's penalizing valid
+   code.  */
+#define LARCH_REF_LOCAL(info, h) \
+  (_bfd_elf_symbol_refs_local_p ((h), (info), true))
 
 /* Generate a PLT header.  */
 
@@ -712,7 +750,7 @@ loongarch_tls_transition_without_check (struct bfd_link_info *info,
 					struct elf_link_hash_entry *h)
 {
   bool local_exec = bfd_link_executable (info)
-		    && SYMBOL_REFERENCES_LOCAL (info, h);
+		    && LARCH_REF_LOCAL (info, h);
 
   switch (r_type)
     {
@@ -1196,7 +1234,7 @@ loongarch_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
     {
       if (h->plt.refcount <= 0
 	  || (h->type != STT_GNU_IFUNC
-	      && (SYMBOL_REFERENCES_LOCAL (info, h)
+	      && (LARCH_REF_LOCAL (info, h)
 		  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
 		      && h->root.type == bfd_link_hash_undefweak))))
 	{
@@ -1714,14 +1752,14 @@ elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
      here if it is defined and referenced in a non-shared object.  */
   if (h->type == STT_GNU_IFUNC && h->def_regular)
     {
-      if (ref_local && SYMBOL_REFERENCES_LOCAL (info, h))
+      if (ref_local && LARCH_REF_LOCAL (info, h))
 	return local_allocate_ifunc_dyn_relocs (info, h,
 						&h->dyn_relocs,
 						PLT_ENTRY_SIZE,
 						PLT_HEADER_SIZE,
 						GOT_ENTRY_SIZE,
 						false);
-      else if (!ref_local && !SYMBOL_REFERENCES_LOCAL (info, h))
+      else if (!ref_local && !LARCH_REF_LOCAL (info, h))
 	return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
 						   &h->dyn_relocs,
 						   PLT_ENTRY_SIZE,
@@ -1749,7 +1787,6 @@ elfNN_allocate_ifunc_dynrelocs_ref_global (struct elf_link_hash_entry *h,
 					 false);
 }
 
-
 /* Allocate space in .plt, .got and associated reloc sections for
    ifunc dynamic relocs.  */
 
@@ -2662,7 +2699,6 @@ tlsoff (struct bfd_link_info *info, bfd_vma addr)
   return addr - elf_hash_table (info)->tls_sec->vma;
 }
 
-
 static int
 loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 				bfd *input_bfd, asection *input_section,
@@ -2788,7 +2824,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 	    {
 	      defined_local = !unresolved_reloc && !ignored;
 	      resolved_local =
-		defined_local && SYMBOL_REFERENCES_LOCAL (info, h);
+		defined_local && LARCH_REF_LOCAL (info, h);
 	      resolved_dynly = !resolved_local;
 	      resolved_to_const = !resolved_local && !resolved_dynly;
 	    }
@@ -2877,7 +2913,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		      outrel.r_addend = 0;
 		    }
 
-		  if (SYMBOL_REFERENCES_LOCAL (info, h))
+		  if (LARCH_REF_LOCAL (info, h))
 		    {
 
 		      if (htab->elf.splt != NULL)
@@ -3246,7 +3282,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		  if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (is_dyn,
 							bfd_link_pic (info), h)
 		      && ((bfd_link_pic (info)
-			   && SYMBOL_REFERENCES_LOCAL (info, h))))
+			   && LARCH_REF_LOCAL (info, h))))
 		    {
 		      /* This is actually a static link, or it is a
 			 -Bsymbolic link and the symbol is defined
@@ -3391,7 +3427,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		asection *srel = htab->elf.srelgot;
 		bfd_vma tls_block_off = 0;
 
-		if (SYMBOL_REFERENCES_LOCAL (info, h))
+		if (LARCH_REF_LOCAL (info, h))
 		  {
 		    BFD_ASSERT (elf_hash_table (info)->tls_sec);
 		    tls_block_off = relocation
@@ -3402,7 +3438,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		  {
 		    rela.r_offset = sec_addr (got) + got_off;
 		    rela.r_addend = 0;
-		    if (SYMBOL_REFERENCES_LOCAL (info, h))
+		    if (LARCH_REF_LOCAL (info, h))
 		      {
 			/* Local sym, used in exec, set module id 1.  */
 			if (bfd_link_executable (info))
@@ -3435,7 +3471,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		if (tls_type & GOT_TLS_IE)
 		  {
 		    rela.r_offset = sec_addr (got) + got_off + ie_off;
-		    if (SYMBOL_REFERENCES_LOCAL (info, h))
+		    if (LARCH_REF_LOCAL (info, h))
 		      {
 			/* Local sym, used in exec, set module id 1.  */
 			if (!bfd_link_executable (info))
@@ -3637,7 +3673,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 							    bfd_link_pic (info),
 							    h)
 			  && bfd_link_pic (info)
-			  && SYMBOL_REFERENCES_LOCAL (info, h))
+			  && LARCH_REF_LOCAL (info, h))
 			{
 			  Elf_Internal_Rela rela;
 			  rela.r_offset = sec_addr (got) + got_off;
@@ -4178,7 +4214,7 @@ loongarch_tls_perform_trans (bfd *abfd, asection *sec,
 {
   unsigned long insn;
   bool local_exec = bfd_link_executable (info)
-		      && SYMBOL_REFERENCES_LOCAL (info, h);
+		      && LARCH_REF_LOCAL (info, h);
   bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
   unsigned long r_type = ELFNN_R_TYPE (rel->r_info);
   unsigned long r_symndx = ELFNN_R_SYM (rel->r_info);
@@ -4890,7 +4926,7 @@ loongarch_elf_relax_section (bfd *abfd, asection *sec,
 	  else
 	    continue;
 
-	  if (h && SYMBOL_REFERENCES_LOCAL (info, h))
+	  if (h && LARCH_REF_LOCAL (info, h))
 	    local_got = true;
 	  symtype = h->type;
 	}
@@ -5027,12 +5063,12 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
       if (htab->elf.splt)
 	{
 	  BFD_ASSERT ((h->type == STT_GNU_IFUNC
-		       && SYMBOL_REFERENCES_LOCAL (info, h))
+		       && LARCH_REF_LOCAL (info, h))
 		      || h->dynindx != -1);
 
 	  plt = htab->elf.splt;
 	  gotplt = htab->elf.sgotplt;
-	  if (h->type == STT_GNU_IFUNC && SYMBOL_REFERENCES_LOCAL (info, h))
+	  if (h->type == STT_GNU_IFUNC && LARCH_REF_LOCAL (info, h))
 	    relplt = htab->elf.srelgot;
 	  else
 	    relplt = htab->elf.srelplt;
@@ -5043,7 +5079,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
       else /* if (htab->elf.iplt) */
 	{
 	  BFD_ASSERT (h->type == STT_GNU_IFUNC
-		      && SYMBOL_REFERENCES_LOCAL (info, h));
+		      && LARCH_REF_LOCAL (info, h));
 
 	  plt = htab->elf.iplt;
 	  gotplt = htab->elf.igotplt;
@@ -5131,7 +5167,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
 	      if (htab->elf.splt == NULL)
 		srela = htab->elf.irelplt;
 
-	      if (SYMBOL_REFERENCES_LOCAL (info, h))
+	      if (LARCH_REF_LOCAL (info, h))
 		{
 		  asection *sec = h->root.u.def.section;
 		  rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
@@ -5168,7 +5204,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
 	      return true;
 	    }
 	}
-      else if (bfd_link_pic (info) && SYMBOL_REFERENCES_LOCAL (info, h))
+      else if (bfd_link_pic (info) && LARCH_REF_LOCAL (info, h))
 	{
 	  asection *sec = h->root.u.def.section;
 	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
diff --git a/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
index cb592874b1e..968e7564b49 100644
--- a/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
+++ b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
@@ -8,6 +8,7 @@
 .* R_LARCH_IRELATIVE .*
 .* R_LARCH_IRELATIVE .*
 .* R_LARCH_IRELATIVE .*
+.* R_LARCH_IRELATIVE .*
 #...
 .*'\.rela\.plt'.*
 #...
@@ -16,4 +17,3 @@
 .* R_LARCH_JUMP_SLOT .*
 .* R_LARCH_JUMP_SLOT .*
 .* R_LARCH_JUMP_SLOT .*
-.* R_LARCH_JUMP_SLOT .*
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 6cff117e29b..9a668fb7164 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -134,6 +134,7 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "reloc_abs_with_shared"
     run_dump_test "r_larch_32_elf64"
     run_dump_test "ifunc-reloc"
+    run_dump_test "protected-func"
   }
 
   if [check_pie_support] {
diff --git a/ld/testsuite/ld-loongarch-elf/protected-func.d b/ld/testsuite/ld-loongarch-elf/protected-func.d
new file mode 100644
index 00000000000..501c7cb5f8c
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/protected-func.d
@@ -0,0 +1,6 @@
+#ld: -shared
+#readelf: -Wr
+
+#...
+.* R_LARCH_RELATIVE .*
+.* R_LARCH_RELATIVE .*
diff --git a/ld/testsuite/ld-loongarch-elf/protected-func.s b/ld/testsuite/ld-loongarch-elf/protected-func.s
new file mode 100644
index 00000000000..8f28f9254a4
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/protected-func.s
@@ -0,0 +1,17 @@
+# protected function should be non-preemptible and relocated with
+# R_LARCH_RELATIVE in shared library, for both GOT and pointer data
+
+.globl x
+.protected x
+.type x, @function
+x:
+  ret
+
+.globl _start
+_start:
+  la.got $a0, x
+  ret
+
+.data
+p:
+  .quad x
-- 
2.45.2


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

* [PATCH v2 4/5] LoongArch: Add DT_RELR support
  2024-06-26 10:04 [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support Xi Ruoyao
                   ` (2 preceding siblings ...)
  2024-06-26 10:04 ` [PATCH v2 3/5] LoongArch: Make protected function symbols local for -shared Xi Ruoyao
@ 2024-06-26 10:04 ` Xi Ruoyao
  2024-06-27  7:21   ` mengqinggang
  2024-06-27  7:27   ` mengqinggang
  2024-06-26 10:04 ` [PATCH v2 5/5] LoongArch: Add DT_RELR tests Xi Ruoyao
  4 siblings, 2 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-26 10:04 UTC (permalink / raw)
  To: binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy, Xi Ruoyao

The logic is same as a71d87680110 ("aarch64: Add DT_RELR support").

As LoongArch does not have -z dynamic-undefined-weak, we don't need to
consider UNDEFWEAK_NO_DYNAMIC_RELOC.

The linker relaxation adds another layer of complexity.  When we delete
bytes in a section during relaxation, we need to fix up the offset in
the to-be-packed relative relocations against this section.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 bfd/elfnn-loongarch.c                      | 482 ++++++++++++++++++++-
 binutils/testsuite/lib/binutils-common.exp |   1 +
 ld/emulparams/elf64loongarch.sh            |   1 +
 3 files changed, 481 insertions(+), 3 deletions(-)

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 1a84b88320b..f501589bc70 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -84,6 +84,12 @@ struct _bfd_loongarch_elf_obj_tdata
    && elf_tdata (bfd) != NULL						\
    && elf_object_id (bfd) == LARCH_ELF_DATA)
 
+struct relr_entry
+{
+  asection *sec;
+  bfd_vma off;
+};
+
 struct loongarch_elf_link_hash_table
 {
   struct elf_link_hash_table elf;
@@ -104,8 +110,50 @@ struct loongarch_elf_link_hash_table
   /* The data segment phase, don't relax the section
      when it is exp_seg_relro_adjust.  */
   int *data_segment_phase;
+
+  /* Array of relative relocs to be emitted in DT_RELR format.  */
+  bfd_size_type relr_alloc;
+  bfd_size_type relr_count;
+  struct relr_entry *relr;
+
+  /* Sorted output addresses of above relative relocs.  */
+  bfd_vma *relr_sorted;
+
+  /* Layout recomputation count.  */
+  bfd_size_type relr_layout_iter;
 };
 
+struct loongarch_elf_section_data
+{
+  struct bfd_elf_section_data elf;
+
+  /* &htab->relr[i] where i is the smallest number s.t.
+     htab->relr[i].sec == &elf.  NULL if there exists no such i.  */
+  struct relr_entry *relr;
+};
+
+/* We need an additional field in elf_section_data to handle complex
+   interactions between DT_RELR and relaxation.  */
+static bool
+loongarch_elf_new_section_hook (bfd *abfd, asection *sec)
+{
+  if (!sec->used_by_bfd)
+    {
+      struct loongarch_elf_section_data *sdata;
+      size_t amt = sizeof (*sdata);
+
+      sdata = bfd_zalloc (abfd, amt);
+      if (!sdata)
+	return false;
+      sec->used_by_bfd = sdata;
+    }
+
+  return _bfd_elf_new_section_hook (abfd, sec);
+}
+
+#define loongarch_elf_section_data(x) \
+  ((struct loongarch_elf_section_data *) elf_section_data (x))
+
 /* Get the LoongArch ELF linker hash table from a link_info structure.  */
 #define loongarch_elf_hash_table(p)					\
   (elf_hash_table_id (elf_hash_table (p)) == LARCH_ELF_DATA		\
@@ -927,6 +975,20 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
       if (rel + 1 != relocs + sec->reloc_count
 	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX)
 	r_type = loongarch_tls_transition (abfd, info, h, r_symndx, r_type);
+
+      /* I don't want to spend time supporting DT_RELR with old object
+	 files doing stack-based relocs.  */
+      if (info->enable_dt_relr
+	  && r_type >= R_LARCH_SOP_PUSH_PCREL
+	  && r_type <= R_LARCH_SOP_POP_32_U)
+	{
+	  /* xgettext:c-format */
+	  _bfd_error_handler (_("%pB: stack based reloc type (%u) is not "
+				"supported with -z pack-relative-relocs"),
+			      abfd, r_type);
+	  return false;
+	}
+
       switch (r_type)
 	{
 	case R_LARCH_GOT_PC_HI20:
@@ -1118,6 +1180,20 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	    return false;
 	  break;
 
+	case R_LARCH_ALIGN:
+	  /* Check against irrational R_LARCH_ALIGN relocs which may cause
+	     removing an odd number of bytes and disrupt DT_RELR.  */
+	  if (rel->r_offset % 4 != 0)
+	    {
+	      /* xgettext:c-format */
+	      _bfd_error_handler (
+		_("%pB: R_LARCH_ALIGN with offset %" PRId64 " not aligned "
+		  "to instruction boundary"),
+		abfd, (uint64_t) rel->r_offset);
+	      return false;
+	    }
+	  break;
+
 	default:
 	  break;
 	}
@@ -1832,6 +1908,342 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
   return true;
 }
 
+static bool
+record_relr (struct loongarch_elf_link_hash_table *htab, asection *sec,
+	     bfd_vma off, asection *sreloc)
+{
+  struct relr_entry **sec_relr = &loongarch_elf_section_data (sec)->relr;
+
+  /* Undo the relocation section size accounting.  */
+  BFD_ASSERT (sreloc->size >= sizeof (ElfNN_External_Rela));
+  sreloc->size -= sizeof (ElfNN_External_Rela);
+
+  BFD_ASSERT (off % 2 == 0 && sec->alignment_power > 0);
+  if (htab->relr_count >= htab->relr_alloc)
+    {
+      if (htab->relr_alloc == 0)
+	htab->relr_alloc = 4096;
+      else
+	htab->relr_alloc *= 2;
+
+      htab->relr = bfd_realloc (htab->relr,
+				htab->relr_alloc * sizeof (*htab->relr));
+      if (!htab->relr)
+	return false;
+    }
+  htab->relr[htab->relr_count].sec = sec;
+  htab->relr[htab->relr_count].off = off;
+  if (*sec_relr == NULL)
+    *sec_relr = &htab->relr[htab->relr_count];
+  htab->relr_count++;
+  return true;
+}
+
+static bool
+record_relr_local_got_relocs (bfd *input_bfd, struct bfd_link_info *info)
+{
+  bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd);
+  char *local_tls_type = _bfd_loongarch_elf_local_got_tls_type (input_bfd);
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
+  struct loongarch_elf_link_hash_table *htab =
+    loongarch_elf_hash_table (info);
+
+  if (!local_got_offsets || !local_tls_type || !bfd_link_pic (info))
+    return true;
+
+  for (unsigned i = 0; i < symtab_hdr->sh_info; i++)
+    {
+      bfd_vma off = local_got_offsets[i];
+
+      /* FIXME: If the local symbol is in SHN_ABS then emitting
+	 a relative relocation is not correct, but it seems to be wrong
+	 in loongarch_elf_relocate_section too.  */
+      if (local_tls_type[i] == GOT_NORMAL
+	  && !record_relr (htab, htab->elf.sgot, off, htab->elf.srelgot))
+	return false;
+    }
+
+  return true;
+}
+
+static bool
+record_relr_dyn_got_relocs (struct elf_link_hash_entry *h, void *inf)
+{
+  struct bfd_link_info *info = (struct bfd_link_info *) inf;
+  struct loongarch_elf_link_hash_table *htab =
+    loongarch_elf_hash_table (info);
+
+  if (h->root.type == bfd_link_hash_indirect)
+    return true;
+  if (h->type == STT_GNU_IFUNC && h->def_regular)
+    return true;
+  if (h->got.refcount <= 0)
+    return true;
+  if (loongarch_elf_hash_entry (h)->tls_type
+      & (GOT_TLS_GD | GOT_TLS_IE | GOT_TLS_GDESC))
+    return true;
+  if (!bfd_link_pic (info))
+    return true;
+
+  /* On LoongArch a GOT entry for undefined weak symbol is never relocated
+     with R_LARCH_RELATIVE: we don't have -z dynamic-undefined-weak, thus
+     the GOT entry is either const 0 (if the symbol is LARCH_REF_LOCAL) or
+     relocated with R_LARCH_NN (otherwise).  */
+  if (h->root.type == bfd_link_hash_undefweak)
+    return true;
+
+  if (!LARCH_REF_LOCAL (info, h))
+    return true;
+  if (bfd_is_abs_symbol (&h->root))
+    return true;
+
+  if (!record_relr (htab, htab->elf.sgot, h->got.offset,
+		    htab->elf.srelgot))
+    return false;
+
+  return true;
+}
+
+static bool
+record_relr_non_got_relocs (bfd *input_bfd, struct bfd_link_info *info,
+			    asection *sec)
+{
+  asection *sreloc;
+  struct loongarch_elf_link_hash_table *htab;
+  Elf_Internal_Rela *relocs, *rel, *rel_end;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+
+  if (!bfd_link_pic (info))
+    return true;
+  if (sec->reloc_count == 0)
+    return true;
+  if ((sec->flags & (SEC_RELOC | SEC_ALLOC | SEC_DEBUGGING))
+       != (SEC_RELOC | SEC_ALLOC))
+    return true;
+  if (sec->alignment_power == 0)
+    return true;
+  if (discarded_section (sec))
+    return true;
+
+  sreloc = elf_section_data (sec)->sreloc;
+  if (sreloc == NULL)
+    return true;
+
+  htab = loongarch_elf_hash_table (info);
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
+  sym_hashes = elf_sym_hashes (input_bfd);
+  relocs = _bfd_elf_link_info_read_relocs (input_bfd, info, sec, NULL,
+					   NULL, info->keep_memory);
+  BFD_ASSERT (relocs != NULL);
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned r_symndx = ELFNN_R_SYM (rel->r_info);
+      struct elf_link_hash_entry *h = NULL;
+      asection *def_sec = NULL;
+
+      if (ELFNN_R_TYPE (rel->r_info) != R_LARCH_NN
+	  || rel->r_offset % 2 != 0)
+	continue;
+
+      /* The logical below must match loongarch_elf_relocate_section.  */
+      if (r_symndx < symtab_hdr->sh_info)
+	{
+	  /* A local symbol.  */
+	  Elf_Internal_Sym *isym;
+	  isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, input_bfd,
+					r_symndx);
+	  BFD_ASSERT(isym != NULL);
+
+	  /* Local STT_GNU_IFUNC symbol uses R_LARCH_IRELATIVE for
+	     R_LARCH_NN, not R_LARCH_RELATIVE.  */
+	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+	    continue;
+	  def_sec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
+	}
+      else
+	{
+	  h = sym_hashes[r_symndx - symtab_hdr->sh_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;
+
+	  /* Filter out symbols that cannot have a relative reloc.  */
+	  if (h->dyn_relocs == NULL)
+	    continue;
+	  if (bfd_is_abs_symbol (&h->root))
+	    continue;
+	  if (h->type == STT_GNU_IFUNC)
+	    continue;
+
+	  if (h->root.type == bfd_link_hash_defined
+	      || h->root.type == bfd_link_hash_defweak)
+	    def_sec = h->root.u.def.section;
+
+	  /* On LoongArch an R_LARCH_NN against undefined weak symbol
+	     is never converted to R_LARCH_RELATIVE: we don't have
+	     -z dynamic-undefined-weak, thus the reloc is either removed
+	     (if the symbol is LARCH_REF_LOCAL) or kept (otherwise).  */
+	  if (h->root.type == bfd_link_hash_undefweak)
+	    continue;
+
+	  if (!LARCH_REF_LOCAL (info, h))
+	    continue;
+	}
+
+      if (!def_sec || discarded_section (def_sec))
+	continue;
+
+      if (!record_relr (htab, sec, rel->r_offset, sreloc))
+	return false;
+    }
+
+  return true;
+}
+
+static int
+cmp_relr_addr (const void *p, const void *q)
+{
+  const bfd_vma *a = p, *b = q;
+  return (*a > *b) - (*a < *b);
+}
+
+static bool
+sort_relr (struct bfd_link_info *info,
+	   struct loongarch_elf_link_hash_table *htab)
+{
+  if (htab->relr_count == 0)
+    return true;
+
+  bfd_vma *addr = htab->relr_sorted;
+  if (!addr)
+    {
+      addr = bfd_malloc (htab->relr_count * sizeof (*addr));
+      if (!addr)
+	return false;
+      htab->relr_sorted = addr;
+    }
+
+  for (bfd_size_type i = 0; i < htab->relr_count; i++)
+    {
+      bfd_vma off = _bfd_elf_section_offset (info->output_bfd, info,
+					     htab->relr[i].sec,
+					     htab->relr[i].off);
+      addr[i] = htab->relr[i].sec->output_section->vma
+		+ htab->relr[i].sec->output_offset + off;
+    }
+  qsort(addr, htab->relr_count, sizeof (*addr), cmp_relr_addr);
+  return true;
+}
+
+static bool
+loongarch_elf_size_relative_relocs (struct bfd_link_info *info,
+				    bool *need_layout)
+{
+  struct loongarch_elf_link_hash_table *htab =
+    loongarch_elf_hash_table (info);
+  asection *srelrdyn = htab->elf.srelrdyn;
+
+  *need_layout = false;
+
+  if (!sort_relr (info, htab))
+    return false;
+  bfd_vma *addr = htab->relr_sorted;
+
+  BFD_ASSERT (srelrdyn != NULL);
+  bfd_size_type oldsize = srelrdyn->size;
+  srelrdyn->size = 0;
+  for (bfd_size_type i = 0; i < htab->relr_count; )
+    {
+      bfd_vma base = addr[i];
+      i++;
+      srelrdyn->size += NN / 8;
+      base += NN / 8;
+      while (1)
+	{
+	  bfd_size_type start_i = i;
+	  while (i < htab->relr_count
+		 && addr[i] - base < (NN - 1) * (NN / 8)
+		 && (addr[i] - base) % (NN / 8) == 0)
+	    i++;
+	  if (i == start_i)
+	    break;
+	  srelrdyn->size += NN / 8;
+	  base += (NN - 1) * (NN / 8);
+	}
+    }
+  if (srelrdyn->size != oldsize)
+    {
+      *need_layout = true;
+      /* Stop after a few iterations in case the layout does not converge,
+	 but we can only stop when the size would shrink (and pad the
+	 spare space with 1.  */
+      if (htab->relr_layout_iter++ > 5 && srelrdyn->size < oldsize)
+	{
+	  srelrdyn->size = oldsize;
+	  *need_layout = false;
+	}
+    }
+  return true;
+}
+
+static bool
+loongarch_elf_finish_relative_relocs (struct bfd_link_info *info)
+{
+  struct loongarch_elf_link_hash_table *htab =
+    loongarch_elf_hash_table (info);
+  asection *srelrdyn = htab->elf.srelrdyn;
+  bfd *dynobj = htab->elf.dynobj;
+
+  if (!srelrdyn || srelrdyn->size == 0)
+    return true;
+
+  srelrdyn->contents = bfd_alloc (dynobj, srelrdyn->size);
+  if (!srelrdyn->contents)
+    return false;
+
+  bfd_vma *addr = htab->relr_sorted;
+  bfd_byte *loc = srelrdyn->contents;
+  for (bfd_size_type i = 0; i < htab->relr_count; )
+    {
+      bfd_vma base = addr[i];
+      i++;
+      bfd_put_NN (dynobj, base, loc);
+      loc += NN / 8;
+      base += NN / 8;
+      while (1)
+	{
+	  uintNN_t bits = 0;
+	  while (i < htab->relr_count)
+	    {
+	      bfd_vma delta = addr[i] - base;
+	      if (delta >= (NN - 1) * (NN / 8) || delta % (NN / 8) != 0)
+		break;
+	      bits |= (uintNN_t) 1 << (delta / (NN / 8));
+	      i++;
+	    }
+	  if (bits == 0)
+	    break;
+	  bfd_put_NN (dynobj, (bits << 1) | 1, loc);
+	  loc += NN / 8;
+	  base += (NN - 1) * (NN / 8);
+	}
+    }
+
+  free (addr);
+  htab->relr_sorted = NULL;
+
+  /* Pad any excess with 1's, a do-nothing encoding.  */
+  while (loc < srelrdyn->contents + srelrdyn->size)
+    {
+      bfd_put_NN (dynobj, 1, loc);
+      loc += NN / 8;
+    }
+
+  return true;
+}
+
 static bool
 loongarch_elf_late_size_sections (bfd *output_bfd,
 				  struct bfd_link_info *info)
@@ -2012,6 +2424,24 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
       && (htab->elf.splt == NULL || htab->elf.splt->size == 0))
     htab->elf.sgotplt->size = 0;
 
+  if (info->enable_dt_relr && !bfd_link_relocatable (info))
+    {
+      elf_link_hash_traverse (&htab->elf, record_relr_dyn_got_relocs, info);
+
+      for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
+	{
+	  if (!is_loongarch_elf (ibfd))
+	    continue;
+
+	  for (s = ibfd->sections; s != NULL; s = s->next)
+	    if (!record_relr_non_got_relocs (ibfd, info, s))
+	      return false;
+
+	  if (!record_relr_local_got_relocs (ibfd, info))
+	    return false;
+	}
+    }
+
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
@@ -2036,6 +2466,14 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
 	      s->reloc_count = 0;
 	    }
 	}
+      else if (s == htab->elf.srelrdyn && htab->relr_count == 0)
+	{
+	  /* Remove .relr.dyn based on relr_count, not size, since
+	     it is not sized yet.  */
+	    s->flags |= SEC_EXCLUDE;
+	  /* Allocate contents later.  */
+	    continue;
+	}
       else
 	{
 	  /* It's not one of our sections.  */
@@ -2968,6 +3406,17 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 			info, input_bfd, input_section, rel, howto,
 			bfd_reloc_notsupported, is_undefweak, name, msg);
 		    }
+		  else if (info->enable_dt_relr
+			   && (ELFNN_R_TYPE (outrel.r_info)
+			       == R_LARCH_RELATIVE)
+			   && input_section->alignment_power != 0
+			   && rel->r_offset % 2 == 0)
+		    /* Don't emit a relative relocation that is packed,
+		       only apply the addend (as if we are applying the
+		       original R_LARCH_NN reloc in a PDE).  */
+		    r = perform_relocation (rel, input_section, howto,
+					    relocation, input_bfd,
+					    contents);
 		  else
 		    loongarch_elf_append_rela (output_bfd, sreloc,
 					       &outrel);
@@ -3695,7 +4144,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		  got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1);
 		  if ((local_got_offsets[r_symndx] & 1) == 0)
 		    {
-		      if (bfd_link_pic (info))
+		      if (bfd_link_pic (info) && !info->enable_dt_relr)
 			{
 			  Elf_Internal_Rela rela;
 			  rela.r_offset = sec_addr (got) + got_off;
@@ -4107,6 +4556,14 @@ loongarch_relax_delete_bytes (bfd *abfd,
   unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
   struct bfd_elf_section_data *data = elf_section_data (sec);
   bfd_byte *contents = data->this_hdr.contents;
+  struct relr_entry *relr =
+    ((struct loongarch_elf_section_data *)elf_section_data (sec))->relr;
+  struct loongarch_elf_link_hash_table *htab =
+    loongarch_elf_hash_table (link_info);
+  struct relr_entry *relr_end = NULL;
+
+  if (htab->relr_count)
+    relr_end = htab->relr + htab->relr_count;
 
   /* Actually delete the bytes.  */
   sec->size -= count;
@@ -4119,6 +4576,11 @@ loongarch_relax_delete_bytes (bfd *abfd,
     if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr)
       data->relocs[i].r_offset -= count;
 
+  /* Likewise for relative relocs to be packed into .relr.  */
+  for (; relr && relr < relr_end && relr->sec == sec; relr++)
+    if (relr->off > addr && relr->off < toaddr)
+      relr->off -= count;
+
   /* Adjust the local symbols defined in this section.  */
   for (i = 0; i < symtab_hdr->sh_info; i++)
     {
@@ -5207,9 +5669,18 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
       else if (bfd_link_pic (info) && LARCH_REF_LOCAL (info, h))
 	{
 	  asection *sec = h->root.u.def.section;
+	  bfd_vma linkaddr = h->root.u.def.value + sec->output_section->vma
+			     + sec->output_offset;
+
+	  /* Don't emit relative relocs if they are packed, but we need
+	     to write the addend (link-time addr) into the GOT then.  */
+	  if (info->enable_dt_relr)
+	    {
+	      bfd_put_NN (output_bfd, linkaddr, sgot->contents + off);
+	      goto skip_got_reloc;
+	    }
 	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
-	  rela.r_addend = (h->root.u.def.value + sec->output_section->vma
-			   + sec->output_offset);
+	  rela.r_addend = linkaddr;
 	}
       else
 	{
@@ -5220,6 +5691,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
 
       loongarch_elf_append_rela (output_bfd, srela, &rela);
     }
+skip_got_reloc:
 
   /* Mark some specially defined symbols as absolute.  */
   if (h == htab->elf.hdynamic || h == htab->elf.hgot || h == htab->elf.hplt)
@@ -5673,6 +6145,10 @@ elf_loongarch64_hash_symbol (struct elf_link_hash_entry *h)
 #define elf_backend_grok_psinfo loongarch_elf_grok_psinfo
 #define elf_backend_hash_symbol elf_loongarch64_hash_symbol
 #define bfd_elfNN_bfd_relax_section loongarch_elf_relax_section
+#define elf_backend_size_relative_relocs loongarch_elf_size_relative_relocs
+#define elf_backend_finish_relative_relocs \
+  loongarch_elf_finish_relative_relocs
+#define bfd_elfNN_new_section_hook loongarch_elf_new_section_hook
 
 #define elf_backend_dtrel_excludes_plt 1
 
diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
index f0136577b6c..ce7413a77e5 100644
--- a/binutils/testsuite/lib/binutils-common.exp
+++ b/binutils/testsuite/lib/binutils-common.exp
@@ -474,6 +474,7 @@ proc supports_dt_relr {} {
 	  || [istarget i?86-*-*]
 	  || [istarget powerpc64*-*-*]
 	  || [istarget aarch64*-*-*])
+	  || [istarget loongarch64*-*-*]
 	 && ([istarget *-*-linux*]
 	     || [istarget *-*-gnu*]) } {
 	return 1
diff --git a/ld/emulparams/elf64loongarch.sh b/ld/emulparams/elf64loongarch.sh
index d7b2229e213..8c805da987e 100644
--- a/ld/emulparams/elf64loongarch.sh
+++ b/ld/emulparams/elf64loongarch.sh
@@ -1,4 +1,5 @@
 source_sh ${srcdir}/emulparams/elf64loongarch-defs.sh
+source_sh ${srcdir}/emulparams/dt-relr.sh
 OUTPUT_FORMAT="elf64-loongarch"
 
 case "$target" in
-- 
2.45.2


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

* [PATCH v2 5/5] LoongArch: Add DT_RELR tests
  2024-06-26 10:04 [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support Xi Ruoyao
                   ` (3 preceding siblings ...)
  2024-06-26 10:04 ` [PATCH v2 4/5] LoongArch: Add DT_RELR support Xi Ruoyao
@ 2024-06-26 10:04 ` Xi Ruoyao
  2024-06-27  7:11   ` mengqinggang
  4 siblings, 1 reply; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-26 10:04 UTC (permalink / raw)
  To: binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy, Xi Ruoyao

Most tests are ported from AArch64.

The relr-addend test is added to make sure the addend (link-time address)
is correctly written into the relocated section.  Doing so is not
strictly needed for RELA, but strictly needed for RELR).

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
 .../ld-loongarch-elf/ld-loongarch-elf.exp     |  10 ++
 ld/testsuite/ld-loongarch-elf/relr-addend.d   |  11 ++
 ld/testsuite/ld-loongarch-elf/relr-addend.s   |  17 +++
 ld/testsuite/ld-loongarch-elf/relr-align.d    |  22 ++++
 ld/testsuite/ld-loongarch-elf/relr-align.s    | 106 ++++++++++++++++++
 ld/testsuite/ld-loongarch-elf/relr-data-pie.d |  18 +++
 .../ld-loongarch-elf/relr-data-shared.d       |  18 +++
 ld/testsuite/ld-loongarch-elf/relr-data.s     |  71 ++++++++++++
 .../ld-loongarch-elf/relr-discard-pie.d       |   8 ++
 .../ld-loongarch-elf/relr-discard-shared.d    |  11 ++
 ld/testsuite/ld-loongarch-elf/relr-discard.ld |  13 +++
 ld/testsuite/ld-loongarch-elf/relr-discard.s  |  61 ++++++++++
 ld/testsuite/ld-loongarch-elf/relr-got-pie.d  |  15 +++
 .../ld-loongarch-elf/relr-got-shared.d        |  15 +++
 ld/testsuite/ld-loongarch-elf/relr-got.s      |  27 +++++
 ld/testsuite/ld-loongarch-elf/relr-relocs.ld  |  24 ++++
 ld/testsuite/ld-loongarch-elf/relr-text-pie.d |  14 +++
 .../ld-loongarch-elf/relr-text-shared.d       |  14 +++
 ld/testsuite/ld-loongarch-elf/relr-text.s     |  10 ++
 19 files changed, 485 insertions(+)
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-addend.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-addend.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-align.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-align.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-data-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-data-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-data.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard.ld
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-discard.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-got-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-got-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-got.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-relocs.ld
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-text-pie.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-text-shared.d
 create mode 100644 ld/testsuite/ld-loongarch-elf/relr-text.s

diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index 9a668fb7164..4606ede9fc0 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -135,10 +135,20 @@ if [istarget "loongarch64-*-*"] {
     run_dump_test "r_larch_32_elf64"
     run_dump_test "ifunc-reloc"
     run_dump_test "protected-func"
+    run_dump_test "relr-addend"
+    run_dump_test "relr-align"
+    run_dump_test "relr-data-shared"
+    run_dump_test "relr-discard-shared"
+    run_dump_test "relr-got-shared"
+    run_dump_test "relr-text-shared"
   }
 
   if [check_pie_support] {
     run_dump_test "pie_discard"
+    run_dump_test "relr-data-pie"
+    run_dump_test "relr-discard-pie"
+    run_dump_test "relr-got-pie"
+    run_dump_test "relr-text-pie"
   }
 
   run_dump_test "max_imm_b16"
diff --git a/ld/testsuite/ld-loongarch-elf/relr-addend.d b/ld/testsuite/ld-loongarch-elf/relr-addend.d
new file mode 100644
index 00000000000..da13c2cf823
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-addend.d
@@ -0,0 +1,11 @@
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#objdump: -s -j.got -j.data
+
+.*:     file format elf64-loongarch
+
+Contents of section \.got:
+ 20000 [0-9a-f]+ [0-9a-f]+ 00003412 00000000  .*
+ 20010 08003412 00000000                    .*
+Contents of section \.data:
+ 12340000 14451100 00000000 10989101 00000000  .*
+ 12340010 00003412 00000000 08003412 00000000  .*
diff --git a/ld/testsuite/ld-loongarch-elf/relr-addend.s b/ld/testsuite/ld-loongarch-elf/relr-addend.s
new file mode 100644
index 00000000000..3d08f6ca0ae
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-addend.s
@@ -0,0 +1,17 @@
+.data
+.align	8
+x:
+	.quad	0x114514
+y:
+	.quad	0x1919810
+px:
+	.quad	x
+py:
+	.quad	y
+
+.text
+.align	2
+_start:
+	la.got	$a0, x
+	la.got	$a1, y
+	ret
diff --git a/ld/testsuite/ld-loongarch-elf/relr-align.d b/ld/testsuite/ld-loongarch-elf/relr-align.d
new file mode 100644
index 00000000000..d534243b2a5
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-align.d
@@ -0,0 +1,22 @@
+#source: relr-align.s
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -rW
+
+Relocation section '\.rela.dyn' at offset 0x[0-9a-f]+ contains 3 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0000000012340011  0000000000000003 R_LARCH_RELATIVE                          10000
+0000000012340019  0000000000000003 R_LARCH_RELATIVE                          10000
+0000000012340041  0000000000000003 R_LARCH_RELATIVE                          10000
+
+Relocation section '\.relr.dyn' at offset 0x[0-9a-f]+ contains 9 entries which relocate 10 locations:
+Index: Entry            Address           Symbolic Address
+0000:  0000000012340000 0000000012340000  double_0
+0001:  0000000000000003 0000000012340008  double_0 \+ 0x8
+0002:  0000000012340022 0000000012340022  double_2
+0003:  0000000000000003 000000001234002a  double_2 \+ 0x8
+0004:  0000000012340038 0000000012340038  single_0
+0005:  000000001234004a 000000001234004a  single_2
+0006:  0000000012340058 0000000012340058  big
+0007:  8000000100000001 0000000012340158  big \+ 0x100
+                        0000000012340250  big \+ 0x1f8
+0008:  0000000000000003 0000000012340258  big \+ 0x200
diff --git a/ld/testsuite/ld-loongarch-elf/relr-align.s b/ld/testsuite/ld-loongarch-elf/relr-align.s
new file mode 100644
index 00000000000..ddd055ab74e
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-align.s
@@ -0,0 +1,106 @@
+# Test DT_RELR with differently aligned relative relocs.
+
+.text
+.global _start
+_start:
+foo:
+
+.data
+.p2align 3
+double_0:
+.quad foo
+.quad foo
+.byte 0
+double_1:
+.quad foo
+.quad foo
+.byte 0
+double_2:
+.quad foo
+.quad foo
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+single_0:
+.quad foo
+.byte 0
+single_1:
+.quad foo
+.byte 0
+single_2:
+.quad foo
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+.byte 0
+big:
+.quad foo
+.quad 1
+.quad 2
+.quad 3
+.quad 4
+.quad 5
+.quad 6
+.quad 7
+.quad 8
+.quad 9
+.quad 10
+.quad 11
+.quad 12
+.quad 13
+.quad 14
+.quad 15
+.quad 16
+.quad 17
+.quad 18
+.quad 19
+.quad 20
+.quad 21
+.quad 22
+.quad 23
+.quad 24
+.quad 25
+.quad 26
+.quad 27
+.quad 28
+.quad 29
+.quad 30
+.quad 31
+.quad foo + 32
+.quad 33
+.quad 34
+.quad 35
+.quad 36
+.quad 37
+.quad 38
+.quad 39
+.quad 40
+.quad 41
+.quad 42
+.quad 43
+.quad 44
+.quad 45
+.quad 46
+.quad 47
+.quad 48
+.quad 49
+.quad 50
+.quad 51
+.quad 52
+.quad 53
+.quad 54
+.quad 55
+.quad 56
+.quad 57
+.quad 58
+.quad 59
+.quad 60
+.quad 61
+.quad 62
+.quad foo + 63
+.quad foo + 64
diff --git a/ld/testsuite/ld-loongarch-elf/relr-data-pie.d b/ld/testsuite/ld-loongarch-elf/relr-data-pie.d
new file mode 100644
index 00000000000..20ef9ac1c84
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-data-pie.d
@@ -0,0 +1,18 @@
+#source: relr-data.s
+#ld: -pie -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -rW
+
+Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 5 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0000000012340000  0000000000000003 R_LARCH_RELATIVE                          10004
+0000000012340008  0000000000000003 R_LARCH_RELATIVE                          10008
+0000000012340010  0000000000000003 R_LARCH_RELATIVE                          1000c
+0000000012340018  0000000000000003 R_LARCH_RELATIVE                          12340050
+0000000012340040  0000000c00000002 R_LARCH_64             0000000000000000 sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries which relocate 4 locations:
+Index: Entry            Address           Symbolic Address
+0000:  0000000012340020 0000000012340020  aligned_local
+0001:  0000000000000027 0000000012340028  aligned_hidden
+                        0000000012340030  aligned_global
+                        0000000012340048  aligned_DYNAMIC
diff --git a/ld/testsuite/ld-loongarch-elf/relr-data-shared.d b/ld/testsuite/ld-loongarch-elf/relr-data-shared.d
new file mode 100644
index 00000000000..37e4c0da83e
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-data-shared.d
@@ -0,0 +1,18 @@
+#source: relr-data.s
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -rW
+
+Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 6 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0000000012340000  0000000000000003 R_LARCH_RELATIVE                          10004
+0000000012340008  0000000000000003 R_LARCH_RELATIVE                          10008
+0000000012340018  0000000000000003 R_LARCH_RELATIVE                          12340050
+0000000012340010  0000000d00000002 R_LARCH_64             000000000001000c sym_global \+ 0
+0000000012340030  0000000d00000002 R_LARCH_64             000000000001000c sym_global \+ 0
+0000000012340040  0000000c00000002 R_LARCH_64             0000000000000000 sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries which relocate 3 locations:
+Index: Entry            Address           Symbolic Address
+0000:  0000000012340020 0000000012340020  aligned_local
+0001:  0000000000000023 0000000012340028  aligned_hidden
+                        0000000012340048  aligned_DYNAMIC
diff --git a/ld/testsuite/ld-loongarch-elf/relr-data.s b/ld/testsuite/ld-loongarch-elf/relr-data.s
new file mode 100644
index 00000000000..03673e0fbd2
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-data.s
@@ -0,0 +1,71 @@
+# Test symbol references in .data when used with DT_RELR.
+# Relocations for unaligned sections are currently not packed.
+
+.text
+.global _start
+_start:
+	nop
+
+sym_local:
+	nop
+
+.global sym_hidden
+.hidden sym_hidden
+sym_hidden:
+	nop
+
+.global sym_global
+sym_global:
+	nop
+
+.global sym_global_abs
+.set sym_global_abs, 42
+
+.global sym_weak_undef
+.weak sym_weak_undef
+
+.section .data.unaligned_local
+unaligned_local:
+.quad sym_local
+
+.section .data.unaligned_hidden
+unaligned_hidden:
+.quad sym_hidden
+
+.section .data.unaligned_global
+unaligned_global:
+.quad sym_global
+
+.section .data.unaligned_DYNAMIC
+unaligned_DYNAMIC:
+.quad _DYNAMIC
+
+.section .data.aligned_local
+.p2align 1
+aligned_local:
+.quad sym_local
+
+.section .data.aligned_hidden
+.p2align 1
+aligned_hidden:
+.quad sym_hidden
+
+.section .data.aligned_global
+.p2align 1
+aligned_global:
+.quad sym_global
+
+.section .data.aligned_global_abs
+.p2align 1
+aligned_global_abs:
+.quad sym_global_abs
+
+.section .data.aligned_weak_undef
+.p2align 1
+aligned_weak_undef:
+.quad sym_weak_undef
+
+.section .data.aligned_DYNAMIC
+.p2align 1
+aligned_DYNAMIC:
+.quad _DYNAMIC
diff --git a/ld/testsuite/ld-loongarch-elf/relr-discard-pie.d b/ld/testsuite/ld-loongarch-elf/relr-discard-pie.d
new file mode 100644
index 00000000000..4ea8ae5e7b4
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-discard-pie.d
@@ -0,0 +1,8 @@
+#source: relr-discard.s
+#ld: -pie -z pack-relative-relocs -T relr-discard.ld
+#readelf: -rW
+
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries which relocate 2 locations:
+Index: Entry            Address           Symbolic Address
+0000:  0000000000020008 0000000000020008  _GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:  0000000000000003 0000000000020010  _GLOBAL_OFFSET_TABLE_ \+ 0x10
diff --git a/ld/testsuite/ld-loongarch-elf/relr-discard-shared.d b/ld/testsuite/ld-loongarch-elf/relr-discard-shared.d
new file mode 100644
index 00000000000..8bfd8ba5add
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-discard-shared.d
@@ -0,0 +1,11 @@
+#source: relr-discard.s
+#ld: -shared -z pack-relative-relocs -T relr-discard.ld
+#readelf: -rW
+
+Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 1 entry:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0000000000020010  0000000300000002 R_LARCH_64             000000000001000c sym_global \+ 0
+
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 1 entry which relocates 1 location:
+Index: Entry            Address           Symbolic Address
+0000:  0000000000020008 0000000000020008  _GLOBAL_OFFSET_TABLE_ \+ 0x8
diff --git a/ld/testsuite/ld-loongarch-elf/relr-discard.ld b/ld/testsuite/ld-loongarch-elf/relr-discard.ld
new file mode 100644
index 00000000000..165f1ed2f11
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-discard.ld
@@ -0,0 +1,13 @@
+OUTPUT_ARCH(loongarch64)
+ENTRY(_start)
+SECTIONS
+{
+  /DISCARD/ : { *(.discard.*) }
+
+  . = 0x10000;
+  .text : { *(.text) }
+  . = 0x20000;
+  .got  : { *(.got) *(.got.plt)}
+  . = 0x30000;
+  .data : { *(.data) *(.data.*) }
+}
diff --git a/ld/testsuite/ld-loongarch-elf/relr-discard.s b/ld/testsuite/ld-loongarch-elf/relr-discard.s
new file mode 100644
index 00000000000..b52374a5498
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-discard.s
@@ -0,0 +1,61 @@
+# Test DT_RELR with references in discarded sections.
+
+.text
+.p2align 3
+.global _start
+_start:
+	nop
+
+sym_local:
+	nop
+
+.global sym_hidden
+.hidden sym_hidden
+sym_hidden:
+	nop
+
+.global sym_global
+sym_global:
+	nop
+
+.global sym_global_abs
+.set sym_global_abs, 42
+
+.global sym_weak_undef
+.weak sym_weak_undef
+
+.section .discard.got_local,"ax"
+	la.got $a0, sym_local
+
+.section .discard.got_global,"ax"
+	la.got $a0, sym_global
+
+.section .discard.local,"a"
+.p2align 1
+discard_local:
+.quad sym_local
+
+.section .discard.hidden,"a"
+.p2align 1
+discard_hidden:
+.quad sym_hidden
+
+.section .discard.global,"a"
+.p2align 1
+discard_global:
+.quad sym_global
+
+.section .discard.global_abs,"a"
+.p2align 1
+discard_global_abs:
+.quad sym_global_abs
+
+.section .discard.weak_undef,"a"
+.p2align 1
+discard_weak_undef:
+.quad sym_weak_undef
+
+.section .discard._DYNAMIC,"a"
+.p2align 1
+discard_DYNAMIC:
+.quad _DYNAMIC
diff --git a/ld/testsuite/ld-loongarch-elf/relr-got-pie.d b/ld/testsuite/ld-loongarch-elf/relr-got-pie.d
new file mode 100644
index 00000000000..e994f2bfe01
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-got-pie.d
@@ -0,0 +1,15 @@
+#source: relr-got.s
+#ld: -pie -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -rW
+
+Relocation section '.rela.dyn' at offset 0x[0-9a-f]+ contains 2 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0000000000000000  0000000000000000 R_LARCH_NONE                              0
+0000000000020030  0000000200000002 R_LARCH_64             0000000000000000 sym_weak_undef \+ 0
+
+Relocation section '.relr.dyn' at offset 0x[0-9a-f]+ contains 2 entries which relocate 4 locations:
+Index: Entry            Address           Symbolic Address
+0000:  0000000000020008 0000000000020008  _GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:  000000000000000f 0000000000020010  _GLOBAL_OFFSET_TABLE_ \+ 0x10
+                        0000000000020018  _GLOBAL_OFFSET_TABLE_ \+ 0x18
+                        0000000000020020  _GLOBAL_OFFSET_TABLE_ \+ 0x20
diff --git a/ld/testsuite/ld-loongarch-elf/relr-got-shared.d b/ld/testsuite/ld-loongarch-elf/relr-got-shared.d
new file mode 100644
index 00000000000..169e0e5d69d
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-got-shared.d
@@ -0,0 +1,15 @@
+#source: relr-got.s
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -rW
+
+Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 3 entries:
+    Offset             Info             Type               Symbol's Value  Symbol's Name \+ Addend
+0000000000020020  0000000300000002 R_LARCH_64             0000000000010034 sym_global \+ 0
+0000000000020028  0000000500000002 R_LARCH_64             000000000000002a sym_global_abs \+ 0
+0000000000020030  0000000200000002 R_LARCH_64             0000000000000000 sym_weak_undef \+ 0
+
+Relocation section '\.relr\.dyn' at offset 0x[0-9a-f]+ contains 2 entries which relocate 3 locations:
+Index: Entry            Address           Symbolic Address
+0000:  0000000000020008 0000000000020008  _GLOBAL_OFFSET_TABLE_ \+ 0x8
+0001:  0000000000000007 0000000000020010  _GLOBAL_OFFSET_TABLE_ \+ 0x10
+                        0000000000020018  _GLOBAL_OFFSET_TABLE_ \+ 0x18
diff --git a/ld/testsuite/ld-loongarch-elf/relr-got.s b/ld/testsuite/ld-loongarch-elf/relr-got.s
new file mode 100644
index 00000000000..162528bc7e6
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-got.s
@@ -0,0 +1,27 @@
+.text
+.global _start
+_start:
+	la.got	$a0, sym_local
+	la.got	$a1, sym_hidden
+	la.got	$a2, sym_global
+	la.got	$a3, sym_global_abs
+	la.got	$a4, sym_weak_undef
+	la.got	$a5, _DYNAMIC
+
+sym_local:
+	nop
+
+.global sym_hidden
+.hidden sym_hidden
+sym_hidden:
+	nop
+
+.global sym_global
+sym_global:
+	nop
+
+.global sym_global_abs
+.set sym_global_abs, 42
+
+.global sym_weak_undef
+.weak sym_weak_undef
diff --git a/ld/testsuite/ld-loongarch-elf/relr-relocs.ld b/ld/testsuite/ld-loongarch-elf/relr-relocs.ld
new file mode 100644
index 00000000000..ed83275b629
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-relocs.ld
@@ -0,0 +1,24 @@
+/* Script for DT_RELR tests */
+OUTPUT_ARCH(loongarch64)
+ENTRY(_start)
+SECTIONS
+{
+	PROVIDE (__executable_start = 0x8000); . = 0x10000;
+	.text :
+	{
+		*(.before)
+		*(.text)
+		*(.after)
+	} =0
+	. = 0x20000;
+	.got :
+	{
+		*(.got)
+		*(.got.plt)
+	}
+	. = 0x12340000;
+	.data :
+	{
+		*(.data)
+	}
+}
diff --git a/ld/testsuite/ld-loongarch-elf/relr-text-pie.d b/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
new file mode 100644
index 00000000000..8e34500fbd2
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
@@ -0,0 +1,14 @@
+#source: relr-text.s
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -drW
+
+#...
+ 0x0000000000000016 \(TEXTREL\)            0x0
+#...
+ 0x0000000000000024 \(RELR\)               .*
+ 0x0000000000000023 \(RELRSZ\)             8 \(bytes\)
+ 0x0000000000000025 \(RELRENT\)            8 \(bytes\)
+#...
+Relocation section '\.relr\.dyn' .* contains 1 entry which relocates 1 location:
+Index: Entry            Address           Symbolic Address
+0000:  0000000000010000 0000000000010000  _start
diff --git a/ld/testsuite/ld-loongarch-elf/relr-text-shared.d b/ld/testsuite/ld-loongarch-elf/relr-text-shared.d
new file mode 100644
index 00000000000..8e34500fbd2
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-text-shared.d
@@ -0,0 +1,14 @@
+#source: relr-text.s
+#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
+#readelf: -drW
+
+#...
+ 0x0000000000000016 \(TEXTREL\)            0x0
+#...
+ 0x0000000000000024 \(RELR\)               .*
+ 0x0000000000000023 \(RELRSZ\)             8 \(bytes\)
+ 0x0000000000000025 \(RELRENT\)            8 \(bytes\)
+#...
+Relocation section '\.relr\.dyn' .* contains 1 entry which relocates 1 location:
+Index: Entry            Address           Symbolic Address
+0000:  0000000000010000 0000000000010000  _start
diff --git a/ld/testsuite/ld-loongarch-elf/relr-text.s b/ld/testsuite/ld-loongarch-elf/relr-text.s
new file mode 100644
index 00000000000..47465f2d8c4
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/relr-text.s
@@ -0,0 +1,10 @@
+# Test DT_RELR with DT_TEXTREL and R_LARCH_ALIGN.
+
+.text
+.p2align 5
+.global _start
+_start:
+.global foo
+.hidden foo
+foo:
+.quad foo
-- 
2.45.2


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

* Re: [PATCH v2 5/5] LoongArch: Add DT_RELR tests
  2024-06-26 10:04 ` [PATCH v2 5/5] LoongArch: Add DT_RELR tests Xi Ruoyao
@ 2024-06-27  7:11   ` mengqinggang
  2024-06-27 10:14     ` Xi Ruoyao
  0 siblings, 1 reply; 21+ messages in thread
From: mengqinggang @ 2024-06-27  7:11 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Zhensong Liu, i.swmail, maskray, Szabolcs Nagy


> diff --git a/ld/testsuite/ld-loongarch-elf/relr-text-pie.d b/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
> new file mode 100644
> index 00000000000..8e34500fbd2
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
> @@ -0,0 +1,14 @@
> +#source: relr-text.s
> +#ld: -shared -z pack-relative-relocs -T relr-relocs.ld


ld: -shared -> ld: pie?


> +#readelf: -drW
> +
> +#...
> + 0x0000000000000016 \(TEXTREL\)            0x0
> +#...
> + 0x0000000000000024 \(RELR\)               .*
> + 0x0000000000000023 \(RELRSZ\)             8 \(bytes\)
> + 0x0000000000000025 \(RELRENT\)            8 \(bytes\)
> +#...
> +Relocation section '\.relr\.dyn' .* contains 1 entry which relocates 1 location:
> +Index: Entry            Address           Symbolic Address
> +0000:  0000000000010000 0000000000010000  _start
> diff --git a/ld/testsuite/ld-loongarch-elf/relr-text-shared.d b/ld/testsuite/ld-loongarch-elf/relr-text-shared.d
> new file mode 100644
> index 00000000000..8e34500fbd2
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/relr-text-shared.d
> @@ -0,0 +1,14 @@
> +#source: relr-text.s
> +#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
> +#readelf: -drW
> +
> +#...
> + 0x0000000000000016 \(TEXTREL\)            0x0
> +#...
> + 0x0000000000000024 \(RELR\)               .*
> + 0x0000000000000023 \(RELRSZ\)             8 \(bytes\)
> + 0x0000000000000025 \(RELRENT\)            8 \(bytes\)
> +#...
> +Relocation section '\.relr\.dyn' .* contains 1 entry which relocates 1 location:
> +Index: Entry            Address           Symbolic Address
> +0000:  0000000000010000 0000000000010000  _start
> diff --git a/ld/testsuite/ld-loongarch-elf/relr-text.s b/ld/testsuite/ld-loongarch-elf/relr-text.s
> new file mode 100644
> index 00000000000..47465f2d8c4
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/relr-text.s
> @@ -0,0 +1,10 @@
> +# Test DT_RELR with DT_TEXTREL and R_LARCH_ALIGN.
> +
> +.text
> +.p2align 5
> +.global _start
> +_start:
> +.global foo
> +.hidden foo
> +foo:
> +.quad foo


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

* Re: [PATCH v2 4/5] LoongArch: Add DT_RELR support
  2024-06-26 10:04 ` [PATCH v2 4/5] LoongArch: Add DT_RELR support Xi Ruoyao
@ 2024-06-27  7:21   ` mengqinggang
  2024-06-27 10:13     ` Xi Ruoyao
  2024-06-27  7:27   ` mengqinggang
  1 sibling, 1 reply; 21+ messages in thread
From: mengqinggang @ 2024-06-27  7:21 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Zhensong Liu, i.swmail, maskray, Szabolcs Nagy


在 2024/6/26 下午6:04, Xi Ruoyao 写道:
> The logic is same as a71d87680110 ("aarch64: Add DT_RELR support").
>
> As LoongArch does not have -z dynamic-undefined-weak, we don't need to
> consider UNDEFWEAK_NO_DYNAMIC_RELOC.
>
> The linker relaxation adds another layer of complexity.  When we delete
> bytes in a section during relaxation, we need to fix up the offset in
> the to-be-packed relative relocations against this section.
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
>   bfd/elfnn-loongarch.c                      | 482 ++++++++++++++++++++-
>   binutils/testsuite/lib/binutils-common.exp |   1 +
>   ld/emulparams/elf64loongarch.sh            |   1 +
>   3 files changed, 481 insertions(+), 3 deletions(-)
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index 1a84b88320b..f501589bc70 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -84,6 +84,12 @@ struct _bfd_loongarch_elf_obj_tdata
>      && elf_tdata (bfd) != NULL						\
>      && elf_object_id (bfd) == LARCH_ELF_DATA)
>   
> +struct relr_entry
> +{
> +  asection *sec;
> +  bfd_vma off;
> +};
> +
>   struct loongarch_elf_link_hash_table
>   {
>     struct elf_link_hash_table elf;
> @@ -104,8 +110,50 @@ struct loongarch_elf_link_hash_table
>     /* The data segment phase, don't relax the section
>        when it is exp_seg_relro_adjust.  */
>     int *data_segment_phase;
> +
> +  /* Array of relative relocs to be emitted in DT_RELR format.  */
> +  bfd_size_type relr_alloc;
> +  bfd_size_type relr_count;
> +  struct relr_entry *relr;
> +
> +  /* Sorted output addresses of above relative relocs.  */
> +  bfd_vma *relr_sorted;
> +
> +  /* Layout recomputation count.  */
> +  bfd_size_type relr_layout_iter;
>   };
>   
> +struct loongarch_elf_section_data
> +{
> +  struct bfd_elf_section_data elf;
> +
> +  /* &htab->relr[i] where i is the smallest number s.t.
> +     htab->relr[i].sec == &elf.  NULL if there exists no such i.  */


Why  htab->relr[i].sec == &elf?


> +  struct relr_entry *relr;
> +};
> +
> +/* We need an additional field in elf_section_data to handle complex
> +   interactions between DT_RELR and relaxation.  */
> +static bool
> +loongarch_elf_new_section_hook (bfd *abfd, asection *sec)
> +{
> +  if (!sec->used_by_bfd)
> +    {
> +      struct loongarch_elf_section_data *sdata;
> +      size_t amt = sizeof (*sdata);
> +
> +      sdata = bfd_zalloc (abfd, amt);
> +      if (!sdata)
> +	return false;
> +      sec->used_by_bfd = sdata;
> +    }
> +
> +  return _bfd_elf_new_section_hook (abfd, sec);
> +}
> +
> +#define loongarch_elf_section_data(x) \
> +  ((struct loongarch_elf_section_data *) elf_section_data (x))
> +
>   /* Get the LoongArch ELF linker hash table from a link_info structure.  */
>   #define loongarch_elf_hash_table(p)					\
>     (elf_hash_table_id (elf_hash_table (p)) == LARCH_ELF_DATA		\
> @@ -927,6 +975,20 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>         if (rel + 1 != relocs + sec->reloc_count
>   	  && ELFNN_R_TYPE (rel[1].r_info) == R_LARCH_RELAX)
>   	r_type = loongarch_tls_transition (abfd, info, h, r_symndx, r_type);
> +
> +      /* I don't want to spend time supporting DT_RELR with old object
> +	 files doing stack-based relocs.  */
> +      if (info->enable_dt_relr
> +	  && r_type >= R_LARCH_SOP_PUSH_PCREL
> +	  && r_type <= R_LARCH_SOP_POP_32_U)
> +	{
> +	  /* xgettext:c-format */
> +	  _bfd_error_handler (_("%pB: stack based reloc type (%u) is not "
> +				"supported with -z pack-relative-relocs"),
> +			      abfd, r_type);
> +	  return false;
> +	}
> +
>         switch (r_type)
>   	{
>   	case R_LARCH_GOT_PC_HI20:
> @@ -1118,6 +1180,20 @@ loongarch_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
>   	    return false;
>   	  break;
>   
> +	case R_LARCH_ALIGN:
> +	  /* Check against irrational R_LARCH_ALIGN relocs which may cause
> +	     removing an odd number of bytes and disrupt DT_RELR.  */
> +	  if (rel->r_offset % 4 != 0)
> +	    {
> +	      /* xgettext:c-format */
> +	      _bfd_error_handler (
> +		_("%pB: R_LARCH_ALIGN with offset %" PRId64 " not aligned "
> +		  "to instruction boundary"),
> +		abfd, (uint64_t) rel->r_offset);
> +	      return false;
> +	    }
> +	  break;
> +
>   	default:
>   	  break;
>   	}
> @@ -1832,6 +1908,342 @@ maybe_set_textrel (struct elf_link_hash_entry *h, void *info_p)
>     return true;
>   }
>   
> +static bool
> +record_relr (struct loongarch_elf_link_hash_table *htab, asection *sec,
> +	     bfd_vma off, asection *sreloc)
> +{
> +  struct relr_entry **sec_relr = &loongarch_elf_section_data (sec)->relr;
> +
> +  /* Undo the relocation section size accounting.  */
> +  BFD_ASSERT (sreloc->size >= sizeof (ElfNN_External_Rela));
> +  sreloc->size -= sizeof (ElfNN_External_Rela);
> +
> +  BFD_ASSERT (off % 2 == 0 && sec->alignment_power > 0);
> +  if (htab->relr_count >= htab->relr_alloc)
> +    {
> +      if (htab->relr_alloc == 0)
> +	htab->relr_alloc = 4096;
> +      else
> +	htab->relr_alloc *= 2;
> +
> +      htab->relr = bfd_realloc (htab->relr,
> +				htab->relr_alloc * sizeof (*htab->relr));
> +      if (!htab->relr)
> +	return false;
> +    }
> +  htab->relr[htab->relr_count].sec = sec;
> +  htab->relr[htab->relr_count].off = off;
> +  if (*sec_relr == NULL)
> +    *sec_relr = &htab->relr[htab->relr_count];
> +  htab->relr_count++;
> +  return true;
> +}
> +
> +static bool
> +record_relr_local_got_relocs (bfd *input_bfd, struct bfd_link_info *info)
> +{
> +  bfd_vma *local_got_offsets = elf_local_got_offsets (input_bfd);
> +  char *local_tls_type = _bfd_loongarch_elf_local_got_tls_type (input_bfd);
> +  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_bfd);
> +  struct loongarch_elf_link_hash_table *htab =
> +    loongarch_elf_hash_table (info);
> +
> +  if (!local_got_offsets || !local_tls_type || !bfd_link_pic (info))
> +    return true;
> +
> +  for (unsigned i = 0; i < symtab_hdr->sh_info; i++)
> +    {
> +      bfd_vma off = local_got_offsets[i];
> +
> +      /* FIXME: If the local symbol is in SHN_ABS then emitting
> +	 a relative relocation is not correct, but it seems to be wrong
> +	 in loongarch_elf_relocate_section too.  */
> +      if (local_tls_type[i] == GOT_NORMAL
> +	  && !record_relr (htab, htab->elf.sgot, off, htab->elf.srelgot))
> +	return false;
> +    }
> +
> +  return true;
> +}
> +
> +static bool
> +record_relr_dyn_got_relocs (struct elf_link_hash_entry *h, void *inf)
> +{
> +  struct bfd_link_info *info = (struct bfd_link_info *) inf;
> +  struct loongarch_elf_link_hash_table *htab =
> +    loongarch_elf_hash_table (info);
> +
> +  if (h->root.type == bfd_link_hash_indirect)
> +    return true;
> +  if (h->type == STT_GNU_IFUNC && h->def_regular)
> +    return true;
> +  if (h->got.refcount <= 0)
> +    return true;
> +  if (loongarch_elf_hash_entry (h)->tls_type
> +      & (GOT_TLS_GD | GOT_TLS_IE | GOT_TLS_GDESC))
> +    return true;
> +  if (!bfd_link_pic (info))
> +    return true;
> +
> +  /* On LoongArch a GOT entry for undefined weak symbol is never relocated
> +     with R_LARCH_RELATIVE: we don't have -z dynamic-undefined-weak, thus
> +     the GOT entry is either const 0 (if the symbol is LARCH_REF_LOCAL) or
> +     relocated with R_LARCH_NN (otherwise).  */
> +  if (h->root.type == bfd_link_hash_undefweak)
> +    return true;
> +
> +  if (!LARCH_REF_LOCAL (info, h))
> +    return true;
> +  if (bfd_is_abs_symbol (&h->root))
> +    return true;
> +
> +  if (!record_relr (htab, htab->elf.sgot, h->got.offset,
> +		    htab->elf.srelgot))
> +    return false;
> +
> +  return true;
> +}
> +
> +static bool
> +record_relr_non_got_relocs (bfd *input_bfd, struct bfd_link_info *info,
> +			    asection *sec)
> +{
> +  asection *sreloc;
> +  struct loongarch_elf_link_hash_table *htab;
> +  Elf_Internal_Rela *relocs, *rel, *rel_end;
> +  Elf_Internal_Shdr *symtab_hdr;
> +  struct elf_link_hash_entry **sym_hashes;
> +
> +  if (!bfd_link_pic (info))
> +    return true;
> +  if (sec->reloc_count == 0)
> +    return true;
> +  if ((sec->flags & (SEC_RELOC | SEC_ALLOC | SEC_DEBUGGING))
> +       != (SEC_RELOC | SEC_ALLOC))
> +    return true;
> +  if (sec->alignment_power == 0)
> +    return true;
> +  if (discarded_section (sec))
> +    return true;
> +
> +  sreloc = elf_section_data (sec)->sreloc;
> +  if (sreloc == NULL)
> +    return true;
> +
> +  htab = loongarch_elf_hash_table (info);
> +  symtab_hdr = &elf_symtab_hdr (input_bfd);
> +  sym_hashes = elf_sym_hashes (input_bfd);
> +  relocs = _bfd_elf_link_info_read_relocs (input_bfd, info, sec, NULL,
> +					   NULL, info->keep_memory);
> +  BFD_ASSERT (relocs != NULL);
> +  rel_end = relocs + sec->reloc_count;
> +  for (rel = relocs; rel < rel_end; rel++)
> +    {
> +      unsigned r_symndx = ELFNN_R_SYM (rel->r_info);
> +      struct elf_link_hash_entry *h = NULL;
> +      asection *def_sec = NULL;
> +
> +      if (ELFNN_R_TYPE (rel->r_info) != R_LARCH_NN
> +	  || rel->r_offset % 2 != 0)
> +	continue;
> +
> +      /* The logical below must match loongarch_elf_relocate_section.  */
> +      if (r_symndx < symtab_hdr->sh_info)
> +	{
> +	  /* A local symbol.  */
> +	  Elf_Internal_Sym *isym;
> +	  isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, input_bfd,
> +					r_symndx);
> +	  BFD_ASSERT(isym != NULL);
> +
> +	  /* Local STT_GNU_IFUNC symbol uses R_LARCH_IRELATIVE for
> +	     R_LARCH_NN, not R_LARCH_RELATIVE.  */
> +	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
> +	    continue;
> +	  def_sec = bfd_section_from_elf_index (input_bfd, isym->st_shndx);
> +	}
> +      else
> +	{
> +	  h = sym_hashes[r_symndx - symtab_hdr->sh_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;
> +
> +	  /* Filter out symbols that cannot have a relative reloc.  */
> +	  if (h->dyn_relocs == NULL)
> +	    continue;
> +	  if (bfd_is_abs_symbol (&h->root))
> +	    continue;
> +	  if (h->type == STT_GNU_IFUNC)
> +	    continue;
> +
> +	  if (h->root.type == bfd_link_hash_defined
> +	      || h->root.type == bfd_link_hash_defweak)
> +	    def_sec = h->root.u.def.section;
> +
> +	  /* On LoongArch an R_LARCH_NN against undefined weak symbol
> +	     is never converted to R_LARCH_RELATIVE: we don't have
> +	     -z dynamic-undefined-weak, thus the reloc is either removed
> +	     (if the symbol is LARCH_REF_LOCAL) or kept (otherwise).  */
> +	  if (h->root.type == bfd_link_hash_undefweak)
> +	    continue;
> +
> +	  if (!LARCH_REF_LOCAL (info, h))
> +	    continue;
> +	}
> +
> +      if (!def_sec || discarded_section (def_sec))
> +	continue;
> +
> +      if (!record_relr (htab, sec, rel->r_offset, sreloc))
> +	return false;
> +    }
> +
> +  return true;
> +}
> +
> +static int
> +cmp_relr_addr (const void *p, const void *q)
> +{
> +  const bfd_vma *a = p, *b = q;
> +  return (*a > *b) - (*a < *b);
> +}
> +
> +static bool
> +sort_relr (struct bfd_link_info *info,
> +	   struct loongarch_elf_link_hash_table *htab)
> +{
> +  if (htab->relr_count == 0)
> +    return true;
> +
> +  bfd_vma *addr = htab->relr_sorted;
> +  if (!addr)
> +    {
> +      addr = bfd_malloc (htab->relr_count * sizeof (*addr));
> +      if (!addr)
> +	return false;
> +      htab->relr_sorted = addr;
> +    }
> +
> +  for (bfd_size_type i = 0; i < htab->relr_count; i++)
> +    {
> +      bfd_vma off = _bfd_elf_section_offset (info->output_bfd, info,
> +					     htab->relr[i].sec,
> +					     htab->relr[i].off);
> +      addr[i] = htab->relr[i].sec->output_section->vma
> +		+ htab->relr[i].sec->output_offset + off;
> +    }
> +  qsort(addr, htab->relr_count, sizeof (*addr), cmp_relr_addr);
> +  return true;
> +}
> +
> +static bool
> +loongarch_elf_size_relative_relocs (struct bfd_link_info *info,
> +				    bool *need_layout)
> +{
> +  struct loongarch_elf_link_hash_table *htab =
> +    loongarch_elf_hash_table (info);
> +  asection *srelrdyn = htab->elf.srelrdyn;
> +
> +  *need_layout = false;
> +
> +  if (!sort_relr (info, htab))
> +    return false;
> +  bfd_vma *addr = htab->relr_sorted;
> +
> +  BFD_ASSERT (srelrdyn != NULL);
> +  bfd_size_type oldsize = srelrdyn->size;
> +  srelrdyn->size = 0;
> +  for (bfd_size_type i = 0; i < htab->relr_count; )
> +    {
> +      bfd_vma base = addr[i];
> +      i++;
> +      srelrdyn->size += NN / 8;
> +      base += NN / 8;
> +      while (1)
> +	{
> +	  bfd_size_type start_i = i;
> +	  while (i < htab->relr_count
> +		 && addr[i] - base < (NN - 1) * (NN / 8)
> +		 && (addr[i] - base) % (NN / 8) == 0)
> +	    i++;
> +	  if (i == start_i)
> +	    break;
> +	  srelrdyn->size += NN / 8;
> +	  base += (NN - 1) * (NN / 8);
> +	}
> +    }
> +  if (srelrdyn->size != oldsize)
> +    {
> +      *need_layout = true;
> +      /* Stop after a few iterations in case the layout does not converge,
> +	 but we can only stop when the size would shrink (and pad the
> +	 spare space with 1.  */
> +      if (htab->relr_layout_iter++ > 5 && srelrdyn->size < oldsize)
> +	{
> +	  srelrdyn->size = oldsize;
> +	  *need_layout = false;
> +	}
> +    }
> +  return true;
> +}
> +
> +static bool
> +loongarch_elf_finish_relative_relocs (struct bfd_link_info *info)
> +{
> +  struct loongarch_elf_link_hash_table *htab =
> +    loongarch_elf_hash_table (info);
> +  asection *srelrdyn = htab->elf.srelrdyn;
> +  bfd *dynobj = htab->elf.dynobj;
> +
> +  if (!srelrdyn || srelrdyn->size == 0)
> +    return true;
> +
> +  srelrdyn->contents = bfd_alloc (dynobj, srelrdyn->size);
> +  if (!srelrdyn->contents)
> +    return false;
> +
> +  bfd_vma *addr = htab->relr_sorted;
> +  bfd_byte *loc = srelrdyn->contents;
> +  for (bfd_size_type i = 0; i < htab->relr_count; )
> +    {
> +      bfd_vma base = addr[i];
> +      i++;
> +      bfd_put_NN (dynobj, base, loc);
> +      loc += NN / 8;
> +      base += NN / 8;
> +      while (1)
> +	{
> +	  uintNN_t bits = 0;
> +	  while (i < htab->relr_count)
> +	    {
> +	      bfd_vma delta = addr[i] - base;
> +	      if (delta >= (NN - 1) * (NN / 8) || delta % (NN / 8) != 0)
> +		break;
> +	      bits |= (uintNN_t) 1 << (delta / (NN / 8));
> +	      i++;
> +	    }
> +	  if (bits == 0)
> +	    break;
> +	  bfd_put_NN (dynobj, (bits << 1) | 1, loc);
> +	  loc += NN / 8;
> +	  base += (NN - 1) * (NN / 8);
> +	}
> +    }
> +
> +  free (addr);
> +  htab->relr_sorted = NULL;
> +
> +  /* Pad any excess with 1's, a do-nothing encoding.  */
> +  while (loc < srelrdyn->contents + srelrdyn->size)
> +    {
> +      bfd_put_NN (dynobj, 1, loc);
> +      loc += NN / 8;
> +    }
> +
> +  return true;
> +}
> +
>   static bool
>   loongarch_elf_late_size_sections (bfd *output_bfd,
>   				  struct bfd_link_info *info)
> @@ -2012,6 +2424,24 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
>         && (htab->elf.splt == NULL || htab->elf.splt->size == 0))
>       htab->elf.sgotplt->size = 0;
>   
> +  if (info->enable_dt_relr && !bfd_link_relocatable (info))
> +    {
> +      elf_link_hash_traverse (&htab->elf, record_relr_dyn_got_relocs, info);
> +
> +      for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
> +	{
> +	  if (!is_loongarch_elf (ibfd))
> +	    continue;
> +
> +	  for (s = ibfd->sections; s != NULL; s = s->next)
> +	    if (!record_relr_non_got_relocs (ibfd, info, s))
> +	      return false;
> +
> +	  if (!record_relr_local_got_relocs (ibfd, info))
> +	    return false;
> +	}
> +    }
> +
>     /* The check_relocs and adjust_dynamic_symbol entry points have
>        determined the sizes of the various dynamic sections.  Allocate
>        memory for them.  */
> @@ -2036,6 +2466,14 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
>   	      s->reloc_count = 0;
>   	    }
>   	}
> +      else if (s == htab->elf.srelrdyn && htab->relr_count == 0)
> +	{
> +	  /* Remove .relr.dyn based on relr_count, not size, since
> +	     it is not sized yet.  */
> +	    s->flags |= SEC_EXCLUDE;
> +	  /* Allocate contents later.  */
> +	    continue;
> +	}
>         else
>   	{
>   	  /* It's not one of our sections.  */
> @@ -2968,6 +3406,17 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   			info, input_bfd, input_section, rel, howto,
>   			bfd_reloc_notsupported, is_undefweak, name, msg);
>   		    }
> +		  else if (info->enable_dt_relr
> +			   && (ELFNN_R_TYPE (outrel.r_info)
> +			       == R_LARCH_RELATIVE)
> +			   && input_section->alignment_power != 0
> +			   && rel->r_offset % 2 == 0)
> +		    /* Don't emit a relative relocation that is packed,
> +		       only apply the addend (as if we are applying the
> +		       original R_LARCH_NN reloc in a PDE).  */
> +		    r = perform_relocation (rel, input_section, howto,
> +					    relocation, input_bfd,
> +					    contents);
>   		  else
>   		    loongarch_elf_append_rela (output_bfd, sreloc,
>   					       &outrel);
> @@ -3695,7 +4144,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   		  got_off = local_got_offsets[r_symndx] & (~(bfd_vma)1);
>   		  if ((local_got_offsets[r_symndx] & 1) == 0)
>   		    {
> -		      if (bfd_link_pic (info))
> +		      if (bfd_link_pic (info) && !info->enable_dt_relr)
>   			{
>   			  Elf_Internal_Rela rela;
>   			  rela.r_offset = sec_addr (got) + got_off;
> @@ -4107,6 +4556,14 @@ loongarch_relax_delete_bytes (bfd *abfd,
>     unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
>     struct bfd_elf_section_data *data = elf_section_data (sec);
>     bfd_byte *contents = data->this_hdr.contents;
> +  struct relr_entry *relr =
> +    ((struct loongarch_elf_section_data *)elf_section_data (sec))->relr;
> +  struct loongarch_elf_link_hash_table *htab =
> +    loongarch_elf_hash_table (link_info);
> +  struct relr_entry *relr_end = NULL;
> +
> +  if (htab->relr_count)
> +    relr_end = htab->relr + htab->relr_count;
>   
>     /* Actually delete the bytes.  */
>     sec->size -= count;
> @@ -4119,6 +4576,11 @@ loongarch_relax_delete_bytes (bfd *abfd,
>       if (data->relocs[i].r_offset > addr && data->relocs[i].r_offset < toaddr)
>         data->relocs[i].r_offset -= count;
>   
> +  /* Likewise for relative relocs to be packed into .relr.  */
> +  for (; relr && relr < relr_end && relr->sec == sec; relr++)
> +    if (relr->off > addr && relr->off < toaddr)
> +      relr->off -= count;
> +
>     /* Adjust the local symbols defined in this section.  */
>     for (i = 0; i < symtab_hdr->sh_info; i++)
>       {
> @@ -5207,9 +5669,18 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
>         else if (bfd_link_pic (info) && LARCH_REF_LOCAL (info, h))
>   	{
>   	  asection *sec = h->root.u.def.section;
> +	  bfd_vma linkaddr = h->root.u.def.value + sec->output_section->vma
> +			     + sec->output_offset;
> +
> +	  /* Don't emit relative relocs if they are packed, but we need
> +	     to write the addend (link-time addr) into the GOT then.  */
> +	  if (info->enable_dt_relr)
> +	    {
> +	      bfd_put_NN (output_bfd, linkaddr, sgot->contents + off);
> +	      goto skip_got_reloc;
> +	    }
>   	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
> -	  rela.r_addend = (h->root.u.def.value + sec->output_section->vma
> -			   + sec->output_offset);
> +	  rela.r_addend = linkaddr;
>   	}
>         else
>   	{
> @@ -5220,6 +5691,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
>   
>         loongarch_elf_append_rela (output_bfd, srela, &rela);
>       }
> +skip_got_reloc:
>   
>     /* Mark some specially defined symbols as absolute.  */
>     if (h == htab->elf.hdynamic || h == htab->elf.hgot || h == htab->elf.hplt)
> @@ -5673,6 +6145,10 @@ elf_loongarch64_hash_symbol (struct elf_link_hash_entry *h)
>   #define elf_backend_grok_psinfo loongarch_elf_grok_psinfo
>   #define elf_backend_hash_symbol elf_loongarch64_hash_symbol
>   #define bfd_elfNN_bfd_relax_section loongarch_elf_relax_section
> +#define elf_backend_size_relative_relocs loongarch_elf_size_relative_relocs
> +#define elf_backend_finish_relative_relocs \
> +  loongarch_elf_finish_relative_relocs
> +#define bfd_elfNN_new_section_hook loongarch_elf_new_section_hook
>   
>   #define elf_backend_dtrel_excludes_plt 1
>   
> diff --git a/binutils/testsuite/lib/binutils-common.exp b/binutils/testsuite/lib/binutils-common.exp
> index f0136577b6c..ce7413a77e5 100644
> --- a/binutils/testsuite/lib/binutils-common.exp
> +++ b/binutils/testsuite/lib/binutils-common.exp
> @@ -474,6 +474,7 @@ proc supports_dt_relr {} {
>   	  || [istarget i?86-*-*]
>   	  || [istarget powerpc64*-*-*]
>   	  || [istarget aarch64*-*-*])
> +	  || [istarget loongarch64*-*-*]
>   	 && ([istarget *-*-linux*]
>   	     || [istarget *-*-gnu*]) } {
>   	return 1
> diff --git a/ld/emulparams/elf64loongarch.sh b/ld/emulparams/elf64loongarch.sh
> index d7b2229e213..8c805da987e 100644
> --- a/ld/emulparams/elf64loongarch.sh
> +++ b/ld/emulparams/elf64loongarch.sh
> @@ -1,4 +1,5 @@
>   source_sh ${srcdir}/emulparams/elf64loongarch-defs.sh
> +source_sh ${srcdir}/emulparams/dt-relr.sh
>   OUTPUT_FORMAT="elf64-loongarch"
>   
>   case "$target" in


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

* Re: [PATCH v2 4/5] LoongArch: Add DT_RELR support
  2024-06-26 10:04 ` [PATCH v2 4/5] LoongArch: Add DT_RELR support Xi Ruoyao
  2024-06-27  7:21   ` mengqinggang
@ 2024-06-27  7:27   ` mengqinggang
  2024-06-27 10:16     ` Xi Ruoyao
  1 sibling, 1 reply; 21+ messages in thread
From: mengqinggang @ 2024-06-27  7:27 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Zhensong Liu, i.swmail, maskray, Szabolcs Nagy



> @@ -2036,6 +2466,14 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
>   	      s->reloc_count = 0;
>   	    }
>   	}
> +      else if (s == htab->elf.srelrdyn && htab->relr_count == 0)
> +	{
> +	  /* Remove .relr.dyn based on relr_count, not size, since
> +	     it is not sized yet.  */
> +	    s->flags |= SEC_EXCLUDE;

Two extra spaces are indented.


> +	  /* Allocate contents later.  */
> +	    continue;

Two extra spaces are indented.


> +	}


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

* Re: [PATCH v2 4/5] LoongArch: Add DT_RELR support
  2024-06-27  7:21   ` mengqinggang
@ 2024-06-27 10:13     ` Xi Ruoyao
  0 siblings, 0 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-27 10:13 UTC (permalink / raw)
  To: mengqinggang, binutils; +Cc: Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Thu, 2024-06-27 at 15:21 +0800, mengqinggang wrote:

/* snip */

> > +struct loongarch_elf_section_data
> > +{
> > +  struct bfd_elf_section_data elf;
> > +
> > +  /* &htab->relr[i] where i is the smallest number s.t.
> > +     htab->relr[i].sec == &elf.  NULL if there exists no such i. 
> > */
> 
> 
> Why  htab->relr[i].sec == &elf?

Oops this is wrong.  Should be

elf_section_data(htab->relr[i].sec) == &elf

will fix in V3.

/* snip */

> > @@ -4107,6 +4556,14 @@ loongarch_relax_delete_bytes (bfd *abfd,
> >     unsigned int sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
> >     struct bfd_elf_section_data *data = elf_section_data (sec);
> >     bfd_byte *contents = data->this_hdr.contents;
> > +  struct relr_entry *relr =
> > +    ((struct loongarch_elf_section_data *)elf_section_data (sec))->relr;

And here should (re)use loongarch_elf_section_data(sec)->relr.  Will fix
in V3 as well.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2 5/5] LoongArch: Add DT_RELR tests
  2024-06-27  7:11   ` mengqinggang
@ 2024-06-27 10:14     ` Xi Ruoyao
  0 siblings, 0 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-27 10:14 UTC (permalink / raw)
  To: mengqinggang, binutils; +Cc: Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Thu, 2024-06-27 at 15:11 +0800, mengqinggang wrote:
> > diff --git a/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
> > b/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
> > new file mode 100644
> > index 00000000000..8e34500fbd2
> > --- /dev/null
> > +++ b/ld/testsuite/ld-loongarch-elf/relr-text-pie.d
> > @@ -0,0 +1,14 @@
> > +#source: relr-text.s
> > +#ld: -shared -z pack-relative-relocs -T relr-relocs.ld
> 
> 
> ld: -shared -> ld: pie?

Indeed.  Will fix this test case in V3.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2 4/5] LoongArch: Add DT_RELR support
  2024-06-27  7:27   ` mengqinggang
@ 2024-06-27 10:16     ` Xi Ruoyao
  0 siblings, 0 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-27 10:16 UTC (permalink / raw)
  To: mengqinggang, binutils; +Cc: Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Thu, 2024-06-27 at 15:27 +0800, mengqinggang wrote:
> > +      else if (s == htab->elf.srelrdyn && htab->relr_count == 0)
> > +	{
> > +	  /* Remove .relr.dyn based on relr_count, not size, since
> > +	     it is not sized yet.  */
> > +	    s->flags |= SEC_EXCLUDE;
> 
> Two extra spaces are indented.
> 
> 
> > +	  /* Allocate contents later.  */
> > +	    continue;
> 
> Two extra spaces are indented.

Will remove the extra spaces in V3.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-26 10:04 ` [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64 Xi Ruoyao
@ 2024-06-27 10:58   ` Jinyang He
  2024-06-27 12:39     ` Xi Ruoyao
  0 siblings, 1 reply; 21+ messages in thread
From: Jinyang He @ 2024-06-27 10:58 UTC (permalink / raw)
  To: Xi Ruoyao, binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On 2024-06-26 18:04, Xi Ruoyao wrote:

> We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:
>
>      $ cat t.s
>      .data
>      x:
>          .4byte x
> 	.4byte 0xdeadbeef
>      $ as/as-new t.s -o t.o
>      $ ld/ld-new -shared t.o
>      $ objdump -R
>      a.out:     file format elf64-loongarch
>
>      DYNAMIC RELOCATION RECORDS
>      OFFSET           TYPE              VALUE
>      00000000000001a8 R_LARCH_RELATIVE  *ABS*+0x00000000000001a8
>
> But this is just wrong: at runtime the dynamic linker will run
> *(uintptr *)&x += load_address, clobbering the next 4 bytes of data
> ("0xdeadbeef" in the example).
>
> If we keep the R_LARCH_32 reloc as-is in ELFCLASS64, it'll be rejected
> by the Glibc dynamic linker anyway.  And it does not make too much sense
> to modify Glibc to support it.  So we can just reject it like x86_64:
>
>      relocation R_X86_64_32 against `.data' can not be used when making a
>      shared object; recompile with -fPIC
>
> or RISC-V:
>
>      relocation R_RISCV_32 against non-absolute symbol `a local symbol'
>      can not be used in RV64 when making a shared object"
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
>   bfd/elfnn-loongarch.c                         | 23 ++++++++++++++++++-
>   .../ld-loongarch-elf/ld-loongarch-elf.exp     |  1 +
>   .../ld-loongarch-elf/r_larch_32_elf64.d       |  4 ++++
>   .../ld-loongarch-elf/r_larch_32_elf64.s       |  3 +++
>   4 files changed, 30 insertions(+), 1 deletion(-)
>   create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
>   create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index b1720760475..3a55ac93e20 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   	      /* No alloc space of func allocate_dynrelocs.  */
>   	      if (unresolved_reloc
>   		  && !(h && (h->is_weakalias || !h->dyn_relocs)))
> -		loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
> +		{
> +		  if (is_pic && r_type != R_LARCH_NN)
> +		    {
> +		      /* Not to use ELFCLASSNN in string literal or it'll
> +			 puzzle gettext.  */
> +
> +		      /* xgettext:c-format  */
> +		      char *msg = bfd_asprintf (
> +			_("reloc is unresolved and cannot be turned to "
> +			  "a runtime reloc in ELFCLASS%d"),
> +			NN);
> +
> +		      /* loongarch_reloc_is_fatal will output
> +			 "R_LARCH_32" or "R_LARCH_64" for us.  */
I'd like to do this rejection earlier in `check_relocs` than
`relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
so this rejection should be efficient only for R_LARCH_32 on loongarch64.

Thanks.
> +		      fatal = loongarch_reloc_is_fatal (
> +			info, input_bfd, input_section, rel, howto,
> +			bfd_reloc_notsupported, is_undefweak, name, msg);
> +		    }
> +		  else
> +		    loongarch_elf_append_rela (output_bfd, sreloc,
> +					       &outrel);
> +		}
>   	    }
>   
>   	  relocation += rel->r_addend;
> diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> index 2d67c4f2668..4d9f4aebaff 100644
> --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> @@ -132,6 +132,7 @@ if [istarget "loongarch64-*-*"] {
>       run_dump_test "reloc_le_with_shared"
>       run_dump_test "reloc_ler_with_shared"
>       run_dump_test "reloc_abs_with_shared"
> +    run_dump_test "r_larch_32_elf64"
>     }
>   
>     if [check_pie_support] {
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> new file mode 100644
> index 00000000000..df61f3a36c5
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> @@ -0,0 +1,4 @@
> +#name: R_LARCH_32 in ELFCLASS64
> +#source: r_larch_32_elf64.s
> +#ld: -shared -melf64loongarch
> +#error: R_LARCH_32 against `x':\nreloc is unresolved and cannot be turned to a runtime reloc in ELFCLASS64
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> new file mode 100644
> index 00000000000..6649f2bce01
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> @@ -0,0 +1,3 @@
> +.data
> +x:
> +	.4byte x


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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-27 10:58   ` Jinyang He
@ 2024-06-27 12:39     ` Xi Ruoyao
  2024-06-27 17:19       ` Xi Ruoyao
  0 siblings, 1 reply; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-27 12:39 UTC (permalink / raw)
  To: Jinyang He, binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Thu, 2024-06-27 at 18:58 +0800, Jinyang He wrote:

/* snip */

> > @@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
> >   	      /* No alloc space of func allocate_dynrelocs.  */
> >   	      if (unresolved_reloc
> >   		  && !(h && (h->is_weakalias || !h->dyn_relocs)))
> > -		loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
> > +		{
> > +		  if (is_pic && r_type != R_LARCH_NN)
> > +		    {
> > +		      /* Not to use ELFCLASSNN in string literal or it'll
> > +			 puzzle gettext.  */
> > +
> > +		      /* xgettext:c-format  */
> > +		      char *msg = bfd_asprintf (
> > +			_("reloc is unresolved and cannot be turned to "
> > +			  "a runtime reloc in ELFCLASS%d"),
> > +			NN);
> > +
> > +		      /* loongarch_reloc_is_fatal will output
> > +			 "R_LARCH_32" or "R_LARCH_64" for us.  */
> I'd like to do this rejection earlier in `check_relocs` than
> `relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
> so this rejection should be efficient only for R_LARCH_32 on loongarch64.

Ok, in V3 I'll use the same approach as RISC-V then.


-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-27 12:39     ` Xi Ruoyao
@ 2024-06-27 17:19       ` Xi Ruoyao
  2024-06-28  1:53         ` Jinyang He
  0 siblings, 1 reply; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-27 17:19 UTC (permalink / raw)
  To: Jinyang He, binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Thu, 2024-06-27 at 20:39 +0800, Xi Ruoyao wrote:
> > I'd like to do this rejection earlier in `check_relocs` than
> > `relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
> > so this rejection should be efficient only for R_LARCH_32 on
> > loongarch64.
> 
> Ok, in V3 I'll use the same approach as RISC-V then.

And after some thinking: R_LARCH_64 on loongarch32 should be fine.  On
little-endian hardware *(uint64 *)pc += load_addr should be same as
*(uint32 *)pc += load_addr unless the latter wraps, but if it wraps
Glibc dynamic linker should complain anyway.

RISC-V also converts R_RISCV_64 to R_RISCV_RELATIVE for rv32.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-27 17:19       ` Xi Ruoyao
@ 2024-06-28  1:53         ` Jinyang He
  2024-06-28 17:04           ` Fangrui Song
  0 siblings, 1 reply; 21+ messages in thread
From: Jinyang He @ 2024-06-28  1:53 UTC (permalink / raw)
  To: Xi Ruoyao, binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On 2024-06-28 01:19, Xi Ruoyao wrote:

> On Thu, 2024-06-27 at 20:39 +0800, Xi Ruoyao wrote:
>>> I'd like to do this rejection earlier in `check_relocs` than
>>> `relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
>>> so this rejection should be efficient only for R_LARCH_32 on
>>> loongarch64.
>> Ok, in V3 I'll use the same approach as RISC-V then.
> And after some thinking: R_LARCH_64 on loongarch32 should be fine.  On
> little-endian hardware *(uint64 *)pc += load_addr should be same as
> *(uint32 *)pc += load_addr unless the latter wraps, but if it wraps
> Glibc dynamic linker should complain anyway.
>
> RISC-V also converts R_RISCV_64 to R_RISCV_RELATIVE for rv32.
Yes, you're right. I think we cannot avoid asm like `.8byte .L1` or
`.8byte .L1 - .L2`, so emiting 64bits static reloc type on loongarch32
makes sense.


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

* Re: [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries
  2024-06-26 10:04 ` [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries Xi Ruoyao
@ 2024-06-28  9:40   ` Jinyang He
  2024-06-28 12:39     ` Xi Ruoyao
  0 siblings, 1 reply; 21+ messages in thread
From: Jinyang He @ 2024-06-28  9:40 UTC (permalink / raw)
  To: Xi Ruoyao, binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

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

On 2024-06-26 18:04, Xi Ruoyao wrote:

> With a simple test case:
>
>      .globl  ifunc
>      .globl  ifunc_hidden
>      .hidden ifunc_hidden
>      .type   ifunc, %gnu_indirect_function
>      .type   ifunc_hidden, %gnu_indirect_function
>
>      .text
>      .align  2
>      ifunc:  ret
>      ifunc_hidden: ret
>
>      test:
>        bl ifunc
>        bl ifunc_hidden
>
> "ld -shared" produces a shared object with one R_LARCH_NONE (instead of
> R_LARCH_JUMP_SLOT as we expect) to relocate the GOT entry of "ifunc".
> It's because the indices in .plt and .rela.plt mismatches for
> STV_DEFAULT STT_IFUNC symbols when another PLT entry exists for a
> STV_HIDDEN STT_IFUNC symbol, and such a mismatch breaks the logic of
> loongarch_elf_finish_dynamic_symbol.  Fix the issue by reordering .plt
> so the indices no longer mismatch.
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
>   bfd/elfnn-loongarch.c                         | 77 ++++++++++++++++---
>   ld/testsuite/ld-loongarch-elf/ifunc-reloc.d   | 19 +++++
>   ld/testsuite/ld-loongarch-elf/ifunc-reloc.s   | 55 +++++++++++++
>   .../ld-loongarch-elf/ld-loongarch-elf.exp     |  1 +
>   4 files changed, 140 insertions(+), 12 deletions(-)
>   create mode 100644 ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
>   create mode 100644 ld/testsuite/ld-loongarch-elf/ifunc-reloc.s
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index 3a55ac93e20..c02e3f4bd9c 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -1691,9 +1691,10 @@ local_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
>      ifunc dynamic relocs.  */
>   
>   static bool
> -elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
> +elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h,
> +				struct bfd_link_info *info,
> +				bool ref_local)
>   {
> -  struct bfd_link_info *info;
>     /* An example of a bfd_link_hash_indirect symbol is versioned
>        symbol. For example: __gxx_personality_v0(bfd_link_hash_indirect)
>        -> __gxx_personality_v0(bfd_link_hash_defined)
> @@ -1709,20 +1710,18 @@ elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
>     if (h->root.type == bfd_link_hash_warning)
>       h = (struct elf_link_hash_entry *) h->root.u.i.link;
>   
> -  info = (struct bfd_link_info *) inf;
> -
>     /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it
>        here if it is defined and referenced in a non-shared object.  */
>     if (h->type == STT_GNU_IFUNC && h->def_regular)
>       {
> -      if (SYMBOL_REFERENCES_LOCAL (info, h))
> +      if (ref_local && SYMBOL_REFERENCES_LOCAL (info, h))
>   	return local_allocate_ifunc_dyn_relocs (info, h,
>   						&h->dyn_relocs,
>   						PLT_ENTRY_SIZE,
>   						PLT_HEADER_SIZE,
>   						GOT_ENTRY_SIZE,
>   						false);
> -      else
> +      else if (!ref_local && !SYMBOL_REFERENCES_LOCAL (info, h))
>   	return _bfd_elf_allocate_ifunc_dyn_relocs (info, h,
>   						   &h->dyn_relocs,
>   						   PLT_ENTRY_SIZE,
> @@ -1734,6 +1733,23 @@ elfNN_allocate_ifunc_dynrelocs (struct elf_link_hash_entry *h, void *inf)
>     return true;
>   }
>   
> +static bool
> +elfNN_allocate_ifunc_dynrelocs_ref_local (struct elf_link_hash_entry *h,
> +					  void *info)
> +{
> +  return elfNN_allocate_ifunc_dynrelocs (h, (struct bfd_link_info *) info,
> +					 true);
> +}
> +
> +static bool
> +elfNN_allocate_ifunc_dynrelocs_ref_global (struct elf_link_hash_entry *h,
> +					   void *info)
> +{
> +  return elfNN_allocate_ifunc_dynrelocs (h, (struct bfd_link_info *) info,
> +					 false);
> +}
> +
> +
>   /* Allocate space in .plt, .got and associated reloc sections for
>      ifunc dynamic relocs.  */
>   
> @@ -1749,7 +1765,7 @@ elfNN_allocate_local_ifunc_dynrelocs (void **slot, void *inf)
>         || h->root.type != bfd_link_hash_defined)
>       abort ();
>   
> -  return elfNN_allocate_ifunc_dynrelocs (h, inf);
> +  return elfNN_allocate_ifunc_dynrelocs_ref_local (h, inf);
>   }
>   
>   /* Set DF_TEXTREL if we find any dynamic relocs that apply to
> @@ -1909,11 +1925,48 @@ loongarch_elf_late_size_sections (bfd *output_bfd,
>        sym dynamic relocs.  */
>     elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
>   
> -  /* Allocate global ifunc sym .plt and .got entries, and space for global
> -     ifunc sym dynamic relocs.  */
> -  elf_link_hash_traverse (&htab->elf, elfNN_allocate_ifunc_dynrelocs, info);
> -
> -  /* Allocate .plt and .got entries, and space for local ifunc symbols.  */
> +  /* Allocate global ifunc sym .plt and .got entries, and space for
> +     *preemptible* ifunc sym dynamic relocs.  Note that we must do it
> +     for *all* preemptible ifunc (including local ifuncs and STV_HIDDEN
> +     ifuncs) before doing it for any non-preemptible ifunc symbol:
> +     assuming we are not so careful, when we link a shared library the
> +     correlation of .plt and .rela.plt might look like:
> +
> +				idx in .plt	idx in .rela.plt
> +	ext_func1@plt		0		0
> +	ext_func2@plt		1		1
> +	ext_func3@plt		2		2
> +	hidden_ifunc1@plt	3		None: it's in .rela.got
> +	hidden_ifunc2@plt	4		None: it's in .rela.got
> +	normal_ifunc1@plt	5	!=	3
> +	normal_ifunc2@plt	6	!=	4
> +	local_ifunc@plt		7		None: it's in .rela.got
> +
> +     Now oops the indices for normal_ifunc{1,2} in .rela.plt were different
> +     from the indices in .plt :(.  This would break finish_dynamic_symbol
> +     which assumes the index in .rela.plt matches the index in .plt.
> +
> +     So let's be careful and make it correct:
> +
> +				idx in .plt	idx in .rela.plt
> +	ext_func1@plt		0		0
> +	ext_func2@plt		1		1
> +	ext_func3@plt		2		2
> +	normal_ifunc1@plt	3		3
> +	normal_ifunc2@plt	4		4
> +	hidden_ifunc1@plt	5		None: it's in .rela.got
> +	hidden_ifunc2@plt	6		None: it's in .rela.got
> +	local_ifunc@plt		7		None: it's in .rela.got
> +
> +     Now normal_ifuncs first.  */
> +  elf_link_hash_traverse (&htab->elf,
> +			  elfNN_allocate_ifunc_dynrelocs_ref_global, info);
> +
> +  /* Now hidden_ifuncs ifuncs.  */
LGTM. It makes logic clear and simple!
Update "hidden_ifuncs" in the third patch?

Thanks.
> +  elf_link_hash_traverse (&htab->elf,
> +			  elfNN_allocate_ifunc_dynrelocs_ref_local, info);
> +
> +  /* Finally local ifuncs.  */
>     htab_traverse (htab->loc_hash_table,
>   		 elfNN_allocate_local_ifunc_dynrelocs, info);
>   
> diff --git a/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
> new file mode 100644
> index 00000000000..cb592874b1e
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.d
> @@ -0,0 +1,19 @@
> +#ld: -shared
> +#readelf: -Wr
> +
> +#...
> +.*'\.rela\.dyn'.*
> +#...
> +.* R_LARCH_RELATIVE .*
> +.* R_LARCH_IRELATIVE .*
> +.* R_LARCH_IRELATIVE .*
> +.* R_LARCH_IRELATIVE .*
> +#...
> +.*'\.rela\.plt'.*
> +#...
> +.* R_LARCH_JUMP_SLOT .*
> +.* R_LARCH_JUMP_SLOT .*
> +.* R_LARCH_JUMP_SLOT .*
> +.* R_LARCH_JUMP_SLOT .*
> +.* R_LARCH_JUMP_SLOT .*
> +.* R_LARCH_JUMP_SLOT .*
> diff --git a/ld/testsuite/ld-loongarch-elf/ifunc-reloc.s b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.s
> new file mode 100644
> index 00000000000..e59f2b20e36
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/ifunc-reloc.s
> @@ -0,0 +1,55 @@
> +.globl	foo
> +.globl	foo_hidden1
> +.globl	foo_hidden2
> +.globl	foo_protected
> +
> +.type	foo, %gnu_indirect_function
> +.type	foo_hidden1, %gnu_indirect_function
> +.type	foo_hidden2, %gnu_indirect_function
> +.type	foo_protected, %gnu_indirect_function
> +.type	foo_internal, %gnu_indirect_function
> +
> +.hidden	foo_hidden1
> +.hidden	foo_hidden2
> +
> +.protected	foo_protected
> +
> +.globl	ext_ifunc1
> +.globl	ext_ifunc2
> +.type	ext_ifunc1, %gnu_indirect_function
> +.type	ext_ifunc2, %gnu_indirect_function
> +
> +.text
> +.align	2
> +foo:
> +	ret
> +
> +foo_hidden1:
> +	ret
> +
> +foo_hidden2:
> +	ret
> +
> +foo_protected:
> +	ret
> +
> +foo_internal:
> +	ret
> +
> +test:
> +	la.got	$a0, num
> +	# The order is deliberately shuffled.
> +	bl	ext_ifunc1
> +	bl	foo
> +	bl	foo_hidden1
> +	bl	ext_func1
> +	bl	foo_protected
> +	bl	foo_internal
> +	bl	foo_hidden2
> +	bl	ext_func2
> +	bl	ext_ifunc2
> +
> +.data
> +.align	3
> +num:
> +	.quad	114514
> diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> index 4d9f4aebaff..6cff117e29b 100644
> --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> @@ -133,6 +133,7 @@ if [istarget "loongarch64-*-*"] {
>       run_dump_test "reloc_ler_with_shared"
>       run_dump_test "reloc_abs_with_shared"
>       run_dump_test "r_larch_32_elf64"
> +    run_dump_test "ifunc-reloc"
>     }
>   
>     if [check_pie_support] {

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

* Re: [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries
  2024-06-28  9:40   ` Jinyang He
@ 2024-06-28 12:39     ` Xi Ruoyao
  0 siblings, 0 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-28 12:39 UTC (permalink / raw)
  To: Jinyang He, binutils
  Cc: mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Fri, 2024-06-28 at 17:40 +0800, Jinyang He wrote:
> > +     Now normal_ifuncs first.  */
> > +  elf_link_hash_traverse (&htab->elf,
> > +			  elfNN_allocate_ifunc_dynrelocs_ref_global, info);
> > +
> > +  /* Now hidden_ifuncs ifuncs.  */
> 
>     LGTM. It makes logic clear and simple!
> 
>     Update "hidden_ifuncs" in the third patch?

Yes absolutely.  Actually I've seen this typo at least twice myself but
I just forgot to fix it each time :(.

Thanks for the reminder.

> > +  elf_link_hash_traverse (&htab->elf,
> > +			  elfNN_allocate_ifunc_dynrelocs_ref_local, info);
> > +
> > +  /* Finally local ifuncs.  */
> >    htab_traverse (htab->loc_hash_table,
> >  		 elfNN_allocate_local_ifunc_dynrelocs, info);

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-28  1:53         ` Jinyang He
@ 2024-06-28 17:04           ` Fangrui Song
  2024-06-29 13:56             ` Jinyang He
  0 siblings, 1 reply; 21+ messages in thread
From: Fangrui Song @ 2024-06-28 17:04 UTC (permalink / raw)
  To: Jinyang He, Xi Ruoyao
  Cc: binutils, mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Thu, Jun 27, 2024 at 6:53 PM Jinyang He <hejinyang@loongson.cn> wrote:
>
> On 2024-06-28 01:19, Xi Ruoyao wrote:
>
> > On Thu, 2024-06-27 at 20:39 +0800, Xi Ruoyao wrote:
> >>> I'd like to do this rejection earlier in `check_relocs` than
> >>> `relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
> >>> so this rejection should be efficient only for R_LARCH_32 on
> >>> loongarch64.
> >> Ok, in V3 I'll use the same approach as RISC-V then.
> > And after some thinking: R_LARCH_64 on loongarch32 should be fine.  On
> > little-endian hardware *(uint64 *)pc += load_addr should be same as
> > *(uint32 *)pc += load_addr unless the latter wraps, but if it wraps
> > Glibc dynamic linker should complain anyway.
> >
> > RISC-V also converts R_RISCV_64 to R_RISCV_RELATIVE for rv32.
> Yes, you're right. I think we cannot avoid asm like `.8byte .L1` or
> `.8byte .L1 - .L2`, so emiting 64bits static reloc type on loongarch32
> makes sense.
>

x86-32, aarch32, ppc32, and s390 ports do not support `.quad .L1`.
mips32 and riscv32 accept `.quad .L1`, which might be a mistake.

Why cannot '.8byte .L1` be avoided?

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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-28 17:04           ` Fangrui Song
@ 2024-06-29 13:56             ` Jinyang He
  2024-06-30  2:55               ` Xi Ruoyao
  0 siblings, 1 reply; 21+ messages in thread
From: Jinyang He @ 2024-06-29 13:56 UTC (permalink / raw)
  To: Fangrui Song, Xi Ruoyao
  Cc: binutils, mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

在 2024/6/29 1:04, Fangrui Song 写道:

> On Thu, Jun 27, 2024 at 6:53 PM Jinyang He <hejinyang@loongson.cn> wrote:
>> On 2024-06-28 01:19, Xi Ruoyao wrote:
>>
>>> On Thu, 2024-06-27 at 20:39 +0800, Xi Ruoyao wrote:
>>>>> I'd like to do this rejection earlier in `check_relocs` than
>>>>> `relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
>>>>> so this rejection should be efficient only for R_LARCH_32 on
>>>>> loongarch64.
>>>> Ok, in V3 I'll use the same approach as RISC-V then.
>>> And after some thinking: R_LARCH_64 on loongarch32 should be fine.  On
>>> little-endian hardware *(uint64 *)pc += load_addr should be same as
>>> *(uint32 *)pc += load_addr unless the latter wraps, but if it wraps
>>> Glibc dynamic linker should complain anyway.
>>>
>>> RISC-V also converts R_RISCV_64 to R_RISCV_RELATIVE for rv32.
>> Yes, you're right. I think we cannot avoid asm like `.8byte .L1` or
>> `.8byte .L1 - .L2`, so emiting 64bits static reloc type on loongarch32
>> makes sense.
>>
> x86-32, aarch32, ppc32, and s390 ports do not support `.quad .L1`.
> mips32 and riscv32 accept `.quad .L1`, which might be a mistake.
>
> Why cannot '.8byte .L1` be avoided?
Thank you for providing the detailed list. To be frankly, I sometimes see
how RISCV does and think how LoongArch should do. I'm sorry for lack
of in-depth thinking.

I think users may handwrite asm codes for 32-bits and 64 bits machines.
If we accept it, we can reduce the error. Users need to understand that
the value is 8 bytes as they excepted rather than the arch bits size.
Compilers such as gcc should not generate these asm codes.

If it is a clear mistake, I think we should fix it.

Thanks.


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

* Re: [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
  2024-06-29 13:56             ` Jinyang He
@ 2024-06-30  2:55               ` Xi Ruoyao
  0 siblings, 0 replies; 21+ messages in thread
From: Xi Ruoyao @ 2024-06-30  2:55 UTC (permalink / raw)
  To: Jinyang He, Fangrui Song
  Cc: binutils, mengqinggang, Zhensong Liu, i.swmail, maskray, Szabolcs Nagy

On Sat, 2024-06-29 at 21:56 +0800, Jinyang He wrote:
> 在 2024/6/29 1:04, Fangrui Song 写道:
> 
> > On Thu, Jun 27, 2024 at 6:53 PM Jinyang He <hejinyang@loongson.cn> wrote:
> > > On 2024-06-28 01:19, Xi Ruoyao wrote:
> > > 
> > > > On Thu, 2024-06-27 at 20:39 +0800, Xi Ruoyao wrote:
> > > > > > I'd like to do this rejection earlier in `check_relocs` than
> > > > > > `relocate_section`. Generally loongarch32 do not produce R_LARCH_64,
> > > > > > so this rejection should be efficient only for R_LARCH_32 on
> > > > > > loongarch64.
> > > > > Ok, in V3 I'll use the same approach as RISC-V then.
> > > > And after some thinking: R_LARCH_64 on loongarch32 should be fine.  On
> > > > little-endian hardware *(uint64 *)pc += load_addr should be same as
> > > > *(uint32 *)pc += load_addr unless the latter wraps, but if it wraps
> > > > Glibc dynamic linker should complain anyway.
> > > > 
> > > > RISC-V also converts R_RISCV_64 to R_RISCV_RELATIVE for rv32.
> > > Yes, you're right. I think we cannot avoid asm like `.8byte .L1` or
> > > `.8byte .L1 - .L2`, so emiting 64bits static reloc type on loongarch32
> > > makes sense.
> > > 
> > x86-32, aarch32, ppc32, and s390 ports do not support `.quad .L1`.
> > mips32 and riscv32 accept `.quad .L1`, which might be a mistake.
> > 
> > Why cannot '.8byte .L1` be avoided?
> Thank you for providing the detailed list. To be frankly, I sometimes see
> how RISCV does and think how LoongArch should do. I'm sorry for lack
> of in-depth thinking.
> 
> I think users may handwrite asm codes for 32-bits and 64 bits machines.

For supporting this IMO we should add more functionalities like

ld.p/st.p/ldptr.p/stptr.p/addi.p/add.p/sub.p

which is assembled to ld.d etc. for lp64, and ld.w etc. for ilp32.  Now
every project is defining a bunch of macros for these, and IMO it's
better to just support them in GAS so new projects won't need to define
their own macros anymore.

And similarly, for hard coding a pointer to x we can also add a
directive like ".ptr x", which behaves like ".4byte x" for ilp32 and
".8byte x" for lp64.

I'm modifying my code to "do things RISC-V is doing" for now.  When we
finalize ilp32 support we can revise.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

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

end of thread, other threads:[~2024-06-30  2:55 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-06-26 10:04 [PATCH v2 0/5] LoongArch: Add DT_RELR (packing relative relocs) support Xi Ruoyao
2024-06-26 10:04 ` [PATCH v2 1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64 Xi Ruoyao
2024-06-27 10:58   ` Jinyang He
2024-06-27 12:39     ` Xi Ruoyao
2024-06-27 17:19       ` Xi Ruoyao
2024-06-28  1:53         ` Jinyang He
2024-06-28 17:04           ` Fangrui Song
2024-06-29 13:56             ` Jinyang He
2024-06-30  2:55               ` Xi Ruoyao
2024-06-26 10:04 ` [PATCH v2 2/5] LoongArch: Fix bad reloc with mixed visibility ifunc symbols in shared libraries Xi Ruoyao
2024-06-28  9:40   ` Jinyang He
2024-06-28 12:39     ` Xi Ruoyao
2024-06-26 10:04 ` [PATCH v2 3/5] LoongArch: Make protected function symbols local for -shared Xi Ruoyao
2024-06-26 10:04 ` [PATCH v2 4/5] LoongArch: Add DT_RELR support Xi Ruoyao
2024-06-27  7:21   ` mengqinggang
2024-06-27 10:13     ` Xi Ruoyao
2024-06-27  7:27   ` mengqinggang
2024-06-27 10:16     ` Xi Ruoyao
2024-06-26 10:04 ` [PATCH v2 5/5] LoongArch: Add DT_RELR tests Xi Ruoyao
2024-06-27  7:11   ` mengqinggang
2024-06-27 10:14     ` Xi Ruoyao

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).