public inbox for glibc-cvs@sourceware.org help / color / mirror / Atom feed
From: Fangrui Song <maskray@sourceware.org> To: glibc-cvs@sourceware.org Subject: [glibc/maskray/relr] elf: Support DT_RELR relative relocation format [BZ #27924] Date: Sat, 16 Oct 2021 20:20:19 +0000 (GMT) [thread overview] Message-ID: <20211016202019.127783857C7B@sourceware.org> (raw) https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=fce13bcfa150cf9dcefdc1dccf72e025b16d2359 commit fce13bcfa150cf9dcefdc1dccf72e025b16d2359 Author: Fangrui Song <maskray@google.com> Date: Sat Oct 16 13:18:02 2021 -0700 elf: Support DT_RELR relative relocation format [BZ #27924] PIC objects (especially PIE and symbolic shared objects) usually have many relative relocations. In 2017/2018, SHT_RELR/DT_RELR was proposed on https://groups.google.com/g/generic-abi/c/bX460iggiKg/m/GxjM0L-PBAAJ ("Proposal for a new section type SHT_RELR") and is a pre-standard. This packed format can typically save 95% dynamic relocation section size for PIE. The vaddr size of a PIE can be 10% smaller. * Chrome OS folks have carried a local patch for a while (latest version: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/main/sys-libs/glibc/files/local/glibc-2.32). I.e. this feature has been battle tested. * Android bionic supports DT_RELR. * The Linux kernel has supported CONFIG_RELR since 2019-08 (https://git.kernel.org/linus/5cf896fb6be3effd9aea455b22213e27be8bdb1d). * A musl patch (by me) exists but is not applied: https://www.openwall.com/lists/musl/2019/03/06/3 I believe upstream glibc should support DT_RELR to benefit all Linux distributions. As of linker support (to the best of my knowledge): * LLD support DT_RELR. * https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/refs/heads/main/sys-devel/binutils/files/ has a gold patch. * GNU ld feature request https://sourceware.org/bugzilla/show_bug.cgi?id=27923 I wish that GNU ld and gold maintainers can implement the feature as well :) This patch is simpler than Chrome OS's glibc patch and makes ELF_DYNAMIC_DO_RELR available to all ports. I have adjusted aclocal.m4, otherwise it thinks ld.lld doesn't support --pack-dyn-relocs=relr just because ld.lld -v --help doesn't contain the literal string. % ld.lld -v --help | grep pack-dyn-relocs --pack-dyn-relocs=[none,android,relr,android+relr] (`$gnu_ld` is a lie: both gold and ld.lld's "User-Agent:" strings contain "GNU" and therefore make gnu_ld=true.) Tested on aarch64 and x86_64. Diff: --- configure | 31 +++++++++++++++++++++++++++++++ configure.ac | 4 ++++ elf/Makefile | 4 ++++ elf/dynamic-link.h | 25 +++++++++++++++++++++++++ elf/elf.h | 13 +++++++++++-- elf/get-dynamic-info.h | 3 +++ elf/tst-relr.c | 27 +++++++++++++++++++++++++++ 7 files changed, 105 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 3227e434d3..fdab6a97ef 100755 --- a/configure +++ b/configure @@ -6067,6 +6067,37 @@ $as_echo "$libc_linker_feature" >&6; } config_vars="$config_vars have-depaudit = $libc_cv_depaudit" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports --pack-dyn-relocs=relr" >&5 +$as_echo_n "checking for linker that supports --pack-dyn-relocs=relr... " >&6; } +libc_linker_feature=no +if test x"$gnu_ld" = x"yes"; then + cat > conftest.c <<EOF +int _start (void) { return 42; } +EOF + if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp + -Wl,--pack-dyn-relocs=relr -nostdlib -nostartfiles + -fPIC -shared -o conftest.so conftest.c + 1>&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + libc_linker_feature=yes + fi + rm -f conftest* +fi +if test $libc_linker_feature = yes; then + libc_cv_relr=yes +else + libc_cv_relr=no +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5 +$as_echo "$libc_linker_feature" >&6; } +config_vars="$config_vars +have-relr = $libc_cv_relr" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports --no-dynamic-linker" >&5 $as_echo_n "checking for linker that supports --no-dynamic-linker... " >&6; } libc_linker_feature=no diff --git a/configure.ac b/configure.ac index 00f49f09f7..96110f9d7d 100644 --- a/configure.ac +++ b/configure.ac @@ -1354,6 +1354,10 @@ LIBC_LINKER_FEATURE([--depaudit], [-Wl,--depaudit,x], [libc_cv_depaudit=yes], [libc_cv_depaudit=no]) LIBC_CONFIG_VAR([have-depaudit], [$libc_cv_depaudit]) +LIBC_LINKER_FEATURE([--pack-dyn-relocs=relr], [-Wl,--pack-dyn-relocs=relr], + [libc_cv_relr=yes], [libc_cv_relr=no]) +LIBC_CONFIG_VAR([have-relr], [$libc_cv_relr]) + LIBC_LINKER_FEATURE([--no-dynamic-linker], [-Wl,--no-dynamic-linker], [libc_cv_no_dynamic_linker=yes], diff --git a/elf/Makefile b/elf/Makefile index bf45d8ee24..2c4cdfac68 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -245,6 +245,10 @@ tests-special += $(objpfx)tst-audit14-cmp.out $(objpfx)tst-audit15-cmp.out \ $(objpfx)tst-audit16-cmp.out endif endif +ifeq ($(have-relr),yes) +tests += tst-relr +LDFLAGS-tst-relr += -Wl,--pack-dyn-relocs=relr +endif endif tests += $(tests-execstack-$(have-z-execstack)) ifeq ($(run-built-tests),yes) diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index ac4cc70dea..ced1c596be 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -160,6 +160,30 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], # define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do. */ # endif +# define ELF_DYNAMIC_DO_RELR(map) \ + do { \ + ElfW(Addr) l_addr = (map)->l_addr, *where = 0; \ + const ElfW(Relr) *r = 0, *end = 0; \ + if (!(map)->l_info[DT_RELR]) \ + break; \ + r = (const ElfW(Relr) *)D_PTR((map), l_info[DT_RELR]); \ + end = (const ElfW(Relr) *)((const char *)r + \ + (map)->l_info[DT_RELRSZ]->d_un.d_val); \ + for (; r < end; ++r) { \ + ElfW(Relr) entry = *r; \ + if ((entry & 1) == 0) { \ + where = (ElfW(Addr) *)(l_addr + entry); \ + *where++ += l_addr; \ + } else { \ + long i = 0; \ + for (; (entry >>= 1) != 0; i++) \ + if (entry % 2 != 0) \ + where[i] += l_addr; \ + where += 8 * sizeof(ElfW(Relr)) - 1; \ + } \ + } \ + } while (0); + /* This can't just be an inline function because GCC is too dumb to inline functions containing inlines themselves. */ # define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \ @@ -168,6 +192,7 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], (consider_profile)); \ ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \ ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc); \ + ELF_DYNAMIC_DO_RELR ((map)); \ } while (0) #endif diff --git a/elf/elf.h b/elf/elf.h index 50f87baceb..6dc1ee0ac0 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -443,7 +443,8 @@ typedef struct #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indices */ -#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_RELR 19 /* RELR relative relocations */ +#define SHT_NUM 20 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ @@ -662,6 +663,11 @@ typedef struct Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela; +/* RELR relocation table entry */ + +typedef Elf32_Word Elf32_Relr; +typedef Elf64_Xword Elf64_Relr; + /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) @@ -887,7 +893,10 @@ typedef struct #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_SYMTAB_SHNDX 34 /* Address of SYMTAB_SHNDX section */ -#define DT_NUM 35 /* Number used */ +#define DT_RELRSZ 35 /* Total size of RELR relative relocations */ +#define DT_RELR 36 /* Address of RELR relative relocations */ +#define DT_RELRENT 37 /* Size of one RELR relative relocaction */ +#define DT_NUM 38 /* Number used */ #define DT_LOOS 0x6000000d /* Start of OS-specific */ #define DT_HIOS 0x6ffff000 /* End of OS-specific */ #define DT_LOPROC 0x70000000 /* Start of processor-specific */ diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index 1ac0663d1f..ce0151c2b4 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -88,6 +88,7 @@ elf_get_dynamic_info (struct link_map *l) # if ! ELF_MACHINE_NO_REL ADJUST_DYN_INFO (DT_REL); # endif + ADJUST_DYN_INFO (DT_RELR); ADJUST_DYN_INFO (DT_JMPREL); ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH)); @@ -112,6 +113,8 @@ elf_get_dynamic_info (struct link_map *l) if (info[DT_REL] != NULL) assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); #endif + if (info[DT_RELR] != NULL) + assert (info[DT_RELRENT]->d_un.d_val == sizeof (ElfW(Relr))); #ifdef STATIC_PIE_BOOTSTRAP assert (info[DT_RUNPATH] == NULL); assert (info[DT_RPATH] == NULL); diff --git a/elf/tst-relr.c b/elf/tst-relr.c new file mode 100644 index 0000000000..79736a4a8a --- /dev/null +++ b/elf/tst-relr.c @@ -0,0 +1,27 @@ +static int o, x; + +#define ELEMS O O O O O O O O X X X X X X X O O X O O X X X E X E E O X O E +#define E 0, + +#define O &o, +#define X &x, +void *arr[] = { ELEMS }; +#undef O +#undef X + +#define O 1, +#define X 2, +static char val[] = { ELEMS }; + +static int +do_test (void) +{ + for (int i = 0; i < sizeof (arr) / sizeof (arr[0]); i++) + if (!((arr[i] == 0 && val[i] == 0) || + (arr[i] == &o && val[i] == 1) || + (arr[i] == &x && val[i] == 2))) + return 1; + return 0; +} + +#include <support/test-driver.c>
next reply other threads:[~2021-10-16 20:20 UTC|newest] Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-10-16 20:20 Fangrui Song [this message] -- strict thread matches above, loose matches on Subject: below -- 2022-03-09 1:20 Fangrui Song 2022-01-08 8:18 Fangrui Song 2022-01-08 8:18 Fangrui Song 2022-01-08 8:15 Fangrui Song 2022-01-05 3:26 Fangrui Song 2021-11-19 21:03 Fangrui Song 2021-10-29 22:21 Fangrui Song 2021-10-18 19:50 Fangrui Song 2021-10-18 19:49 Fangrui Song 2021-10-18 19:01 Fangrui Song 2021-10-18 19:00 Fangrui Song 2021-10-18 18:55 Fangrui Song 2021-10-18 18:55 Fangrui Song 2021-10-18 17:57 Fangrui Song 2021-10-18 17:57 Fangrui Song 2021-10-17 0:49 Fangrui Song 2021-10-17 0:49 Fangrui Song 2021-10-08 19:36 Fangrui Song
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20211016202019.127783857C7B@sourceware.org \ --to=maskray@sourceware.org \ --cc=glibc-cvs@sourceware.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).