[bcc tech-toolchain, followups to tech-userlevel cc me]

The attached patch teaches ld.elf_so(1) to understand RELR, a
compressed format for R_*_RELATIVE-type relocations that often
substantially reduces the sizes of position-independent executables,
much closer to the non-PIE versions.

The patch adds support when relocating shared objects and dynamic PIEs
(but not static PIEs or ld.elf_so itself).  Later, we might consider
flipping this on in bsd.*.mk on ports for which the toolchain supports
it.

OK?


Experiments conducted by other people show savings of many megabytes
in large executables like Chromium and Firefox when built as PIEs:

Rahul Chaudhry, `Re: Proposal for a new section type SHT_RELR',
generic-abi mailing list, 2018-02-07.
https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
https://web.archive.org/web/20241213012330/https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ

The code to implement RELR in ld.elf_so(1) is small (560 bytes on
amd64) -- likely dwarfed by the space saved by using RELR.  E.g., on
amd64 in current, the ntpd executable has a 59448-byte .rela.dyn
dominated by R_X86_64_RELATIVE; with -Wl,-z,pack-relative-relocs, that
becomes a 360-byte .rela.dyn and a 744-byte .relr.dyn.

GNU binutils has supported RELR, via the -Wl,-z,pack-relative-relocs
option, on amd64, i386, and powerpc since 2.38 -- we are on 2.42 in
current, so the toolchain support for these ports is already there.
(Since then, GNU binutils has added support on aarch64 and loongson.)

Other operating systems have adopted the same format:

- FreeBSD rtld since 13.1 in 2021
- OpenBSD ld.so since 7.1 2002
- glibc since 2.36 in 2022
- musl libc since 2022

Background reading:

Fangrui Song, `Relative relocations and RELR', MaskRay, 2021-10-31.
https://maskray.me/blog/2021-10-31-relative-relocations-and-relr

Change attached in two formats:
- pr59360-ldelfsorelr.patch -- piecemeal hg changeset series
- pr59360-ldelfsorelr.diff -- giant end-to-end diff

PR bin/59360: ld.elf_so(8): missing RELR support
https://gnats.NetBSD.org/59360
# HG changeset patch
# User Taylor R Campbell <riastr...@netbsd.org>
# Date 1745702701 0
#      Sat Apr 26 21:25:01 2025 +0000
# Branch trunk
# Node ID f673072924a94e661ab1235cc1911b82ec4d43ad
# Parent  13492505e6407eebf7935dde7c7d2668a01b2055
# EXP-Topic riastradh-pr59360-ldelfsorelr
ld.elf_so: Add a trivial test for R_*_RELATIVE relocations.

PR bin/59360: ld.elf_so(8): missing RELR support

diff -r 13492505e640 -r f673072924a9 distrib/sets/lists/debug/mi
--- a/distrib/sets/lists/debug/mi       Sat Apr 26 20:28:14 2025 +0000
+++ b/distrib/sets/lists/debug/mi       Sat Apr 26 21:25:01 2025 +0000
@@ -2455,6 +2455,8 @@
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_dl_symver_v2.debug   
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_ifunc.debug  
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_locking.debug        
tests-libexec-debug     debug,atf,pic,compattestfile
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_r_rel_nopack.debug   
tests-libexec-debug     debug,atf,pic,compattestfile
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_r_rel_pack.debug     
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-cleared.debug        
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-false.debug  
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlinfo.debug         
tests-libexec-debug     debug,atf,pic,compattestfile
diff -r 13492505e640 -r f673072924a9 distrib/sets/lists/tests/mi
--- a/distrib/sets/lists/tests/mi       Sat Apr 26 20:28:14 2025 +0000
+++ b/distrib/sets/lists/tests/mi       Sat Apr 26 21:25:01 2025 +0000
@@ -4264,6 +4264,8 @@
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso2     tests-libexec-tests     
compattestfile,atf
 ./usr/tests/libexec/ld.elf_so/h_ifunc                  tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/h_locking                        
tests-libexec-tests     compattestfile,atf,pic
+./usr/tests/libexec/ld.elf_so/h_r_rel_nopack           tests-libexec-tests     
compattestfile,atf,pic
+./usr/tests/libexec/ld.elf_so/h_r_rel_pack             tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/h_thread_local_dtor      tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_df_1_noopen            tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_dl_symver              tests-libexec-tests     
compattestfile,atf,pic
@@ -4276,6 +4278,7 @@
 ./usr/tests/libexec/ld.elf_so/t_ifunc_norelro          tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_ifunc_norelro_now      tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_ifunc_now              tests-libexec-tests     
