summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2022-04-25 16:50:00 -0700
committerFangrui Song <maskray@google.com>2022-04-25 16:50:00 -0700
commitda683b1f1037bf63b0c42f79a8a46f58670b2fed (patch)
tree9089d992c32c7b6d3a462cd32d76a02a8b41e8af
parentd3c732cb4383d02e5d3099d87766e5853acf9ff8 (diff)
downloadglibc-da683b1f1037bf63b0c42f79a8a46f58670b2fed.tar.gz
elf: Support DT_RELR relative relocation format
Adapted from https://sourceware.org/pipermail/libc-alpha/2022-April/138085.html ([PATCH v11 0/7] Support DT_RELR relative relocation format), which is expected to be included in glibc 2.36. glibc 2.35 has a fair amount of rtld changes to avoid nested functions (https://sourceware.org/PR27220). This patch is carefully crafted to make the minimal changes. Notebly, this commit * works around b/208156916 by not bumping DT_NUM. DT_RELR and DT_RELRSZ take the l_info slots at DT_VERSYM+1 and DT_VERSYM+2. * avoids changes to include/link.h * removes the time travel compatibility check (error if DT_RELR is used without GLIBC_ABI_DT_RELR version need). This needs link.h change and the detected case cannot happen if we correctly use -Wl,-z,pack-relative-relocs.
-rwxr-xr-xconfigure75
-rw-r--r--configure.ac5
-rw-r--r--elf/Makefile91
-rw-r--r--elf/Versions5
-rw-r--r--elf/dynamic-link.h42
-rw-r--r--elf/elf.h15
-rw-r--r--elf/get-dynamic-info.h26
-rw-r--r--elf/tst-relr-mod2.c46
-rw-r--r--elf/tst-relr-mod3a.c49
-rw-r--r--elf/tst-relr-mod3b.c22
-rw-r--r--elf/tst-relr-mod4a.c19
-rw-r--r--elf/tst-relr-mod4b.c19
-rw-r--r--elf/tst-relr-mod4b.map3
-rw-r--r--elf/tst-relr-pie.c1
-rw-r--r--elf/tst-relr.c65
-rw-r--r--elf/tst-relr2.c27
-rw-r--r--elf/tst-relr3.c27
-rw-r--r--elf/tst-relr4.c1
-rw-r--r--scripts/versions.awk7
19 files changed, 511 insertions, 34 deletions
diff --git a/configure b/configure
index 95887b7078..447318e678 100755
--- a/configure
+++ b/configure
@@ -730,7 +730,6 @@ infodir
docdir
oldincludedir
includedir
-runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -844,7 +843,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1097,15 +1095,6 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
- -runstatedir | --runstatedir | --runstatedi | --runstated \
- | --runstate | --runstat | --runsta | --runst | --runs \
- | --run | --ru | --r)
- ac_prev=runstatedir ;;
- -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
- | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
- | --run=* | --ru=* | --r=*)
- runstatedir=$ac_optarg ;;
-
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1243,7 +1232,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir runstatedir
+ libdir localedir mandir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1396,7 +1385,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
- --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -5879,22 +5867,25 @@ fi
$as_echo_n "checking for linker that supports -z execstack... " >&6; }
libc_linker_feature=no
if test x"$gnu_ld" = x"yes"; then
- cat > conftest.c <<EOF
+ libc_linker_check=`$LD -v --help 2>/dev/null | grep "\-z execstack"`
+ if test -n "$libc_linker_check"; then
+ cat > conftest.c <<EOF
int _start (void) { return 42; }
EOF
- if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
- -Wl,-z,execstack -nostdlib -nostartfiles
- -fPIC -shared -o conftest.so conftest.c
- 1>&5'
+ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
+ -Wl,-z,execstack -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
+ then
+ libc_linker_feature=yes
+ fi
+ rm -f conftest*
fi
- rm -f conftest*
fi
if test $libc_linker_feature = yes; then
libc_cv_z_execstack=yes
@@ -5909,11 +5900,45 @@ $as_echo "$libc_linker_feature" >&6; }
$as_echo_n "checking for linker that supports -z start-stop-gc... " >&6; }
libc_linker_feature=no
if test x"$gnu_ld" = x"yes"; then
+ libc_linker_check=`$LD -v --help 2>/dev/null | grep "\-z start-stop-gc"`
+ if test -n "$libc_linker_check"; then
+ cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+ if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
+ -Wl,-z,start-stop-gc -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
+fi
+if test $libc_linker_feature = yes; then
+ libc_cv_z_start_stop_gc=yes
+else
+ libc_cv_z_start_stop_gc=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-z-start-stop-gc = $libc_cv_z_start_stop_gc"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z pack-relative-relocs" >&5
+$as_echo_n "checking for linker that supports -z pack-relative-relocs... " >&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,-z,start-stop-gc -nostdlib -nostartfiles
+ -Wl,-z,pack-relative-relocs -nostdlib -nostartfiles
-fPIC -shared -o conftest.so conftest.c
1>&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
@@ -5927,14 +5952,14 @@ EOF
rm -f conftest*
fi
if test $libc_linker_feature = yes; then
- libc_cv_z_start_stop_gc=yes
+ libc_cv_dt_relr=yes
else
- libc_cv_z_start_stop_gc=no
+ libc_cv_dt_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-z-start-stop-gc = $libc_cv_z_start_stop_gc"
+have-dt-relr = $libc_cv_dt_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; }
diff --git a/configure.ac b/configure.ac
index b3505fce40..b1a1530dba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1354,6 +1354,11 @@ LIBC_LINKER_FEATURE([-z start-stop-gc], [-Wl,-z,start-stop-gc],
[libc_cv_z_start_stop_gc=yes], [libc_cv_z_start_stop_gc=no])
LIBC_CONFIG_VAR([have-z-start-stop-gc], [$libc_cv_z_start_stop_gc])
+LIBC_LINKER_FEATURE([-z pack-relative-relocs],
+ [-Wl,-z,pack-relative-relocs],
+ [libc_cv_dt_relr=yes], [libc_cv_dt_relr=no])
+LIBC_CONFIG_VAR([have-dt-relr], [$libc_cv_dt_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 1b9acb5242..7b44740999 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -209,6 +209,44 @@ tests-execstack-yes = tst-execstack tst-execstack-needed tst-execstack-prog
endif
endif
endif
+ifeq ($(have-dt-relr),yes)
+tests += \
+ tst-relr \
+ tst-relr2 \
+ tst-relr3 \
+ tst-relr4 \
+# tests
+modules-names-dt-relr = \
+ tst-relr-mod2 \
+ tst-relr-mod3a \
+ tst-relr-mod3b \
+ tst-relr-mod4a \
+ tst-relr-mod4b \
+# modules-names-dt-relr
+modules-names += $(modules-names-dt-relr)
+# These shared libraries have special build rules.
+modules-names-nobuild += $(modules-names-dt-relr)
+ifeq ($(have-fpie),yes)
+tests += \
+ tst-relr-pie \
+# tests
+tests-pie += \
+ tst-relr-pie \
+# tests-pie
+tests-special += \
+ $(objpfx)check-tst-relr-pie.out \
+# tests-special
+endif
+CFLAGS-tst-relr-pie.c += $(pie-ccflag)
+LDFLAGS-tst-relr += -Wl,-z,pack-relative-relocs
+LDFLAGS-tst-relr-pie += -Wl,-z,pack-relative-relocs
+LDFLAGS-tst-relr2 += -Wl,--allow-shlib-undefined
+CFLAGS-tst-relr-mod2.c += $(no-stack-protector)
+CFLAGS-tst-relr-mod3a.c += $(no-stack-protector)
+CFLAGS-tst-relr-mod3b.c += $(no-stack-protector)
+CFLAGS-tst-relr-mod4a.c += $(no-stack-protector)
+CFLAGS-tst-relr-mod4b.c += $(no-stack-protector)
+endif
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-leaks1-mem.out \
$(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
@@ -1482,3 +1520,56 @@ $(objpfx)tst-dlopen-offset-comb.so: $(objpfx)tst-dlopen-offset-mod1.so $(objpfx)
dd if=$(objpfx)tst-dlopen-offset-mod3.so of=$(objpfx)tst-dlopen-offset-comb.so bs=1024 seek=192
$(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
+
+$(objpfx)check-tst-relr-pie.out: $(objpfx)tst-relr-pie
+ LC_ALL=C $(OBJDUMP) -p $< \
+ | sed -ne '/required from libc.so/,$$ p' \
+ | grep GLIBC_ABI_DT_RELR > $@; \
+ $(evaluate-test)
+
+# The test checks if a DT_RELR shared library without DT_NEEDED works as
+# intended, so it uses an explicit link rule.
+$(objpfx)tst-relr2: $(objpfx)tst-relr-mod2.so
+$(objpfx)tst-relr-mod2.so: $(objpfx)tst-relr-mod2.os
+ $(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
+ $(LDFLAGS-soname-fname) \
+ -shared -o $@.new $(filter-out $(map-file),$^)
+ $(call after-link,$@.new)
+ mv -f $@.new $@
+
+# The test checks if a DT_RELR shared library without DT_VERNEED works as
+# intended, so it uses an explicit link rule.
+$(objpfx)tst-relr3: $(objpfx)tst-relr-mod3a.so
+$(objpfx)tst-relr-mod3b.so: $(objpfx)tst-relr-mod3b.os
+ $(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
+ $(LDFLAGS-soname-fname) \
+ -shared -o $@.new $(filter-out $(map-file),$^)
+ $(call after-link,$@.new)
+ mv -f $@.new $@
+
+$(objpfx)tst-relr-mod3a.so: $(objpfx)tst-relr-mod3a.os \
+ $(objpfx)tst-relr-mod3b.so
+ $(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
+ $(LDFLAGS-soname-fname) \
+ -shared -o $@.new $(filter-out $(map-file),$^)
+ $(call after-link,$@.new)
+ mv -f $@.new $@
+
+# The test checks if a DT_RELR shared library without libc.so on DT_NEEDED
+# works as intended, so it uses an explicit link rule.
+$(objpfx)tst-relr4: $(objpfx)tst-relr-mod4a.so
+$(objpfx)tst-relr-mod4b.so: $(objpfx)tst-relr-mod4b.os
+ $(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
+ $(LDFLAGS-soname-fname) \
+ -Wl,--version-script=tst-relr-mod4b.map \
+ -shared -o $@.new $(filter-out $(map-file),$^)
+ $(call after-link,$@.new)
+ mv -f $@.new $@
+
+$(objpfx)tst-relr-mod4a.so: $(objpfx)tst-relr-mod4a.os \
+ $(objpfx)tst-relr-mod4b.so
+ $(LINK.o) -nostdlib -nostartfiles -Wl,-z,pack-relative-relocs \
+ $(LDFLAGS-soname-fname) \
+ -shared -o $@.new $(filter-out $(map-file),$^)
+ $(call after-link,$@.new)
+ mv -f $@.new $@
diff --git a/elf/Versions b/elf/Versions
index 05eba2ab58..7fa8f67284 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -20,6 +20,11 @@ libc {
__register_frame_info_table_bases; _Unwind_Find_FDE;
}
%endif
+ GLIBC_ABI_DT_RELR {
+ # This symbol is used only for empty version map and will be removed
+ # by scripts/versions.awk.
+ __placeholder_only_for_empty_version_map;
+ }
GLIBC_PRIVATE {
# functions used in other libraries
_dl_addr;
diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
index f576d787e3..e9d7facad9 100644
--- a/elf/dynamic-link.h
+++ b/elf/dynamic-link.h
@@ -128,7 +128,9 @@ elf_machine_lazy_rel (struct link_map *map,
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
ranges[2] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; \
\
- if ((map)->l_info[DT_##RELOC]) \
+ /* With DT_RELR, DT_RELA/DT_REL can have zero value. */ \
+ if ((map)->l_info[DT_##RELOC] != NULL \
+ && (map)->l_info[DT_##RELOC]->d_un.d_ptr != 0) \
{ \
ranges[0].start = D_PTR ((map), l_info[DT_##RELOC]); \
ranges[0].size = (map)->l_info[DT_##RELOC##SZ]->d_un.d_val; \
@@ -142,6 +144,8 @@ elf_machine_lazy_rel (struct link_map *map,
ElfW(Addr) start = D_PTR ((map), l_info[DT_JMPREL]); \
ElfW(Addr) size = (map)->l_info[DT_PLTRELSZ]->d_un.d_val; \
\
+ if (ranges[0].start == 0) \
+ ranges[0].start = start; \
if (ranges[0].start + ranges[0].size == (start + size)) \
ranges[0].size -= size; \
if (ELF_DURING_STARTUP \
@@ -253,12 +257,48 @@ elf_machine_lazy_rel (struct link_map *map,
# define ELF_DYNAMIC_DO_RELA(map, lazy, skip_ifunc, boot_map) /* Nothing to do. */
# endif
+/* Google-local: b/208156916. To not bump DT_NUM, use DT_VERSYM+1 for DT_RELR
+ and DT_VERSYM+2 for DT_RELRSZ. */
+# define ELF_DYNAMIC_DO_RELR(map) \
+ do { \
+ ElfW(Addr) l_addr = (map)->l_addr, *where = 0; \
+ const ElfW(Relr) *r, *end; \
+ if (!(map)->l_info[VERSYMIDX (DT_VERSYM + 1)]) \
+ break; \
+ r = (const ElfW(Relr) *)D_PTR((map), l_info[VERSYMIDX (DT_VERSYM + 1)]); \
+ end = (const ElfW(Relr) *)((const char *)r + \
+ (map)->l_info[VERSYMIDX (DT_VERSYM + 2)]->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 \
+ { \
+ for (long i = 0; (entry >>= 1) != 0; i++) \
+ if ((entry & 1) != 0) \
+ where[i] += l_addr; \
+ where += CHAR_BIT * 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. */
+# ifdef RTLD_BOOTSTRAP
+# define DO_RTLD_BOOTSTRAP 1
+# else
+# define DO_RTLD_BOOTSTRAP 0
+# endif
# define ELF_DYNAMIC_RELOCATE(map, lazy, consider_profile, skip_ifunc, boot_map) \
do { \
int edr_lazy = elf_machine_runtime_setup ((map), (lazy), \
(consider_profile)); \
+ if (((map) != &GL(dl_rtld_map) || DO_RTLD_BOOTSTRAP)) \
+ ELF_DYNAMIC_DO_RELR (map); \
ELF_DYNAMIC_DO_REL ((map), edr_lazy, skip_ifunc, boot_map); \
ELF_DYNAMIC_DO_RELA ((map), edr_lazy, skip_ifunc, boot_map); \
} while (0)
diff --git a/elf/elf.h b/elf/elf.h
index 954f3266f7..35ff17cae2 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -444,8 +444,9 @@ typedef struct
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
-#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
-#define SHT_NUM 19 /* Number of defined types. */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indices */
+#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. */
@@ -663,6 +664,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)
@@ -861,6 +867,11 @@ typedef struct
#define DT_ENCODING 32 /* Start of encoded range */
#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_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 */
+/* Google-local: b/208156916. Don't bump DT_NUM. */
#define DT_NUM 34 /* Number used */
#define DT_LOOS 0x6000000d /* Start of OS-specific */
#define DT_HIOS 0x6ffff000 /* End of OS-specific */
diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
index f9c5b84d6a..02ba5495b7 100644
--- a/elf/get-dynamic-info.h
+++ b/elf/get-dynamic-info.h
@@ -49,7 +49,12 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
while (dyn->d_tag != DT_NULL)
{
- if ((d_tag_utype) dyn->d_tag < DT_NUM)
+ /* Google-local: b/208156916. See ELF_DYNAMIC_DO_RELR. */
+ if (dyn->d_tag == DT_RELR)
+ info[VERSYMIDX (DT_VERSYM + 1)] = dyn;
+ else if (dyn->d_tag == DT_RELRSZ)
+ info[VERSYMIDX (DT_VERSYM + 2)] = dyn;
+ else if ((d_tag_utype) dyn->d_tag < DT_NUM)
info[dyn->d_tag] = dyn;
else if (dyn->d_tag >= DT_LOPROC &&
dyn->d_tag < DT_LOPROC + DT_THISPROCNUM)
@@ -104,16 +109,27 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
ADJUST_DYN_INFO (DT_PLTGOT);
ADJUST_DYN_INFO (DT_STRTAB);
ADJUST_DYN_INFO (DT_SYMTAB);
+ ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM + 1)); /* DT_RELR */
+ ADJUST_DYN_INFO (DT_JMPREL);
+ ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
+ ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
+ + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
+# undef ADJUST_DYN_INFO
+
+ /* DT_RELA/DT_REL are mandatory. But they may have zero value if
+ there is DT_RELR. Don't relocate them if they are zero. */
+# define ADJUST_DYN_INFO(tag) \
+ do \
+ if (info[tag] != NULL && info[tag]->d_un.d_ptr != 0) \
+ info[tag]->d_un.d_ptr += l_addr; \
+ while (0)
+
# if ! ELF_MACHINE_NO_RELA
ADJUST_DYN_INFO (DT_RELA);
# endif
# if ! ELF_MACHINE_NO_REL
ADJUST_DYN_INFO (DT_REL);
# endif
- ADJUST_DYN_INFO (DT_JMPREL);
- ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
- ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM
- + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM);
# undef ADJUST_DYN_INFO
assert (cnt <= DL_RO_DYN_TEMP_CNT);
}
diff --git a/elf/tst-relr-mod2.c b/elf/tst-relr-mod2.c
new file mode 100644
index 0000000000..dc0a63365c
--- /dev/null
+++ b/elf/tst-relr-mod2.c
@@ -0,0 +1,46 @@
+/* Test for DT_RELR in a shared library without DT_NEEDED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+
+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 };
+
+int
+foo (void)
+{
+ int err = 0;
+ for (int i = 0; i < array_length (arr); i++)
+ if (!((arr[i] == 0 && val[i] == 0)
+ || (arr[i] == &o && val[i] == 1)
+ || (arr[i] == &x && val[i] == 2)))
+ err++;
+ return err;
+}
diff --git a/elf/tst-relr-mod3a.c b/elf/tst-relr-mod3a.c
new file mode 100644
index 0000000000..d1621c91b1
--- /dev/null
+++ b/elf/tst-relr-mod3a.c
@@ -0,0 +1,49 @@
+/* Test for DT_RELR in a shared library without DT_VERNEED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+
+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 };
+
+extern void bar (void);
+
+int
+foo (void)
+{
+ int err = 0;
+ for (int i = 0; i < array_length (arr); i++)
+ if (!((arr[i] == 0 && val[i] == 0)
+ || (arr[i] == &o && val[i] == 1)
+ || (arr[i] == &x && val[i] == 2)))
+ err++;
+ bar ();
+ return err;
+}
diff --git a/elf/tst-relr-mod3b.c b/elf/tst-relr-mod3b.c
new file mode 100644
index 0000000000..544cb4bc05
--- /dev/null
+++ b/elf/tst-relr-mod3b.c
@@ -0,0 +1,22 @@
+/* Test for DT_RELR in a shared library without DT_VERNEED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+void
+bar (void)
+{
+}
diff --git a/elf/tst-relr-mod4a.c b/elf/tst-relr-mod4a.c
new file mode 100644
index 0000000000..e1bfebd4ac
--- /dev/null
+++ b/elf/tst-relr-mod4a.c
@@ -0,0 +1,19 @@
+/* Test for DT_RELR in a shared library without libc.so on DT_NEEDED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-relr-mod3a.c"
diff --git a/elf/tst-relr-mod4b.c b/elf/tst-relr-mod4b.c
new file mode 100644
index 0000000000..617dff79c3
--- /dev/null
+++ b/elf/tst-relr-mod4b.c
@@ -0,0 +1,19 @@
+/* Test for DT_RELR in a shared library without libc.so on DT_NEEDED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include "tst-relr-mod3b.c"
diff --git a/elf/tst-relr-mod4b.map b/elf/tst-relr-mod4b.map
new file mode 100644
index 0000000000..7f02247262
--- /dev/null
+++ b/elf/tst-relr-mod4b.map
@@ -0,0 +1,3 @@
+DT_RELR {
+ global: bar;
+};
diff --git a/elf/tst-relr-pie.c b/elf/tst-relr-pie.c
new file mode 100644
index 0000000000..7df0cdbfd6
--- /dev/null
+++ b/elf/tst-relr-pie.c
@@ -0,0 +1 @@
+#include "tst-relr.c"
diff --git a/elf/tst-relr.c b/elf/tst-relr.c
new file mode 100644
index 0000000000..c634ce0d21
--- /dev/null
+++ b/elf/tst-relr.c
@@ -0,0 +1,65 @@
+/* Basic tests for DT_RELR.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <link.h>
+#include <stdbool.h>
+#include <array_length.h>
+#include <support/check.h>
+
+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)
+{
+ ElfW(Dyn) *d = _DYNAMIC;
+ if (d)
+ {
+ bool has_relr = false;
+ for (; d->d_tag != DT_NULL; d++)
+ if (d->d_tag == DT_RELR)
+ has_relr = true;
+
+#if defined __PIE__ || defined __pie__ || defined PIE || defined pie
+ TEST_VERIFY (has_relr);
+#else
+ TEST_VERIFY (!has_relr);
+#endif
+ }
+
+ for (int i = 0; i < array_length (arr); i++)
+ TEST_VERIFY ((arr[i] == 0 && val[i] == 0)
+ || (arr[i] == &o && val[i] == 1)
+ || (arr[i] == &x && val[i] == 2));
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-relr2.c b/elf/tst-relr2.c
new file mode 100644
index 0000000000..10d77f1791
--- /dev/null
+++ b/elf/tst-relr2.c
@@ -0,0 +1,27 @@
+/* Test for DT_RELR in a shared library without DT_NEEDED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+extern int foo (void);
+
+static int
+do_test (void)
+{
+ return foo ();
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-relr3.c b/elf/tst-relr3.c
new file mode 100644
index 0000000000..69106cf7b7
--- /dev/null
+++ b/elf/tst-relr3.c
@@ -0,0 +1,27 @@
+/* Test for DT_RELR in a shared library without libc.so on DT_NEEDED.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+extern int foo (void);
+
+static int
+do_test (void)
+{
+ return foo ();
+}
+
+#include <support/test-driver.c>
diff --git a/elf/tst-relr4.c b/elf/tst-relr4.c
new file mode 100644
index 0000000000..19a75013f8
--- /dev/null
+++ b/elf/tst-relr4.c
@@ -0,0 +1 @@
+#include "tst-relr3.c"
diff --git a/scripts/versions.awk b/scripts/versions.awk
index a3df316c70..f4a63f3edc 100644
--- a/scripts/versions.awk
+++ b/scripts/versions.awk
@@ -132,8 +132,13 @@ END {
closeversion(oldver, veryoldver);
veryoldver = oldver;
}
- printf("%s {\n global:\n", $2) > outfile;
oldver = $2;
+ # Skip the placeholder symbol used only for empty version map.
+ if ($3 == "__placeholder_only_for_empty_version_map;") {
+ printf("%s {\n", $2) > outfile;
+ continue;
+ }
+ printf("%s {\n global:\n", $2) > outfile;
}
printf(" ") > outfile;
for (n = 3; n <= NF; ++n) {