tech-toolchain archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
RELR: compressed R_*_RELATIVE reloc section
[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.
http://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
http://web.archive.org/web/20241213012330/http://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.
http://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
http://gnats.NetBSD.org/59360
# HG changeset patch
# User Taylor R Campbell <riastradh%NetBSD.org@localhost>
# 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 <riastradh%NetBSD.org@localhost>
# 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.
http://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
http://web.archive.org/web/20241213012330/http://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 <riastradh%NetBSD.org@localhost>
# 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.
http://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
http://web.archive.org/web/20241213012330/http://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.
+ *
+ * http://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
+ * http://web.archive.org/web/20241213012330/http://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.
+ *
+ * http://groups.google.com/g/generic-abi/c/bX460iggiKg/m/Jnz1lgLJAgAJ
+ * http://web.archive.org/web/20241213012330/http://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
+}
Home |
Main Index |
Thread Index |
Old Index