compattestfile,atf,pic
+./usr/tests/libexec/ld.elf_so/t_r_rel                  tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_rtld_r_debug           tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_rtld_r_debug_nopie     tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_thread_local_dtor      tests-libexec-tests     
compattestfile,atf,pic
diff -r 13492505e640 -r f673072924a9 tests/libexec/ld.elf_so/Makefile
--- a/tests/libexec/ld.elf_so/Makefile  Sat Apr 26 20:28:14 2025 +0000
+++ b/tests/libexec/ld.elf_so/Makefile  Sat Apr 26 21:25:01 2025 +0000
@@ -80,6 +80,7 @@ LDADD.t_tls_extern+=  -Wl,-rpath,${TESTSD
 
 TESTS_SH+=             t_df_1_noopen
 TESTS_SH+=             t_dl_symver
+TESTS_SH+=             t_r_rel
 TESTS_SH+=             t_thread_local_dtor
 
 BINDIR=                        ${TESTSDIR}
@@ -117,6 +118,16 @@ SRCS.h_dl_symver_v2=       h_dl_symver.c
 V2ODIR!=               cd ${.CURDIR}/helper_symver_dso2 && ${PRINTOBJDIR}
 LDADD.h_dl_symver_v2=  -L${V2ODIR} -lh_helper_symver_dso
 
+PROGS+=                        h_r_rel_pack
+PROGS+=                        h_r_rel_nopack
+
+SRCS.h_r_rel_pack=     h_r_rel.c
+SRCS.h_r_rel_nopack=   h_r_rel.c
+
+h_r_rel_pack: CTFMERGE=:       # PR toolchain/59364: ctf tools needs update
+LDFLAGS.h_r_rel_pack=  -Wl,-z,pack-relative-relocs
+LDFLAGS.h_r_rel_nopack=        -Wl,-z,nopack-relative-relocs
+
 .include <bsd.test.mk>
 
 .else
diff -r 13492505e640 -r f673072924a9 tests/libexec/ld.elf_so/h_r_rel.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libexec/ld.elf_so/h_r_rel.c Sat Apr 26 21:25:01 2025 +0000
@@ -0,0 +1,146 @@
+/*     $NetBSD$        */
+
+/*-
+ * Copyright (c) 2025 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <stdio.h>
+
+/*
+ * When built as position-independent executable, the value of foop and
+ * foopp should be computed either via R_*_RELATIVE or R_*_REL32 or
+ * similar, which -- ports that support it -- may be compressed into a
+ * SHT_RELR section.
+ *
+ * One pointer indirection is enough to produce this effect, but we use
+ * two pointer indirections to increase the probability of a crash in
+ * case the relocations are done wrong.
+ */
+static int foo = 0x5f4d7635;
+static int *volatile foop = &foo;
+static int *volatile *volatile foopp = &foop;
+
+/*
+ * The RELR section compresses relocations for adjacent addresses into
+ * bitmaps of 31 or 63 bits apiece.  Create a bunch of consecutive
+ * addresses to relocate, punctuated by the occasional non-relocated
+ * address (null), to check for fencepost errors in the bitmap
+ * iteration.
+ */
+static int bar[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+       0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+       0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+       0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+};
+
+static int *volatile barp[] = {
+       &bar[0x00], &bar[0x01], &bar[0x02], &bar[0x03],
+       &bar[0x04], &bar[0x05], &bar[0x06], &bar[0x07],
+       &bar[0x08], &bar[0x09], &bar[0x0a], &bar[0x0b],
+       &bar[0x0c], &bar[0x0d], &bar[0x0e], &bar[0x0f],
+       &bar[0x10], &bar[0x11], &bar[0x12], &bar[0x13],
+       &bar[0x14], &bar[0x15], &bar[0x16], &bar[0x17],
+       &bar[0x18], &bar[0x19], &bar[0x1a], &bar[0x1b],
+       &bar[0x1c], &bar[0x1d], &bar[0x1e], &bar[0x1f],
+       &bar[0x20], &bar[0x21], &bar[0x22], &bar[0x23],
+       &bar[0x24], &bar[0x25], &bar[0x26], &bar[0x27],
+       &bar[0x28], &bar[0x29], &bar[0x2a], &bar[0x2b],
+       &bar[0x2c], &bar[0x2d], &bar[0x2e], &bar[0x2f],
+       &bar[0x30], &bar[0x31], &bar[0x32], &bar[0x33],
+       &bar[0x34], &bar[0x35], &bar[0x36], &bar[0x37],
+       &bar[0x38], &bar[0x39], &bar[0x3a], &bar[0x3b],
+       &bar[0x3c], &bar[0x3d], &bar[0x3e], &bar[0x3f],
+       NULL,       &bar[0x41], &bar[0x42], &bar[0x43], /* test a clear bit */
+       &bar[0x44], &bar[0x45], &bar[0x46], &bar[0x47],
+       &bar[0x48], &bar[0x49], &bar[0x4a], &bar[0x4b],
+       &bar[0x4c], &bar[0x4d], &bar[0x4e], &bar[0x4f],
+       &bar[0x50], &bar[0x51], &bar[0x52], &bar[0x53],
+       &bar[0x54], &bar[0x55], &bar[0x56], &bar[0x57],
+       &bar[0x58], &bar[0x59], &bar[0x5a], &bar[0x5b],
+       &bar[0x5c], &bar[0x5d], &bar[0x5e], &bar[0x5f],
+       &bar[0x60], &bar[0x61], &bar[0x62], &bar[0x63],
+       &bar[0x64], &bar[0x65], &bar[0x66], &bar[0x67],
+       &bar[0x68], &bar[0x69], &bar[0x6a], &bar[0x6b],
+       &bar[0x6c], &bar[0x6d], &bar[0x6e], &bar[0x6f],
+       &bar[0x70], &bar[0x71], &bar[0x72], &bar[0x73],
+       &bar[0x74], &bar[0x75], &bar[0x76], &bar[0x77],
+       &bar[0x78], &bar[0x79], &bar[0x7a], &bar[0x7b],
+       &bar[0x7c], &bar[0x7d], &bar[0x7e], &bar[0x7f],
+       NULL,           /* confirm we stop at the end */
+};
+
+static int baz = -0x1adbd477;
+static int *volatile bazp = &baz;
+
+int
+main(void)
+{
+       int i, result = 0;
+
+       if (**foopp != 0x5f4d7635) {
+               fprintf(stderr, "foo @ %p, foop = %p, *foop = %p,"
+                   " **foopp = 0x%x\n",
+                   &foo, foop, *foopp, **foopp);
+               result |= 1;
+       }
+       for (i = 0; i < (int)__arraycount(barp); i++) {
+               if (i == 0x40 || i == 0x80) {
+                       if (barp[i] != NULL) {
+                               fprintf(stderr, "barp[%u] = %p\n",
+                                   i, barp[i]);
+                       }
+               } else {
+                       if (*barp[i] != i) {
+                               fprintf(stderr, "bar[%u] @ %p, barp[%u] = %p,"
+                                   " *barp[%u] = %u\n",
+                                   i, &bar[i], i, barp[i], i, *barp[i]);
+                               result |= 1;
+                       }
+               }
+       }
+       if (*bazp != -0x1adbd477) {
+               fprintf(stderr, "baz @ %p, bazp = %p, *bazp = 0x%x\n",
+                   &baz, bazp, *bazp);
+               result |= 1;
+       }
+
+       return result;
+}
diff -r 13492505e640 -r f673072924a9 tests/libexec/ld.elf_so/t_r_rel.sh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libexec/ld.elf_so/t_r_rel.sh        Sat Apr 26 21:25:01 2025 +0000
@@ -0,0 +1,115 @@
+#      $NetBSD$
+#
+# Copyright (c) 2025 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+cleanup_core()
+{
+       local prog
+
+       prog=$1
+       test -f "${prog}.core" || return
+       readelf -rs "$(atf_get_srcdir)/${prog}"
+       gdb -batch -ex bt -ex 'info registers' -ex disas \
+           "$(atf_get_srcdir)/${prog}" "${prog}.core"
+}
+
+atf_test_case readelf_relative_nopack
+readelf_relative_nopack_head()
+{
+       atf_set "descr" "readelf R_*_RELATIVE with -z nopack-relative-relocs"
+       atf_set "require.progs" "readelf"
+}
+readelf_relative_nopack_body()
+{
+       atf_check -o match:'R_.*_REL' \
+           readelf -r "$(atf_get_srcdir)"/h_r_rel_nopack
+}
+
+atf_test_case readelf_relative_pack
+readelf_relative_pack_head()
+{
+       atf_set "descr" "readelf R_*_RELATIVE with -z pack-relative-relocs"
+       atf_set "require.progs" "readelf"
+}
+readelf_relative_pack_body()
+{
+       case `uname -p` in
+       i386|powerpc64*|x86_64)
+               ;;
+       *)      # Actually missing GNU binutils ld(1) support.
+               atf_expect_fail "PR bin/59360: ld.elf_so(8):" \
+                   " missing RELR support"
+               ;;
+       esac
+       atf_check -o not-match:'R_.*_REL' \
+           readelf -r "$(atf_get_srcdir)"/h_r_rel_pack
+}
+
+atf_test_case run_relative_nopack cleanup
+run_relative_nopack_head()
+{
+       atf_set "descr" "run R_*_RELATIVE with -z nopack-relative-relocs"
+}
+run_relative_nopack_body()
+{
+       atf_check "$(atf_get_srcdir)"/h_r_rel_nopack
+}
+run_relative_nopack_cleanup()
+{
+       cleanup_core h_r_rel_nopack
+}
+
+atf_test_case run_relative_pack cleanup
+run_relative_pack_head()
+{
+       atf_set "descr" "run R_*_RELATIVE with -z pack-relative-relocs"
+}
+run_relative_pack_body()
+{
+       case `uname -p` in
+       i386|powerpc64*|x86_64)
+               atf_expect_fail "PR bin/59360: ld.elf_so(8):"
+                   " missing RELR support"
+               ;;
+       *)      # Missing GNU binutils ld(1) support to generate RELR
+               # sections, so the program should run just fine because
+               # it just uses traditional REL/RELA instead.
+               ;;
+       esac
+       atf_check "$(atf_get_srcdir)"/h_r_rel_pack
+}
+run_relative_pack_cleanup()
+{
+       cleanup_core h_r_rel_pack
+}
+
+atf_init_test_cases()
+{
+       atf_add_test_case readelf_relative_nopack
+       atf_add_test_case readelf_relative_pack
+       atf_add_test_case run_relative_nopack
+       atf_add_test_case run_relative_pack
+}
# HG changeset patch
# User Taylor R Campbell <riastr...@netbsd.org>
# Date 1745709336 0
#      Sat Apr 26 23:15:36 2025 +0000
# Branch trunk
# Node ID 508beec7e3dd6d44e78a570a662e6edd40e87c7a
# Parent  f673072924a94e661ab1235cc1911b82ec4d43ad
# EXP-Topic riastradh-pr59360-ldelfsorelr
sys/exec_elf.h: Add RELR definitions.

