[3/7] Add GLIBC_ABI_DT_RELR for DT_RELR support
Checks
Context |
Check |
Description |
dj/TryBot-apply_patch |
success
|
Patch applied to master at the time it was sent
|
Commit Message
The EI_ABIVERSION field of the ELF header in executables and shared
libraries can be bumped to indicate the minimum ABI requirement on the
dynamic linker. However, EI_ABIVERSION in executables isn't checked by
the Linux kernel ELF loader nor the existing dynamic linker. Executables
will crash mysteriously if the dynamic linker doesn't support the ABI
features required by the EI_ABIVERSION field. The dynamic linker should
be changed to check EI_ABIVERSION in executables.
Add a glibc version, GLIBC_ABI_DT_RELR, to indicate DT_RELR support so
that the existing dynamic linkers will issue an error on executables
with GLIBC_ABI_DT_RELR depdendency.
Support __placeholder_only_for_empty_version_map as the placeholder symbol
used only for empty version map to generate GLIBC_ABI_DT_RELR without any
symbols.
---
elf/Makefile | 18 ++++++++++++++++--
elf/Versions | 7 +++++++
elf/libc-abi-version.exp | 1 +
scripts/abilist.awk | 2 ++
scripts/versions.awk | 7 ++++++-
5 files changed, 32 insertions(+), 3 deletions(-)
create mode 100644 elf/libc-abi-version.exp
Comments
On Thu, 3 Feb 2022, H.J. Lu via Libc-alpha wrote:
> +%if HAVE_DT_RELR
> + 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;
> + }
My understanding is that HAVE_DT_RELR describes a property of the linker
used to build glibc, not a property of what features glibc itself
supports.
The symbol versions provided by glibc, and whether glibc supports binaries
using RELR relocations, should be independent of whether the linker
version used to build glibc supports such relocations. A given glibc
version should either always support RELR relocations (for a given glibc
ABI) or never support them (for that ABI), independent of linker features,
and likewise the symbol versions provided by glibc should be independent
of linker features.
On Fri, Feb 4, 2022 at 11:53 AM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Thu, 3 Feb 2022, H.J. Lu via Libc-alpha wrote:
>
> > +%if HAVE_DT_RELR
> > + 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;
> > + }
>
> My understanding is that HAVE_DT_RELR describes a property of the linker
> used to build glibc, not a property of what features glibc itself
> supports.
>
> The symbol versions provided by glibc, and whether glibc supports binaries
> using RELR relocations, should be independent of whether the linker
> version used to build glibc supports such relocations. A given glibc
> version should either always support RELR relocations (for a given glibc
> ABI) or never support them (for that ABI), independent of linker features,
> and likewise the symbol versions provided by glibc should be independent
> of linker features.
>
In my cover letter, I said
Binutils 2.38 supports DT_RELR on x86 with the -z report-relative-reloc
option. When DT_RELR is enabled, ld adds a GLIBC_ABI_DT_RELR symbol
version dependency on libc.so to outputs. The DT_RELR support is enabled
in ld.so only if the linker supports -z report-relative-reloc option.
and the first patch has
# define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
do { \
int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
(consider_profile)); \
ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc);
\
+ if (HAVE_DT_RELR && ((map) != &GL(dl_rtld_map) || DO_RTLD_BOOTSTRAP)) \
+ ELF_DYNAMIC_DO_RELR (map); \
} while (0)
If HAVE_DT_RELR is 0, DT_RELR is disabled.
On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
> In my cover letter, I said
>
> Binutils 2.38 supports DT_RELR on x86 with the -z report-relative-reloc
> option. When DT_RELR is enabled, ld adds a GLIBC_ABI_DT_RELR symbol
> version dependency on libc.so to outputs. The DT_RELR support is enabled
> in ld.so only if the linker supports -z report-relative-reloc option.
>
> and the first patch has
>
> # define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
> do { \
> int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
> (consider_profile)); \
> ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
> ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc);
> \
> + if (HAVE_DT_RELR && ((map) != &GL(dl_rtld_map) || DO_RTLD_BOOTSTRAP)) \
> + ELF_DYNAMIC_DO_RELR (map); \
> } while (0)
>
> If HAVE_DT_RELR is 0, DT_RELR is disabled.
It's important that glibc 2.36 supports the same executables and shared
libraries on a given platform, independent of the binutils version used to
build glibc. If any build of glibc 2.36 for some platform supports RELR
relocations, all builds of it for that platform must support such
relocations.
That means that configure tests for linker support can *only* affect
whether glibc is built to *use* such relocations itself - not whether it
supports loading executables and shared libraries that use them.
(You could also increase the minimum linker version for building glibc for
a given platform, but the RELR support is too recent for it to be a good
idea to make the minimum version new enough to include RELR support.)
On Fri, Feb 4, 2022 at 12:11 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
>
> > In my cover letter, I said
> >
> > Binutils 2.38 supports DT_RELR on x86 with the -z report-relative-reloc
> > option. When DT_RELR is enabled, ld adds a GLIBC_ABI_DT_RELR symbol
> > version dependency on libc.so to outputs. The DT_RELR support is enabled
> > in ld.so only if the linker supports -z report-relative-reloc option.
> >
> > and the first patch has
> >
> > # define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
> > do { \
> > int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy), \
> > (consider_profile)); \
> > ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc); \
> > ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc);
> > \
> > + if (HAVE_DT_RELR && ((map) != &GL(dl_rtld_map) || DO_RTLD_BOOTSTRAP)) \
> > + ELF_DYNAMIC_DO_RELR (map); \
> > } while (0)
> >
> > If HAVE_DT_RELR is 0, DT_RELR is disabled.
>
> It's important that glibc 2.36 supports the same executables and shared
> libraries on a given platform, independent of the binutils version used to
> build glibc. If any build of glibc 2.36 for some platform supports RELR
> relocations, all builds of it for that platform must support such
> relocations.
>
> That means that configure tests for linker support can *only* affect
> whether glibc is built to *use* such relocations itself - not whether it
> supports loading executables and shared libraries that use them.
>
> (You could also increase the minimum linker version for building glibc for
> a given platform, but the RELR support is too recent for it to be a good
> idea to make the minimum version new enough to include RELR support.)
Good point. How about "enable DT_RELR only if SUPPORT_DT_RELR is
defined? Currently, only x86 defines SUPPORT_DT_RELR.
On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
> Good point. How about "enable DT_RELR only if SUPPORT_DT_RELR is
> defined? Currently, only x86 defines SUPPORT_DT_RELR.
My preference would be:
1. Support user executables and shared libraries with RELR relocations
across all platforms, unconditionally.
2. Build glibc to use RELR relocations in its own executables and shared
libraries based on an architecture-independent configure test for whether
linker support is present.
And avoid any architecture-specific conditional relating to RELR support
in glibc completely.
*If* it turns out to be hard to have a fully reliable
architecture-independent configure test for linker support, and the
architecture-independent test reports linker support to be present (in an
actual binutils release, not just the development mainline) for an
architecture where that support is in fact buggy and incomplete, then we
might consider adding an architecture-specific test on that architecture
to disable building glibc to use RELR relocations with the buggy linker
version. That is, architecture-specific tests would only be to disable
building glibc to use RELR relocations, not to enable it, and only when
the bugs in linker support on that architecture can't readily be detected
by an architecture-independent test. The default for all existing and
future architectures would be to follow the results of the
architecture-independent configure test.
On Fri, Feb 4, 2022 at 1:01 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
>
> > Good point. How about "enable DT_RELR only if SUPPORT_DT_RELR is
> > defined? Currently, only x86 defines SUPPORT_DT_RELR.
>
> My preference would be:
>
> 1. Support user executables and shared libraries with RELR relocations
> across all platforms, unconditionally.
RELR is kind of like static PIE. Not all architectures support it.
RELR should be enabled only if there is a linker which supports
-z pack-relative-relocs. That is the main reason why RELR is
enabled in glibc 2.35.
> 2. Build glibc to use RELR relocations in its own executables and shared
> libraries based on an architecture-independent configure test for whether
> linker support is present.
This is implemented in
commit 486531c29b0fa48287b29ea20e805bee1ec19a67
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Sat Jan 22 05:44:45 2022 -0800
Add --disable-default-dt-relr
which is similar to --disable-default-pie.
> And avoid any architecture-specific conditional relating to RELR support
> in glibc completely.
>
> *If* it turns out to be hard to have a fully reliable
> architecture-independent configure test for linker support, and the
> architecture-independent test reports linker support to be present (in an
> actual binutils release, not just the development mainline) for an
> architecture where that support is in fact buggy and incomplete, then we
> might consider adding an architecture-specific test on that architecture
> to disable building glibc to use RELR relocations with the buggy linker
> version. That is, architecture-specific tests would only be to disable
> building glibc to use RELR relocations, not to enable it, and only when
> the bugs in linker support on that architecture can't readily be detected
> by an architecture-independent test. The default for all existing and
> future architectures would be to follow the results of the
> architecture-independent configure test.
On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
> On Fri, Feb 4, 2022 at 1:01 PM Joseph Myers <joseph@codesourcery.com> wrote:
> >
> > On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
> >
> > > Good point. How about "enable DT_RELR only if SUPPORT_DT_RELR is
> > > defined? Currently, only x86 defines SUPPORT_DT_RELR.
> >
> > My preference would be:
> >
> > 1. Support user executables and shared libraries with RELR relocations
> > across all platforms, unconditionally.
>
> RELR is kind of like static PIE. Not all architectures support it.
My understanding is that analogy only applies to the static linker, not to
glibc itself - that the static linker needs architecture-specific code,
but glibc doesn't (as evidenced by the lack of any architecture-specific
non-configure changes in this patch series).
> RELR should be enabled only if there is a linker which supports
> -z pack-relative-relocs.
(a) That should only apply to "enabled" in the sense of "glibc itself uses
RELR relocations", not "glibc supports loading executables and shared
libraries with such relocations".
(b) The configure test for that should be architecture-independent, with
no architecture-specific configure changes needed at all.
On Fri, Feb 4, 2022 at 3:58 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
>
> > On Fri, Feb 4, 2022 at 1:01 PM Joseph Myers <joseph@codesourcery.com> wrote:
> > >
> > > On Fri, 4 Feb 2022, H.J. Lu via Libc-alpha wrote:
> > >
> > > > Good point. How about "enable DT_RELR only if SUPPORT_DT_RELR is
> > > > defined? Currently, only x86 defines SUPPORT_DT_RELR.
> > >
> > > My preference would be:
> > >
> > > 1. Support user executables and shared libraries with RELR relocations
> > > across all platforms, unconditionally.
> >
> > RELR is kind of like static PIE. Not all architectures support it.
>
> My understanding is that analogy only applies to the static linker, not to
> glibc itself - that the static linker needs architecture-specific code,
> but glibc doesn't (as evidenced by the lack of any architecture-specific
> non-configure changes in this patch series).
>
> > RELR should be enabled only if there is a linker which supports
> > -z pack-relative-relocs.
>
> (a) That should only apply to "enabled" in the sense of "glibc itself uses
> RELR relocations", not "glibc supports loading executables and shared
> libraries with such relocations".
>
> (b) The configure test for that should be architecture-independent, with
> no architecture-specific configure changes needed at all.
>
Fixed in the v2 patch.
@@ -48,6 +48,10 @@ routines = \
rtld_static_init \
# routines
+ifeq ($(have-dt-relr),yes)
+check-abi-version-libc = $(objpfx)check-abi-version-libc.out
+endif
+
# The core dynamic linking functions are in libc for the static and
# profiled libraries.
dl-routines = \
@@ -1106,8 +1110,8 @@ $(eval $(call include_dsosort_tests,dso-sort-tests-1.def))
$(eval $(call include_dsosort_tests,dso-sort-tests-2.def))
endif
-check-abi: $(objpfx)check-abi-ld.out
-tests-special += $(objpfx)check-abi-ld.out
+check-abi: $(objpfx)check-abi-ld.out $(check-abi-version-libc)
+tests-special += $(objpfx)check-abi-ld.out $(check-abi-version-libc)
update-abi: update-abi-ld
update-all-abi: update-all-abi-ld
@@ -2747,3 +2751,13 @@ $(objpfx)check-tst-relr-pie.out: $(objpfx)tst-relr-pie
| sed -ne '/required from libc.so/,$$ p' \
| grep GLIBC_ABI_DT_RELR > $@; \
$(evaluate-test)
+
+$(objpfx)check-abi-version-libc.out: libc-abi-version.exp \
+ $(objpfx)libc.symlist-abi-version
+ cmp $^ > $@; \
+ $(evaluate-test)
+
+$(objpfx)libc.symlist-abi-version: $(common-objpfx)libc.so
+ LC_ALL=C $(NM) -D $< | grep " GLIBC_ABI_" \
+ | sed "s/^0\+/00000000/" > $@T
+ mv -f $@T $@
@@ -23,6 +23,13 @@ libc {
GLIBC_2.35 {
_dl_find_object;
}
+%if HAVE_DT_RELR
+ 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;
+ }
+%endif
GLIBC_PRIVATE {
# functions used in other libraries
__libc_early_init;
new file mode 100644
@@ -0,0 +1 @@
+00000000 A GLIBC_ABI_DT_RELR
@@ -55,6 +55,8 @@ $2 == "g" || $2 == "w" && (NF == 7 || NF == 8) {
# caused STV_HIDDEN symbols to appear in .dynsym, though that is useless.
if (NF > 7 && $7 == ".hidden") next;
+ if (version ~ /^GLIBC_ABI_/ && !include_abi_version) next;
+
if (version == "GLIBC_PRIVATE" && !include_private) next;
desc = "";
@@ -185,8 +185,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) {