The SHT_RELR .relr.dyn section, identified in DT_RELR dynamic tag,
holds compressed R_*_RELATIVE-type relocations, substantially
reducing the disk space occupied by many programs.

Reference:

Rahul Chaudhry, `Re: Proposal for a new section type SHT_RELR',
generic-abi mailing list, 2018-02-07.

https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
https://web.archive.org/web/20241213012330/https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ

PR bin/59360: ld.elf_so(8): missing RELR support

diff -r f673072924a9 -r 508beec7e3dd sys/sys/exec_elf.h
--- a/sys/sys/exec_elf.h        Sat Apr 26 21:25:01 2025 +0000
+++ b/sys/sys/exec_elf.h        Sat Apr 26 23:15:36 2025 +0000
@@ -517,7 +517,8 @@ typedef struct {
 #define SHT_PREINIT_ARRAY    16                /* Pre-initialization function 
ptrs */
 #define SHT_GROUP           17         /* Section group */
 #define SHT_SYMTAB_SHNDX     18                /* Section indexes (see 
SHN_XINDEX) */
-#define SHT_NUM                     19
+#define SHT_RELR            19         /* Relative relocation information */
+#define SHT_NUM                     20
 
 #define SHT_LOOS            0x60000000 /* Operating system specific range */
 #define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700   /* GNU incremental build data 
*/
@@ -681,6 +682,9 @@ typedef struct {
 #define ELF32_R_TYPE(info)     ((info) & 0xff)
 #define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type))
 
+/* Relative relocations (DT_RELR, SHT_RELR, .relr.dyn) */
+typedef Elf32_Word     Elf32_Relr;
+
 typedef struct {
        Elf64_Addr      r_offset;       /* where to do it */
        Elf64_Xword     r_info;         /* index & type of relocation */
@@ -697,6 +701,9 @@ typedef struct {
 #define ELF64_R_TYPE(info)     ((info) & 0xffffffff)
 #define ELF64_R_INFO(sym,type) (((sym) << 32) + (type))
 
+/* Relative relocations (DT_RELR, SHT_RELR, .relr.dyn) */
+typedef Elf64_Xword    Elf64_Relr;
+
 /*
  * Move entries
  */
@@ -798,7 +805,10 @@ typedef struct {
 #define DT_PREINIT_ARRAY 32    /* Address of pre-init function array */
 #define DT_PREINIT_ARRAYSZ 33  /* Size, in bytes, of DT_PREINIT_ARRAY array */
 #define DT_SYMTAB_SHNDX 34     /* Addr. of SHT_SYMTAB_SHNDX § of DT_SYMTAB */
-#define DT_NUM         35
+#define DT_RELRSZ      35      /* Size, in bytes, of DT_RELR table */
+#define DT_RELR                36      /* Address of Relr relocation table */
+#define DT_RELRENT     37      /* Size, in bytes, of one DT_RELR entry */
+#define DT_NUM         38
 
 #define DT_LOOS                0x60000000      /* Operating system specific 
range */
 #define DT_GNU_HASH    0x6ffffef5      /* GNU-style hash table */
@@ -1206,6 +1216,7 @@ struct netbsd_elfcore_procinfo {
 #define Elf_Sym                Elf32_Sym
 #define Elf_Rel                Elf32_Rel
 #define Elf_Rela       Elf32_Rela
+#define Elf_Relr       Elf32_Relr
 #define Elf_Dyn                Elf32_Dyn
 #define Elf_Word       Elf32_Word
 #define Elf_Sword      Elf32_Sword
@@ -1232,6 +1243,7 @@ struct netbsd_elfcore_procinfo {
 #define Elf_Sym                Elf64_Sym
 #define Elf_Rel                Elf64_Rel
 #define Elf_Rela       Elf64_Rela
+#define Elf_Relr       Elf64_Relr
 #define Elf_Dyn                Elf64_Dyn
 #define Elf_Word       Elf64_Word
 #define Elf_Sword      Elf64_Sword
# HG changeset patch
# User Taylor R Campbell <riastr...@netbsd.org>
# Date 1745710299 0
#      Sat Apr 26 23:31:39 2025 +0000
# Branch trunk
# Node ID 40467c0f0c9bd9a70414873f87a0ffd17da67dfd
# Parent  508beec7e3dd6d44e78a570a662e6edd40e87c7a
# EXP-Topic riastradh-pr59360-ldelfsorelr
ld.elf_so: Implement RELR relocations.

The SHT_RELR .relr.dyn section, identified in DT_RELR dynamic tag,
holds compressed R_*_RELATIVE-type relocations, substantially
reducing the disk space occupied by many programs.

Reference:

Rahul Chaudhry, `Re: Proposal for a new section type SHT_RELR',
generic-abi mailing list, 2018-02-07.

https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
https://web.archive.org/web/20241213012330/https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ

PR bin/59360: ld.elf_so(8): missing RELR support

diff -r 508beec7e3dd -r 40467c0f0c9b libexec/ld.elf_so/headers.c
--- a/libexec/ld.elf_so/headers.c       Sat Apr 26 23:15:36 2025 +0000
+++ b/libexec/ld.elf_so/headers.c       Sat Apr 26 23:31:39 2025 +0000
@@ -72,7 +72,7 @@ void
        const Elf_Dyn  *dyn_rpath = NULL;
        bool            use_pltrel = false;
        bool            use_pltrela = false;
-       Elf_Addr        relsz = 0, relasz = 0;
+       Elf_Addr        relsz = 0, relasz = 0, relrsz = 0;
        Elf_Addr        pltrel = 0, pltrelsz = 0;
 #ifdef RTLD_LOADER
        Elf_Addr        init = 0, fini = 0;
@@ -117,6 +117,19 @@ void
                        assert(dynp->d_un.d_val == sizeof(Elf_Rela));
                        break;
 
+               case DT_RELR:
+                       obj->relr = (const Elf_Relr *)(obj->relocbase +
+                           dynp->d_un.d_ptr);
+                       break;
+
+               case DT_RELRSZ:
+                       relrsz = dynp->d_un.d_val;
+                       break;
+
+               case DT_RELRENT:
+                       assert(dynp->d_un.d_val == sizeof(Elf_Relr));
+                       break;
+
                case DT_PLTREL:
                        use_pltrel = dynp->d_un.d_val == DT_REL;
                        use_pltrela = dynp->d_un.d_val == DT_RELA;
@@ -426,6 +439,7 @@ void
 
        obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
        obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
+       obj->relrlim = (const Elf_Relr *)((const uint8_t *)obj->relr + relrsz);
        if (use_pltrel) {
                obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
                obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + 
pltrelsz);
diff -r 508beec7e3dd -r 40467c0f0c9b libexec/ld.elf_so/reloc.c
--- a/libexec/ld.elf_so/reloc.c Sat Apr 26 23:15:36 2025 +0000
+++ b/libexec/ld.elf_so/reloc.c Sat Apr 26 23:31:39 2025 +0000
@@ -178,6 +178,80 @@ int
 }
 
 /*
+ * _rtld_relocate_relr(obj)
+ *
+ *     Relocate the RELR entries of obj.  The RELR table is encoded as
+ *     a sequence of alternating addresses and bitmaps.  Each address
+ *     entry has the low-order bit clear, and each bitmap has the
+ *     low-order bit set:
+ *
+ *             AAAAAAA0
+ *             BBBBBBB1
+ *             BBBBBBB1
+ *             BBBBBBB1
+ *             AAAAAAA0
+ *             BBBBBBB1
+ *             ...
+ *
+ *     Each address A is taken relative to obj->relocbase, and has
+ *     obj->relocbase added to the Elf_Addr it points at.  For each
+ *     bit i in the following bitmaps concatenated starting at 1,
+ *     excluding the low-order bit used to distinguish bitmaps from
+ *     addresses, the Elf_Addr at the address
+ *
+ *             A + sizeof(Elf_Addr)*i
+ *
+ *     (again, relative to obj->relocbase) has obj->relocbase added
+ *     too.
+ *
+ *     DT_RELR relocations are processed before any DT_REL or DT_RELA
+ *     relocations.
+ *
+ *     References:
+ *
+ *     Rahul Chaudhry, `Re: Proposal for a new section type SHT_RELR',
+ *     generic-abi mailing list, 2018-02-07.
+ *
+ *     https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
+ *     
https://web.archive.org/web/20241213012330/https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
+ */
+static void
+_rtld_relocate_relr(Obj_Entry *obj)
+{
+       const Elf_Relr *relr;
+       Elf_Addr *where;
+       unsigned i;
+
+       if (obj->relr == obj->relrlim)
+               return;
+
+       for (relr = obj->relr; relr < obj->relrlim;) {
+               /*
+                * At an address entry.  Relocate the address.
+                */
+               assert((*relr & 1) == 0);
+               where = (Elf_Addr *)(obj->relocbase + *relr);
+               *where++ += (Elf_Addr)obj->relocbase;
+
+               /*
+                * Process every bitmap entry after the address.
+                */
+               while (++relr < obj->relrlim && *relr & 1) {
+                       /*
+                        * Process every set bit in the bitmap.  Note
+                        * that the first bit (i=0) is not processed
+                        * here -- it's just metadata to mark a bitmap
+                        * entry.
+                        */
+                       for (i = 1; i < CHAR_BIT*sizeof(*relr); i++, where++) {
+                               if (*relr & ((Elf_Relr)1 << i))
+                                       *where += (Elf_Addr)obj->relocbase;
+                       }
+               }
+       }
+}
+
+/*
  * Relocate newly-loaded shared objects.  The argument is a pointer to
  * the Obj_Entry for the first such object.  All objects from the first
  * to the end of the list of objects are relocated.  Returns 0 on success,
@@ -220,6 +294,8 @@ int
                                return -1;
                        }
                }
+               dbg(("doing relative relocations"));
+               _rtld_relocate_relr(obj);
                dbg(("doing non-PLT relocations"));
                if (_rtld_relocate_nonplt_objects(obj) < 0)
                        ok = 0;
diff -r 508beec7e3dd -r 40467c0f0c9b libexec/ld.elf_so/rtld.h
--- a/libexec/ld.elf_so/rtld.h  Sat Apr 26 23:15:36 2025 +0000
+++ b/libexec/ld.elf_so/rtld.h  Sat Apr 26 23:31:39 2025 +0000
@@ -168,6 +168,8 @@ typedef struct Struct_Obj_Entry {
        const Elf_Rel  *rellim;         /* Limit of Relocation entries */
        const Elf_Rela *rela;           /* Relocation entries */
        const Elf_Rela *relalim;        /* Limit of Relocation entries */
+       const Elf_Relr *relr;           /* Relative relocations */
+       const Elf_Relr *relrlim;        /* Limit of relative relocations */
        const Elf_Rel  *pltrel;         /* PLT relocation entries */
        const Elf_Rel  *pltrellim;      /* Limit of PLT relocation entries */
        const Elf_Rela *pltrela;        /* PLT relocation entries */
diff -r 508beec7e3dd -r 40467c0f0c9b tests/libexec/ld.elf_so/t_r_rel.sh
--- a/tests/libexec/ld.elf_so/t_r_rel.sh        Sat Apr 26 23:15:36 2025 +0000
+++ b/tests/libexec/ld.elf_so/t_r_rel.sh        Sat Apr 26 23:31:39 2025 +0000
@@ -91,8 +91,6 @@ run_relative_pack_body()
 {
        case `uname -p` in
        i386|powerpc64*|x86_64)
-               atf_expect_fail "PR bin/59360: ld.elf_so(8):"
-                   " missing RELR support"
                ;;
        *)      # Missing GNU binutils ld(1) support to generate RELR
                # sections, so the program should run just fine because
diff -r 13492505e640 -r 40467c0f0c9b distrib/sets/lists/debug/mi
--- a/distrib/sets/lists/debug/mi       Sat Apr 26 20:28:14 2025 +0000
+++ b/distrib/sets/lists/debug/mi       Sat Apr 26 23:31:39 2025 +0000
@@ -2455,6 +2455,8 @@
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_dl_symver_v2.debug   
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_ifunc.debug  
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_locking.debug        
tests-libexec-debug     debug,atf,pic,compattestfile
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_r_rel_nopack.debug   
tests-libexec-debug     debug,atf,pic,compattestfile
+./usr/libdata/debug/usr/tests/libexec/ld.elf_so/h_r_rel_pack.debug     
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-cleared.debug        
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-false.debug  
tests-libexec-debug     debug,atf,pic,compattestfile
 ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlinfo.debug         
tests-libexec-debug     debug,atf,pic,compattestfile
diff -r 13492505e640 -r 40467c0f0c9b distrib/sets/lists/tests/mi
--- a/distrib/sets/lists/tests/mi       Sat Apr 26 20:28:14 2025 +0000
+++ b/distrib/sets/lists/tests/mi       Sat Apr 26 23:31:39 2025 +0000
@@ -4264,6 +4264,8 @@
 ./usr/tests/libexec/ld.elf_so/h_helper_symver_dso2     tests-libexec-tests     
compattestfile,atf
 ./usr/tests/libexec/ld.elf_so/h_ifunc                  tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/h_locking                        
tests-libexec-tests     compattestfile,atf,pic
+./usr/tests/libexec/ld.elf_so/h_r_rel_nopack           tests-libexec-tests     
compattestfile,atf,pic
+./usr/tests/libexec/ld.elf_so/h_r_rel_pack             tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/h_thread_local_dtor      tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_df_1_noopen            tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_dl_symver              tests-libexec-tests     
compattestfile,atf,pic
@@ -4276,6 +4278,7 @@
 ./usr/tests/libexec/ld.elf_so/t_ifunc_norelro          tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_ifunc_norelro_now      tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_ifunc_now              tests-libexec-tests     
compattestfile,atf,pic
+./usr/tests/libexec/ld.elf_so/t_r_rel                  tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_rtld_r_debug           tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_rtld_r_debug_nopie     tests-libexec-tests     
compattestfile,atf,pic
 ./usr/tests/libexec/ld.elf_so/t_thread_local_dtor      tests-libexec-tests     
compattestfile,atf,pic
diff -r 13492505e640 -r 40467c0f0c9b libexec/ld.elf_so/headers.c
--- a/libexec/ld.elf_so/headers.c       Sat Apr 26 20:28:14 2025 +0000
+++ b/libexec/ld.elf_so/headers.c       Sat Apr 26 23:31:39 2025 +0000
@@ -72,7 +72,7 @@ void
        const Elf_Dyn  *dyn_rpath = NULL;
        bool            use_pltrel = false;
        bool            use_pltrela = false;
-       Elf_Addr        relsz = 0, relasz = 0;
+       Elf_Addr        relsz = 0, relasz = 0, relrsz = 0;
        Elf_Addr        pltrel = 0, pltrelsz = 0;
 #ifdef RTLD_LOADER
        Elf_Addr        init = 0, fini = 0;
@@ -117,6 +117,19 @@ void
                        assert(dynp->d_un.d_val == sizeof(Elf_Rela));
                        break;
 
+               case DT_RELR:
+                       obj->relr = (const Elf_Relr *)(obj->relocbase +
+                           dynp->d_un.d_ptr);
+                       break;
+
+               case DT_RELRSZ:
+                       relrsz = dynp->d_un.d_val;
+                       break;
+
+               case DT_RELRENT:
+                       assert(dynp->d_un.d_val == sizeof(Elf_Relr));
+                       break;
+
                case DT_PLTREL:
                        use_pltrel = dynp->d_un.d_val == DT_REL;
                        use_pltrela = dynp->d_un.d_val == DT_RELA;
@@ -426,6 +439,7 @@ void
 
        obj->rellim = (const Elf_Rel *)((const uint8_t *)obj->rel + relsz);
        obj->relalim = (const Elf_Rela *)((const uint8_t *)obj->rela + relasz);
+       obj->relrlim = (const Elf_Relr *)((const uint8_t *)obj->relr + relrsz);
        if (use_pltrel) {
                obj->pltrel = (const Elf_Rel *)(obj->relocbase + pltrel);
                obj->pltrellim = (const Elf_Rel *)(obj->relocbase + pltrel + 
pltrelsz);
diff -r 13492505e640 -r 40467c0f0c9b libexec/ld.elf_so/reloc.c
--- a/libexec/ld.elf_so/reloc.c Sat Apr 26 20:28:14 2025 +0000
+++ b/libexec/ld.elf_so/reloc.c Sat Apr 26 23:31:39 2025 +0000
@@ -178,6 +178,80 @@ int
 }
 
 /*
+ * _rtld_relocate_relr(obj)
+ *
+ *     Relocate the RELR entries of obj.  The RELR table is encoded as
+ *     a sequence of alternating addresses and bitmaps.  Each address
+ *     entry has the low-order bit clear, and each bitmap has the
+ *     low-order bit set:
+ *
+ *             AAAAAAA0
+ *             BBBBBBB1
+ *             BBBBBBB1
+ *             BBBBBBB1
+ *             AAAAAAA0
+ *             BBBBBBB1
+ *             ...
+ *
+ *     Each address A is taken relative to obj->relocbase, and has
+ *     obj->relocbase added to the Elf_Addr it points at.  For each
+ *     bit i in the following bitmaps concatenated starting at 1,
+ *     excluding the low-order bit used to distinguish bitmaps from
+ *     addresses, the Elf_Addr at the address
+ *
+ *             A + sizeof(Elf_Addr)*i
+ *
+ *     (again, relative to obj->relocbase) has obj->relocbase added
+ *     too.
+ *
+ *     DT_RELR relocations are processed before any DT_REL or DT_RELA
+ *     relocations.
+ *
+ *     References:
+ *
+ *     Rahul Chaudhry, `Re: Proposal for a new section type SHT_RELR',
+ *     generic-abi mailing list, 2018-02-07.
+ *
+ *     https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
+ *     
https://web.archive.org/web/20241213012330/https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
+ */
+static void
+_rtld_relocate_relr(Obj_Entry *obj)
+{
+       const Elf_Relr *relr;
+       Elf_Addr *where;
+       unsigned i;
+
+       if (obj->relr == obj->relrlim)
+               return;
+
+       for (relr = obj->relr; relr < obj->relrlim;) {
+               /*
+                * At an address entry.  Relocate the address.
+                */
+               assert((*relr & 1) == 0);
+               where = (Elf_Addr *)(obj->relocbase + *relr);
+               *where++ += (Elf_Addr)obj->relocbase;
+
+               /*
+                * Process every bitmap entry after the address.
+                */
+               while (++relr < obj->relrlim && *relr & 1) {
+                       /*
+                        * Process every set bit in the bitmap.  Note
+                        * that the first bit (i=0) is not processed
+                        * here -- it's just metadata to mark a bitmap
+                        * entry.
+                        */
+                       for (i = 1; i < CHAR_BIT*sizeof(*relr); i++, where++) {
+                               if (*relr & ((Elf_Relr)1 << i))
+                                       *where += (Elf_Addr)obj->relocbase;
+                       }
+               }
+       }
+}
+
+/*
  * Relocate newly-loaded shared objects.  The argument is a pointer to
  * the Obj_Entry for the first such object.  All objects from the first
  * to the end of the list of objects are relocated.  Returns 0 on success,
@@ -220,6 +294,8 @@ int
                                return -1;
                        }
                }
+               dbg(("doing relative relocations"));
+               _rtld_relocate_relr(obj);
                dbg(("doing non-PLT relocations"));
                if (_rtld_relocate_nonplt_objects(obj) < 0)
                        ok = 0;
diff -r 13492505e640 -r 40467c0f0c9b libexec/ld.elf_so/rtld.h
--- a/libexec/ld.elf_so/rtld.h  Sat Apr 26 20:28:14 2025 +0000
+++ b/libexec/ld.elf_so/rtld.h  Sat Apr 26 23:31:39 2025 +0000
@@ -168,6 +168,8 @@ typedef struct Struct_Obj_Entry {
        const Elf_Rel  *rellim;         /* Limit of Relocation entries */
        const Elf_Rela *rela;           /* Relocation entries */
        const Elf_Rela *relalim;        /* Limit of Relocation entries */
+       const Elf_Relr *relr;           /* Relative relocations */
+       const Elf_Relr *relrlim;        /* Limit of relative relocations */
        const Elf_Rel  *pltrel;         /* PLT relocation entries */
        const Elf_Rel  *pltrellim;      /* Limit of PLT relocation entries */
        const Elf_Rela *pltrela;        /* PLT relocation entries */
diff -r 13492505e640 -r 40467c0f0c9b sys/sys/exec_elf.h
--- a/sys/sys/exec_elf.h        Sat Apr 26 20:28:14 2025 +0000
+++ b/sys/sys/exec_elf.h        Sat Apr 26 23:31:39 2025 +0000
@@ -517,7 +517,8 @@ typedef struct {
 #define SHT_PREINIT_ARRAY    16                /* Pre-initialization function 
ptrs */
 #define SHT_GROUP           17         /* Section group */
 #define SHT_SYMTAB_SHNDX     18                /* Section indexes (see 
SHN_XINDEX) */
-#define SHT_NUM                     19
+#define SHT_RELR            19         /* Relative relocation information */
+#define SHT_NUM                     20
 
 #define SHT_LOOS            0x60000000 /* Operating system specific range */
 #define SHT_GNU_INCREMENTAL_INPUTS 0x6fff4700   /* GNU incremental build data 
*/
@@ -681,6 +682,9 @@ typedef struct {
 #define ELF32_R_TYPE(info)     ((info) & 0xff)
 #define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type))
 
+/* Relative relocations (DT_RELR, SHT_RELR, .relr.dyn) */
+typedef Elf32_Word     Elf32_Relr;
+
 typedef struct {
        Elf64_Addr      r_offset;       /* where to do it */
        Elf64_Xword     r_info;         /* index & type of relocation */
@@ -697,6 +701,9 @@ typedef struct {
 #define ELF64_R_TYPE(info)     ((info) & 0xffffffff)
 #define ELF64_R_INFO(sym,type) (((sym) << 32) + (type))
 
+/* Relative relocations (DT_RELR, SHT_RELR, .relr.dyn) */
+typedef Elf64_Xword    Elf64_Relr;
+
 /*
  * Move entries
  */
@@ -798,7 +805,10 @@ typedef struct {
 #define DT_PREINIT_ARRAY 32    /* Address of pre-init function array */
 #define DT_PREINIT_ARRAYSZ 33  /* Size, in bytes, of DT_PREINIT_ARRAY array */
 #define DT_SYMTAB_SHNDX 34     /* Addr. of SHT_SYMTAB_SHNDX § of DT_SYMTAB */
-#define DT_NUM         35
+#define DT_RELRSZ      35      /* Size, in bytes, of DT_RELR table */
+#define DT_RELR                36      /* Address of Relr relocation table */
+#define DT_RELRENT     37      /* Size, in bytes, of one DT_RELR entry */
+#define DT_NUM         38
 
 #define DT_LOOS                0x60000000      /* Operating system specific 
range */
 #define DT_GNU_HASH    0x6ffffef5      /* GNU-style hash table */
@@ -1206,6 +1216,7 @@ struct netbsd_elfcore_procinfo {
 #define Elf_Sym                Elf32_Sym
 #define Elf_Rel                Elf32_Rel
 #define Elf_Rela       Elf32_Rela
+#define Elf_Relr       Elf32_Relr
 #define Elf_Dyn                Elf32_Dyn
 #define Elf_Word       Elf32_Word
 #define Elf_Sword      Elf32_Sword
@@ -1232,6 +1243,7 @@ struct netbsd_elfcore_procinfo {
 #define Elf_Sym                Elf64_Sym
 #define Elf_Rel                Elf64_Rel
 #define Elf_Rela       Elf64_Rela
+#define Elf_Relr       Elf64_Relr
 #define Elf_Dyn                Elf64_Dyn
 #define Elf_Word       Elf64_Word
 #define Elf_Sword      Elf64_Sword
diff -r 13492505e640 -r 40467c0f0c9b tests/libexec/ld.elf_so/Makefile
--- a/tests/libexec/ld.elf_so/Makefile  Sat Apr 26 20:28:14 2025 +0000
+++ b/tests/libexec/ld.elf_so/Makefile  Sat Apr 26 23:31:39 2025 +0000
@@ -80,6 +80,7 @@ LDADD.t_tls_extern+=  -Wl,-rpath,${TESTSD
 
 TESTS_SH+=             t_df_1_noopen
 TESTS_SH+=             t_dl_symver
+TESTS_SH+=             t_r_rel
 TESTS_SH+=             t_thread_local_dtor
 
 BINDIR=                        ${TESTSDIR}
@@ -117,6 +118,16 @@ SRCS.h_dl_symver_v2=       h_dl_symver.c
 V2ODIR!=               cd ${.CURDIR}/helper_symver_dso2 && ${PRINTOBJDIR}
 LDADD.h_dl_symver_v2=  -L${V2ODIR} -lh_helper_symver_dso
 
+PROGS+=                        h_r_rel_pack
+PROGS+=                        h_r_rel_nopack
+
+SRCS.h_r_rel_pack=     h_r_rel.c
+SRCS.h_r_rel_nopack=   h_r_rel.c
+
+h_r_rel_pack: CTFMERGE=:       # PR toolchain/59364: ctf tools needs update
+LDFLAGS.h_r_rel_pack=  -Wl,-z,pack-relative-relocs
+LDFLAGS.h_r_rel_nopack=        -Wl,-z,nopack-relative-relocs
+
 .include <bsd.test.mk>
 
 .else
diff -r 13492505e640 -r 40467c0f0c9b tests/libexec/ld.elf_so/h_r_rel.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libexec/ld.elf_so/h_r_rel.c Sat Apr 26 23:31:39 2025 +0000
@@ -0,0 +1,146 @@
+/*     $NetBSD$        */
+
+/*-
+ * Copyright (c) 2025 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD$");
+
+#include <stdio.h>
+
+/*
+ * When built as position-independent executable, the value of foop and
+ * foopp should be computed either via R_*_RELATIVE or R_*_REL32 or
+ * similar, which -- ports that support it -- may be compressed into a
+ * SHT_RELR section.
+ *
+ * One pointer indirection is enough to produce this effect, but we use
+ * two pointer indirections to increase the probability of a crash in
+ * case the relocations are done wrong.
+ */
+static int foo = 0x5f4d7635;
+static int *volatile foop = &foo;
+static int *volatile *volatile foopp = &foop;
+
+/*
+ * The RELR section compresses relocations for adjacent addresses into
+ * bitmaps of 31 or 63 bits apiece.  Create a bunch of consecutive
+ * addresses to relocate, punctuated by the occasional non-relocated
+ * address (null), to check for fencepost errors in the bitmap
+ * iteration.
+ */
+static int bar[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+       0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+       0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+       0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+       0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+       0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+       0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+       0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+       0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+       0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+       0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+};
+
+static int *volatile barp[] = {
+       &bar[0x00], &bar[0x01], &bar[0x02], &bar[0x03],
+       &bar[0x04], &bar[0x05], &bar[0x06], &bar[0x07],
+       &bar[0x08], &bar[0x09], &bar[0x0a], &bar[0x0b],
+       &bar[0x0c], &bar[0x0d], &bar[0x0e], &bar[0x0f],
+       &bar[0x10], &bar[0x11], &bar[0x12], &bar[0x13],
+       &bar[0x14], &bar[0x15], &bar[0x16], &bar[0x17],
+       &bar[0x18], &bar[0x19], &bar[0x1a], &bar[0x1b],
+       &bar[0x1c], &bar[0x1d], &bar[0x1e], &bar[0x1f],
+       &bar[0x20], &bar[0x21], &bar[0x22], &bar[0x23],
+       &bar[0x24], &bar[0x25], &bar[0x26], &bar[0x27],
+       &bar[0x28], &bar[0x29], &bar[0x2a], &bar[0x2b],
+       &bar[0x2c], &bar[0x2d], &bar[0x2e], &bar[0x2f],
+       &bar[0x30], &bar[0x31], &bar[0x32], &bar[0x33],
+       &bar[0x34], &bar[0x35], &bar[0x36], &bar[0x37],
+       &bar[0x38], &bar[0x39], &bar[0x3a], &bar[0x3b],
+       &bar[0x3c], &bar[0x3d], &bar[0x3e], &bar[0x3f],
+       NULL,       &bar[0x41], &bar[0x42], &bar[0x43], /* test a clear bit */
+       &bar[0x44], &bar[0x45], &bar[0x46], &bar[0x47],
+       &bar[0x48], &bar[0x49], &bar[0x4a], &bar[0x4b],
+       &bar[0x4c], &bar[0x4d], &bar[0x4e], &bar[0x4f],
+       &bar[0x50], &bar[0x51], &bar[0x52], &bar[0x53],
+       &bar[0x54], &bar[0x55], &bar[0x56], &bar[0x57],
+       &bar[0x58], &bar[0x59], &bar[0x5a], &bar[0x5b],
+       &bar[0x5c], &bar[0x5d], &bar[0x5e], &bar[0x5f],
+       &bar[0x60], &bar[0x61], &bar[0x62], &bar[0x63],
+       &bar[0x64], &bar[0x65], &bar[0x66], &bar[0x67],
+       &bar[0x68], &bar[0x69], &bar[0x6a], &bar[0x6b],
+       &bar[0x6c], &bar[0x6d], &bar[0x6e], &bar[0x6f],
+       &bar[0x70], &bar[0x71], &bar[0x72], &bar[0x73],
+       &bar[0x74], &bar[0x75], &bar[0x76], &bar[0x77],
+       &bar[0x78], &bar[0x79], &bar[0x7a], &bar[0x7b],
+       &bar[0x7c], &bar[0x7d], &bar[0x7e], &bar[0x7f],
+       NULL,           /* confirm we stop at the end */
+};
+
+static int baz = -0x1adbd477;
+static int *volatile bazp = &baz;
+
+int
+main(void)
+{
+       int i, result = 0;
+
+       if (**foopp != 0x5f4d7635) {
+               fprintf(stderr, "foo @ %p, foop = %p, *foop = %p,"
+                   " **foopp = 0x%x\n",
+                   &foo, foop, *foopp, **foopp);
+               result |= 1;
+       }
+       for (i = 0; i < (int)__arraycount(barp); i++) {
+               if (i == 0x40 || i == 0x80) {
+                       if (barp[i] != NULL) {
+                               fprintf(stderr, "barp[%u] = %p\n",
+                                   i, barp[i]);
+                       }
+               } else {
+                       if (*barp[i] != i) {
+                               fprintf(stderr, "bar[%u] @ %p, barp[%u] = %p,"
+                                   " *barp[%u] = %u\n",
+                                   i, &bar[i], i, barp[i], i, *barp[i]);
+                               result |= 1;
+                       }
+               }
+       }
+       if (*bazp != -0x1adbd477) {
+               fprintf(stderr, "baz @ %p, bazp = %p, *bazp = 0x%x\n",
+                   &baz, bazp, *bazp);
+               result |= 1;
+       }
+
+       return result;
+}
diff -r 13492505e640 -r 40467c0f0c9b tests/libexec/ld.elf_so/t_r_rel.sh
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/libexec/ld.elf_so/t_r_rel.sh        Sat Apr 26 23:31:39 2025 +0000
@@ -0,0 +1,113 @@
+#      $NetBSD$
+#
+# Copyright (c) 2025 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+cleanup_core()
+{
+       local prog
+
+       prog=$1
+       test -f "${prog}.core" || return
+       readelf -rs "$(atf_get_srcdir)/${prog}"
+       gdb -batch -ex bt -ex 'info registers' -ex disas \
+           "$(atf_get_srcdir)/${prog}" "${prog}.core"
+}
+
+atf_test_case readelf_relative_nopack
+readelf_relative_nopack_head()
+{
+       atf_set "descr" "readelf R_*_RELATIVE with -z nopack-relative-relocs"
+       atf_set "require.progs" "readelf"
+}
+readelf_relative_nopack_body()
+{
+       atf_check -o match:'R_.*_REL' \
+           readelf -r "$(atf_get_srcdir)"/h_r_rel_nopack
+}
+
+atf_test_case readelf_relative_pack
+readelf_relative_pack_head()
+{
+       atf_set "descr" "readelf R_*_RELATIVE with -z pack-relative-relocs"
+       atf_set "require.progs" "readelf"
+}
+readelf_relative_pack_body()
+{
+       case `uname -p` in
+       i386|powerpc64*|x86_64)
+               ;;
+       *)      # Actually missing GNU binutils ld(1) support.
+               atf_expect_fail "PR bin/59360: ld.elf_so(8):" \
+                   " missing RELR support"
+               ;;
+       esac
+       atf_check -o not-match:'R_.*_REL' \
+           readelf -r "$(atf_get_srcdir)"/h_r_rel_pack
+}
+
+atf_test_case run_relative_nopack cleanup
+run_relative_nopack_head()
+{
+       atf_set "descr" "run R_*_RELATIVE with -z nopack-relative-relocs"
+}
+run_relative_nopack_body()
+{
+       atf_check "$(atf_get_srcdir)"/h_r_rel_nopack
+}
+run_relative_nopack_cleanup()
+{
+       cleanup_core h_r_rel_nopack
+}
+
+atf_test_case run_relative_pack cleanup
+run_relative_pack_head()
+{
+       atf_set "descr" "run R_*_RELATIVE with -z pack-relative-relocs"
+}
+run_relative_pack_body()
+{
+       case `uname -p` in
+       i386|powerpc64*|x86_64)
+               ;;
+       *)      # Missing GNU binutils ld(1) support to generate RELR
+               # sections, so the program should run just fine because
+               # it just uses traditional REL/RELA instead.
+               ;;
+       esac
+       atf_check "$(atf_get_srcdir)"/h_r_rel_pack
+}
+run_relative_pack_cleanup()
+{
+       cleanup_core h_r_rel_pack
+}
+
+atf_init_test_cases()
+{
+       atf_add_test_case readelf_relative_nopack
+       atf_add_test_case readelf_relative_pack
+       atf_add_test_case run_relative_nopack
+       atf_add_test_case run_relative_pack
+}

Reply via email to