diff mbox series

[v7] elf: Handle static PIE with non-zero load address [BZ #31799]

Message ID 20241028220114.3943735-1-hjl.tools@gmail.com
State New
Headers show
Series [v7] elf: Handle static PIE with non-zero load address [BZ #31799] | expand

Commit Message

H.J. Lu Oct. 28, 2024, 10:01 p.m. UTC
For a static PIE with non-zero load address, its PT_DYNAMIC segment
entries contain the relocated values for the load address in static PIE.
Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr of
the PT_LOAD segment with offset == 0 as the load address in static PIE
and adjust the entries of PT_DYNAMIC segment in static PIE by properly
setting the l_addr field for static PIE.  This fixes BZ #31799.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 configure                    | 74 ++++++++++++++++++++++++++++++++++++
 configure.ac                 | 36 ++++++++++++++++++
 elf/Makefile                 | 20 ++++++++++
 elf/dl-reloc-static-pie.c    | 30 +++++++++++----
 elf/tst-pie-address-static.c | 19 +++++++++
 elf/tst-pie-address.c        | 28 ++++++++++++++
 6 files changed, 200 insertions(+), 7 deletions(-)
 create mode 100644 elf/tst-pie-address-static.c
 create mode 100644 elf/tst-pie-address.c

Comments

Noah Goldstein Oct. 29, 2024, 5:33 a.m. UTC | #1
On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> For a static PIE with non-zero load address, its PT_DYNAMIC segment
> entries contain the relocated values for the load address in static PIE.
> Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr of
> the PT_LOAD segment with offset == 0 as the load address in static PIE
> and adjust the entries of PT_DYNAMIC segment in static PIE by properly
> setting the l_addr field for static PIE.  This fixes BZ #31799.
>
> Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> ---
>  configure                    | 74 ++++++++++++++++++++++++++++++++++++
>  configure.ac                 | 36 ++++++++++++++++++
>  elf/Makefile                 | 20 ++++++++++
>  elf/dl-reloc-static-pie.c    | 30 +++++++++++----
>  elf/tst-pie-address-static.c | 19 +++++++++
>  elf/tst-pie-address.c        | 28 ++++++++++++++
>  6 files changed, 200 insertions(+), 7 deletions(-)
>  create mode 100644 elf/tst-pie-address-static.c
>  create mode 100644 elf/tst-pie-address.c
>
> diff --git a/configure b/configure
> index 9c0c0dce03..9bcf62dca5 100755
> --- a/configure
> +++ b/configure
> @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default" >&6; }
>  config_vars="$config_vars
>  cc-pie-default = $libc_cv_cc_pie_default"
>
> +# Get Position Dependent Executable (PDE) load address to be used to
> +# load static Position Independent Executable (PIE) at a known working
> +# non-zero load address.  This is only used by glibc tests to verify
> +# that PIE and static PIE with non-zero load address work correctly.
> +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load address" >&5
> +printf %s "checking PDE load address... " >&6; }
> +if test ${libc_cv_pde_load_address+y}
> +then :
> +  printf %s "(cached) " >&6
> +else case e in #(
> +  e) cat > conftest.S <<EOF
> +.globl _start
> +_start:
> +.globl __start
> +__start:
> +EOF
> +if test $libc_cv_cc_pie_default = yes; then
> +  pde_ld_flags="-no-pie"
> +fi
> +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> +           -nostartfiles -nostdlib $no_ssp \
> +           -o conftest conftest.S 1>&5 2>&5; then
> +  # Get the load address of the first PT_LOAD segment.
> +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> +else
> +  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
> +fi
> +rm -f conftest* ;;
> +esac
> +fi
> +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_pde_load_address" >&5
> +printf "%s\n" "$libc_cv_pde_load_address" >&6; }
> +config_vars="$config_vars
> +pde-load-address = $libc_cv_pde_load_address"
> +
> +# Get the linker command-line option to load executable at a non-zero
> +# load address.  This is only used by glibc tests to verify that PIE and
> +# static PIE with non-zero load address work correctly.
> +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
> +printf %s "checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
> +libc_linker_feature=no
> +cat > conftest.c <<EOF
> +int _start (void) { return 42; }
> +EOF
> +if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
> +                 -Wl,-Ttext-segment=$libc_cv_pde_load_address -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=$?
> +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> +  test $ac_status = 0; }; }
> +then
> +  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
> +      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
> +      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address ignored" > /dev/null 2>&1; then
> +    true
> +  else
> +    libc_linker_feature=yes
> +  fi
> +fi
> +rm -f conftest*
> +if test $libc_linker_feature = yes; then
> +  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
> +else
> +  libc_cv_load_address_ldflag=
> +fi
> +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
> +printf "%s\n" "$libc_linker_feature" >&6; }
> +config_vars="$config_vars
> +load-address-ldflag = $libc_cv_load_address_ldflag"
> +
>  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
>  printf %s "checking if we can build programs as PIE... " >&6; }
>  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> diff --git a/configure.ac b/configure.ac
> index d5a00461ff..895bd5267d 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1763,6 +1763,42 @@ fi
>  rm -f conftest.*])
>  LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
>
> +# Get Position Dependent Executable (PDE) load address to be used to
> +# load static Position Independent Executable (PIE) at a known working
> +# non-zero load address.  This is only used by glibc tests to verify
> +# that PIE and static PIE with non-zero load address work correctly.
> +AC_CACHE_CHECK([PDE load address],
> +              libc_cv_pde_load_address, [dnl
> +cat > conftest.S <<EOF
> +.globl _start
> +_start:
> +.globl __start
> +__start:
> +EOF
> +if test $libc_cv_cc_pie_default = yes; then
> +  pde_ld_flags="-no-pie"
> +fi
> +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> +           -nostartfiles -nostdlib $no_ssp \
> +           -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
> +  # Get the load address of the first PT_LOAD segment.
> +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> +else
> +  AC_MSG_ERROR([${CC-cc} can not create PDE])
> +fi
> +rm -f conftest*])
> +LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
> +
> +# Get the linker command-line option to load executable at a non-zero
> +# load address.  This is only used by glibc tests to verify that PIE and
> +# static PIE with non-zero load address work correctly.
> +LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
> +                   [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
> +                   [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
> +                   [libc_cv_load_address_ldflag=])
> +LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
> +
>  AC_MSG_CHECKING(if we can build programs as PIE)
>  AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
>  # error PIE is not supported
> diff --git a/elf/Makefile b/elf/Makefile
> index 9cfe738919..4eaca7af67 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -1091,6 +1091,25 @@ tests-pie += \
>    tst-pie1 \
>    tst-pie2 \
>    # tests-pie
> +ifneq (,$(load-address-ldflag))
> +tests += \
> +  tst-pie-address \
> +  # tests
> +tests-pie += \
> +  tst-pie-address \
> +  # tests-pie
> +LDFLAGS-tst-pie-address += $(load-address-ldflag)=$(pde-load-address)
> +ifeq (yes,$(enable-static-pie))
> +tests += \
> +  tst-pie-address-static \
> +  # tests
> +tests-static += \
> +  tst-pie-address-static \
> +  # tests-static
> +LDFLAGS-tst-pie-address-static += \
> +  $(load-address-ldflag)=$(pde-load-address)
> +endif
> +endif
>  ifeq (yes,$(have-protected-data))
>  tests += vismain
>  tests-pie += vismain
> @@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
>
>  CFLAGS-tst-pie1.c += $(pie-ccflag)
>  CFLAGS-tst-pie2.c += $(pie-ccflag)
> +CFLAGS-tst-pie-address.c += $(pie-ccflag)
>
>  $(objpfx)tst-piemod1.so: $(libsupport)
>  $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
> diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
> index 10c23d0bf0..bfee89dfc3 100644
> --- a/elf/dl-reloc-static-pie.c
> +++ b/elf/dl-reloc-static-pie.c
> @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
>  {
>    struct link_map *main_map = _dl_get_dl_main_map ();
>
> -  /* Figure out the run-time load address of static PIE.  */
> -  main_map->l_addr = elf_machine_load_address ();
> -
> -  /* Read our own dynamic section and fill in the info array.  */
> -  main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
> -
> +  /* NB: elf_machine_load_address () returns the run-time load address
> +     of static PIE.  The l_addr field contains the difference between the
> +     link-time load address in the ELF file and the run-time load address
> +     in memory.  We must subtract the link-time load address of static PIE,
> +     which can be non-zero, when computing the l_addr field.  Since static
> +     PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD
> +     segment with offset == 0 as the load address of static PIE.  */
> +  ElfW(Addr) file_p_vaddr = 0;
>    const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
>    size_t phnum = GL(dl_phnum);
>    for (ph = phdr; ph < &phdr[phnum]; ++ph)
> -    if (ph->p_type == PT_DYNAMIC)
> +    switch (ph->p_type)
>        {
> +      case PT_LOAD:
> +       if (ph->p_offset == 0)
> +         file_p_vaddr = ph->p_vaddr;
> +       break;
> +      case PT_DYNAMIC:
>         main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
>         break;
> +      default:
> +       break;
>        }
>
> +  /* Figure out the run-time load address of static PIE.  */
> +  ElfW(Addr) l_addr = elf_machine_load_address ();
> +  main_map->l_addr = l_addr - file_p_vaddr;
> +
> +  /* Read our own dynamic section and fill in the info array.  */
> +  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
> +
>    elf_get_dynamic_info (main_map, false, true);
>
>  # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
> diff --git a/elf/tst-pie-address-static.c b/elf/tst-pie-address-static.c
> new file mode 100644
> index 0000000000..be2831e9d6
> --- /dev/null
> +++ b/elf/tst-pie-address-static.c
> @@ -0,0 +1,19 @@
> +/* Test static PIE with non-zero load address.
> +   Copyright (C) 2024 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-pie-address.c"
> diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
> new file mode 100644
> index 0000000000..aa1ca0a9fd
> --- /dev/null
> +++ b/elf/tst-pie-address.c
> @@ -0,0 +1,28 @@
> +/* Test PIE with non-zero load address.
> +   Copyright (C) 2024 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 <stdio.h>
> +
> +static int
> +do_test (void)
> +{
> +  printf ("Hello\n");
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> --
> 2.47.0
>

LGTM.

Think Carlos was also going to take a look at this (from monday review
minutes), so please wait for Carlos to take a look too before pushing.
H.J. Lu Oct. 30, 2024, 11:55 p.m. UTC | #2
On Tue, Oct 29, 2024 at 1:33 PM Noah Goldstein <goldstein.w.n@gmail.com> wrote:
>
> On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > For a static PIE with non-zero load address, its PT_DYNAMIC segment
> > entries contain the relocated values for the load address in static PIE.
> > Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr of
> > the PT_LOAD segment with offset == 0 as the load address in static PIE
> > and adjust the entries of PT_DYNAMIC segment in static PIE by properly
> > setting the l_addr field for static PIE.  This fixes BZ #31799.
> >
> > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > ---
> >  configure                    | 74 ++++++++++++++++++++++++++++++++++++
> >  configure.ac                 | 36 ++++++++++++++++++
> >  elf/Makefile                 | 20 ++++++++++
> >  elf/dl-reloc-static-pie.c    | 30 +++++++++++----
> >  elf/tst-pie-address-static.c | 19 +++++++++
> >  elf/tst-pie-address.c        | 28 ++++++++++++++
> >  6 files changed, 200 insertions(+), 7 deletions(-)
> >  create mode 100644 elf/tst-pie-address-static.c
> >  create mode 100644 elf/tst-pie-address.c
> >
> > diff --git a/configure b/configure
> > index 9c0c0dce03..9bcf62dca5 100755
> > --- a/configure
> > +++ b/configure
> > @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default" >&6; }
> >  config_vars="$config_vars
> >  cc-pie-default = $libc_cv_cc_pie_default"
> >
> > +# Get Position Dependent Executable (PDE) load address to be used to
> > +# load static Position Independent Executable (PIE) at a known working
> > +# non-zero load address.  This is only used by glibc tests to verify
> > +# that PIE and static PIE with non-zero load address work correctly.
> > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load address" >&5
> > +printf %s "checking PDE load address... " >&6; }
> > +if test ${libc_cv_pde_load_address+y}
> > +then :
> > +  printf %s "(cached) " >&6
> > +else case e in #(
> > +  e) cat > conftest.S <<EOF
> > +.globl _start
> > +_start:
> > +.globl __start
> > +__start:
> > +EOF
> > +if test $libc_cv_cc_pie_default = yes; then
> > +  pde_ld_flags="-no-pie"
> > +fi
> > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > +           -nostartfiles -nostdlib $no_ssp \
> > +           -o conftest conftest.S 1>&5 2>&5; then
> > +  # Get the load address of the first PT_LOAD segment.
> > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > +else
> > +  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
> > +fi
> > +rm -f conftest* ;;
> > +esac
> > +fi
> > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_pde_load_address" >&5
> > +printf "%s\n" "$libc_cv_pde_load_address" >&6; }
> > +config_vars="$config_vars
> > +pde-load-address = $libc_cv_pde_load_address"
> > +
> > +# Get the linker command-line option to load executable at a non-zero
> > +# load address.  This is only used by glibc tests to verify that PIE and
> > +# static PIE with non-zero load address work correctly.
> > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
> > +printf %s "checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
> > +libc_linker_feature=no
> > +cat > conftest.c <<EOF
> > +int _start (void) { return 42; }
> > +EOF
> > +if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
> > +                 -Wl,-Ttext-segment=$libc_cv_pde_load_address -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=$?
> > +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> > +  test $ac_status = 0; }; }
> > +then
> > +  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
> > +      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
> > +      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address ignored" > /dev/null 2>&1; then
> > +    true
> > +  else
> > +    libc_linker_feature=yes
> > +  fi
> > +fi
> > +rm -f conftest*
> > +if test $libc_linker_feature = yes; then
> > +  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
> > +else
> > +  libc_cv_load_address_ldflag=
> > +fi
> > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
> > +printf "%s\n" "$libc_linker_feature" >&6; }
> > +config_vars="$config_vars
> > +load-address-ldflag = $libc_cv_load_address_ldflag"
> > +
> >  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
> >  printf %s "checking if we can build programs as PIE... " >&6; }
> >  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> > diff --git a/configure.ac b/configure.ac
> > index d5a00461ff..895bd5267d 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -1763,6 +1763,42 @@ fi
> >  rm -f conftest.*])
> >  LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
> >
> > +# Get Position Dependent Executable (PDE) load address to be used to
> > +# load static Position Independent Executable (PIE) at a known working
> > +# non-zero load address.  This is only used by glibc tests to verify
> > +# that PIE and static PIE with non-zero load address work correctly.
> > +AC_CACHE_CHECK([PDE load address],
> > +              libc_cv_pde_load_address, [dnl
> > +cat > conftest.S <<EOF
> > +.globl _start
> > +_start:
> > +.globl __start
> > +__start:
> > +EOF
> > +if test $libc_cv_cc_pie_default = yes; then
> > +  pde_ld_flags="-no-pie"
> > +fi
> > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > +           -nostartfiles -nostdlib $no_ssp \
> > +           -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
> > +  # Get the load address of the first PT_LOAD segment.
> > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > +else
> > +  AC_MSG_ERROR([${CC-cc} can not create PDE])
> > +fi
> > +rm -f conftest*])
> > +LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
> > +
> > +# Get the linker command-line option to load executable at a non-zero
> > +# load address.  This is only used by glibc tests to verify that PIE and
> > +# static PIE with non-zero load address work correctly.
> > +LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
> > +                   [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
> > +                   [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
> > +                   [libc_cv_load_address_ldflag=])
> > +LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
> > +
> >  AC_MSG_CHECKING(if we can build programs as PIE)
> >  AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
> >  # error PIE is not supported
> > diff --git a/elf/Makefile b/elf/Makefile
> > index 9cfe738919..4eaca7af67 100644
> > --- a/elf/Makefile
> > +++ b/elf/Makefile
> > @@ -1091,6 +1091,25 @@ tests-pie += \
> >    tst-pie1 \
> >    tst-pie2 \
> >    # tests-pie
> > +ifneq (,$(load-address-ldflag))
> > +tests += \
> > +  tst-pie-address \
> > +  # tests
> > +tests-pie += \
> > +  tst-pie-address \
> > +  # tests-pie
> > +LDFLAGS-tst-pie-address += $(load-address-ldflag)=$(pde-load-address)
> > +ifeq (yes,$(enable-static-pie))
> > +tests += \
> > +  tst-pie-address-static \
> > +  # tests
> > +tests-static += \
> > +  tst-pie-address-static \
> > +  # tests-static
> > +LDFLAGS-tst-pie-address-static += \
> > +  $(load-address-ldflag)=$(pde-load-address)
> > +endif
> > +endif
> >  ifeq (yes,$(have-protected-data))
> >  tests += vismain
> >  tests-pie += vismain
> > @@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
> >
> >  CFLAGS-tst-pie1.c += $(pie-ccflag)
> >  CFLAGS-tst-pie2.c += $(pie-ccflag)
> > +CFLAGS-tst-pie-address.c += $(pie-ccflag)
> >
> >  $(objpfx)tst-piemod1.so: $(libsupport)
> >  $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
> > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
> > index 10c23d0bf0..bfee89dfc3 100644
> > --- a/elf/dl-reloc-static-pie.c
> > +++ b/elf/dl-reloc-static-pie.c
> > @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
> >  {
> >    struct link_map *main_map = _dl_get_dl_main_map ();
> >
> > -  /* Figure out the run-time load address of static PIE.  */
> > -  main_map->l_addr = elf_machine_load_address ();
> > -
> > -  /* Read our own dynamic section and fill in the info array.  */
> > -  main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
> > -
> > +  /* NB: elf_machine_load_address () returns the run-time load address
> > +     of static PIE.  The l_addr field contains the difference between the
> > +     link-time load address in the ELF file and the run-time load address
> > +     in memory.  We must subtract the link-time load address of static PIE,
> > +     which can be non-zero, when computing the l_addr field.  Since static
> > +     PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD
> > +     segment with offset == 0 as the load address of static PIE.  */
> > +  ElfW(Addr) file_p_vaddr = 0;
> >    const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
> >    size_t phnum = GL(dl_phnum);
> >    for (ph = phdr; ph < &phdr[phnum]; ++ph)
> > -    if (ph->p_type == PT_DYNAMIC)
> > +    switch (ph->p_type)
> >        {
> > +      case PT_LOAD:
> > +       if (ph->p_offset == 0)
> > +         file_p_vaddr = ph->p_vaddr;
> > +       break;
> > +      case PT_DYNAMIC:
> >         main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
> >         break;
> > +      default:
> > +       break;
> >        }
> >
> > +  /* Figure out the run-time load address of static PIE.  */
> > +  ElfW(Addr) l_addr = elf_machine_load_address ();
> > +  main_map->l_addr = l_addr - file_p_vaddr;
> > +
> > +  /* Read our own dynamic section and fill in the info array.  */
> > +  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
> > +
> >    elf_get_dynamic_info (main_map, false, true);
> >
> >  # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
> > diff --git a/elf/tst-pie-address-static.c b/elf/tst-pie-address-static.c
> > new file mode 100644
> > index 0000000000..be2831e9d6
> > --- /dev/null
> > +++ b/elf/tst-pie-address-static.c
> > @@ -0,0 +1,19 @@
> > +/* Test static PIE with non-zero load address.
> > +   Copyright (C) 2024 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-pie-address.c"
> > diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
> > new file mode 100644
> > index 0000000000..aa1ca0a9fd
> > --- /dev/null
> > +++ b/elf/tst-pie-address.c
> > @@ -0,0 +1,28 @@
> > +/* Test PIE with non-zero load address.
> > +   Copyright (C) 2024 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 <stdio.h>
> > +
> > +static int
> > +do_test (void)
> > +{
> > +  printf ("Hello\n");
> > +  return 0;
> > +}
> > +
> > +#include <support/test-driver.c>
> > --
> > 2.47.0
> >
>
> LGTM.
>
> Think Carlos was also going to take a look at this (from monday review
> minutes), so please wait for Carlos to take a look too before pushing.

Hi Carlos,

Do you have comments?

Thanks.
H.J. Lu Nov. 3, 2024, 11:18 p.m. UTC | #3
On Thu, Oct 31, 2024 at 7:55 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Tue, Oct 29, 2024 at 1:33 PM Noah Goldstein <goldstein.w.n@gmail.com> wrote:
> >
> > On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > For a static PIE with non-zero load address, its PT_DYNAMIC segment
> > > entries contain the relocated values for the load address in static PIE.
> > > Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr of
> > > the PT_LOAD segment with offset == 0 as the load address in static PIE
> > > and adjust the entries of PT_DYNAMIC segment in static PIE by properly
> > > setting the l_addr field for static PIE.  This fixes BZ #31799.
> > >
> > > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > > ---
> > >  configure                    | 74 ++++++++++++++++++++++++++++++++++++
> > >  configure.ac                 | 36 ++++++++++++++++++
> > >  elf/Makefile                 | 20 ++++++++++
> > >  elf/dl-reloc-static-pie.c    | 30 +++++++++++----
> > >  elf/tst-pie-address-static.c | 19 +++++++++
> > >  elf/tst-pie-address.c        | 28 ++++++++++++++
> > >  6 files changed, 200 insertions(+), 7 deletions(-)
> > >  create mode 100644 elf/tst-pie-address-static.c
> > >  create mode 100644 elf/tst-pie-address.c
> > >
> > > diff --git a/configure b/configure
> > > index 9c0c0dce03..9bcf62dca5 100755
> > > --- a/configure
> > > +++ b/configure
> > > @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default" >&6; }
> > >  config_vars="$config_vars
> > >  cc-pie-default = $libc_cv_cc_pie_default"
> > >
> > > +# Get Position Dependent Executable (PDE) load address to be used to
> > > +# load static Position Independent Executable (PIE) at a known working
> > > +# non-zero load address.  This is only used by glibc tests to verify
> > > +# that PIE and static PIE with non-zero load address work correctly.
> > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load address" >&5
> > > +printf %s "checking PDE load address... " >&6; }
> > > +if test ${libc_cv_pde_load_address+y}
> > > +then :
> > > +  printf %s "(cached) " >&6
> > > +else case e in #(
> > > +  e) cat > conftest.S <<EOF
> > > +.globl _start
> > > +_start:
> > > +.globl __start
> > > +__start:
> > > +EOF
> > > +if test $libc_cv_cc_pie_default = yes; then
> > > +  pde_ld_flags="-no-pie"
> > > +fi
> > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > > +           -nostartfiles -nostdlib $no_ssp \
> > > +           -o conftest conftest.S 1>&5 2>&5; then
> > > +  # Get the load address of the first PT_LOAD segment.
> > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > > +else
> > > +  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
> > > +fi
> > > +rm -f conftest* ;;
> > > +esac
> > > +fi
> > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_pde_load_address" >&5
> > > +printf "%s\n" "$libc_cv_pde_load_address" >&6; }
> > > +config_vars="$config_vars
> > > +pde-load-address = $libc_cv_pde_load_address"
> > > +
> > > +# Get the linker command-line option to load executable at a non-zero
> > > +# load address.  This is only used by glibc tests to verify that PIE and
> > > +# static PIE with non-zero load address work correctly.
> > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
> > > +printf %s "checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
> > > +libc_linker_feature=no
> > > +cat > conftest.c <<EOF
> > > +int _start (void) { return 42; }
> > > +EOF
> > > +if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
> > > +                 -Wl,-Ttext-segment=$libc_cv_pde_load_address -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=$?
> > > +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> > > +  test $ac_status = 0; }; }
> > > +then
> > > +  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
> > > +      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
> > > +      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address ignored" > /dev/null 2>&1; then
> > > +    true
> > > +  else
> > > +    libc_linker_feature=yes
> > > +  fi
> > > +fi
> > > +rm -f conftest*
> > > +if test $libc_linker_feature = yes; then
> > > +  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
> > > +else
> > > +  libc_cv_load_address_ldflag=
> > > +fi
> > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
> > > +printf "%s\n" "$libc_linker_feature" >&6; }
> > > +config_vars="$config_vars
> > > +load-address-ldflag = $libc_cv_load_address_ldflag"
> > > +
> > >  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
> > >  printf %s "checking if we can build programs as PIE... " >&6; }
> > >  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> > > diff --git a/configure.ac b/configure.ac
> > > index d5a00461ff..895bd5267d 100644
> > > --- a/configure.ac
> > > +++ b/configure.ac
> > > @@ -1763,6 +1763,42 @@ fi
> > >  rm -f conftest.*])
> > >  LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
> > >
> > > +# Get Position Dependent Executable (PDE) load address to be used to
> > > +# load static Position Independent Executable (PIE) at a known working
> > > +# non-zero load address.  This is only used by glibc tests to verify
> > > +# that PIE and static PIE with non-zero load address work correctly.
> > > +AC_CACHE_CHECK([PDE load address],
> > > +              libc_cv_pde_load_address, [dnl
> > > +cat > conftest.S <<EOF
> > > +.globl _start
> > > +_start:
> > > +.globl __start
> > > +__start:
> > > +EOF
> > > +if test $libc_cv_cc_pie_default = yes; then
> > > +  pde_ld_flags="-no-pie"
> > > +fi
> > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > > +           -nostartfiles -nostdlib $no_ssp \
> > > +           -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
> > > +  # Get the load address of the first PT_LOAD segment.
> > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > > +else
> > > +  AC_MSG_ERROR([${CC-cc} can not create PDE])
> > > +fi
> > > +rm -f conftest*])
> > > +LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
> > > +
> > > +# Get the linker command-line option to load executable at a non-zero
> > > +# load address.  This is only used by glibc tests to verify that PIE and
> > > +# static PIE with non-zero load address work correctly.
> > > +LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
> > > +                   [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
> > > +                   [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
> > > +                   [libc_cv_load_address_ldflag=])
> > > +LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
> > > +
> > >  AC_MSG_CHECKING(if we can build programs as PIE)
> > >  AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
> > >  # error PIE is not supported
> > > diff --git a/elf/Makefile b/elf/Makefile
> > > index 9cfe738919..4eaca7af67 100644
> > > --- a/elf/Makefile
> > > +++ b/elf/Makefile
> > > @@ -1091,6 +1091,25 @@ tests-pie += \
> > >    tst-pie1 \
> > >    tst-pie2 \
> > >    # tests-pie
> > > +ifneq (,$(load-address-ldflag))
> > > +tests += \
> > > +  tst-pie-address \
> > > +  # tests
> > > +tests-pie += \
> > > +  tst-pie-address \
> > > +  # tests-pie
> > > +LDFLAGS-tst-pie-address += $(load-address-ldflag)=$(pde-load-address)
> > > +ifeq (yes,$(enable-static-pie))
> > > +tests += \
> > > +  tst-pie-address-static \
> > > +  # tests
> > > +tests-static += \
> > > +  tst-pie-address-static \
> > > +  # tests-static
> > > +LDFLAGS-tst-pie-address-static += \
> > > +  $(load-address-ldflag)=$(pde-load-address)
> > > +endif
> > > +endif
> > >  ifeq (yes,$(have-protected-data))
> > >  tests += vismain
> > >  tests-pie += vismain
> > > @@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
> > >
> > >  CFLAGS-tst-pie1.c += $(pie-ccflag)
> > >  CFLAGS-tst-pie2.c += $(pie-ccflag)
> > > +CFLAGS-tst-pie-address.c += $(pie-ccflag)
> > >
> > >  $(objpfx)tst-piemod1.so: $(libsupport)
> > >  $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
> > > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
> > > index 10c23d0bf0..bfee89dfc3 100644
> > > --- a/elf/dl-reloc-static-pie.c
> > > +++ b/elf/dl-reloc-static-pie.c
> > > @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
> > >  {
> > >    struct link_map *main_map = _dl_get_dl_main_map ();
> > >
> > > -  /* Figure out the run-time load address of static PIE.  */
> > > -  main_map->l_addr = elf_machine_load_address ();
> > > -
> > > -  /* Read our own dynamic section and fill in the info array.  */
> > > -  main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
> > > -
> > > +  /* NB: elf_machine_load_address () returns the run-time load address
> > > +     of static PIE.  The l_addr field contains the difference between the
> > > +     link-time load address in the ELF file and the run-time load address
> > > +     in memory.  We must subtract the link-time load address of static PIE,
> > > +     which can be non-zero, when computing the l_addr field.  Since static
> > > +     PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD
> > > +     segment with offset == 0 as the load address of static PIE.  */
> > > +  ElfW(Addr) file_p_vaddr = 0;
> > >    const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
> > >    size_t phnum = GL(dl_phnum);
> > >    for (ph = phdr; ph < &phdr[phnum]; ++ph)
> > > -    if (ph->p_type == PT_DYNAMIC)
> > > +    switch (ph->p_type)
> > >        {
> > > +      case PT_LOAD:
> > > +       if (ph->p_offset == 0)
> > > +         file_p_vaddr = ph->p_vaddr;
> > > +       break;
> > > +      case PT_DYNAMIC:
> > >         main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
> > >         break;
> > > +      default:
> > > +       break;
> > >        }
> > >
> > > +  /* Figure out the run-time load address of static PIE.  */
> > > +  ElfW(Addr) l_addr = elf_machine_load_address ();
> > > +  main_map->l_addr = l_addr - file_p_vaddr;
> > > +
> > > +  /* Read our own dynamic section and fill in the info array.  */
> > > +  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
> > > +
> > >    elf_get_dynamic_info (main_map, false, true);
> > >
> > >  # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
> > > diff --git a/elf/tst-pie-address-static.c b/elf/tst-pie-address-static.c
> > > new file mode 100644
> > > index 0000000000..be2831e9d6
> > > --- /dev/null
> > > +++ b/elf/tst-pie-address-static.c
> > > @@ -0,0 +1,19 @@
> > > +/* Test static PIE with non-zero load address.
> > > +   Copyright (C) 2024 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-pie-address.c"
> > > diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
> > > new file mode 100644
> > > index 0000000000..aa1ca0a9fd
> > > --- /dev/null
> > > +++ b/elf/tst-pie-address.c
> > > @@ -0,0 +1,28 @@
> > > +/* Test PIE with non-zero load address.
> > > +   Copyright (C) 2024 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 <stdio.h>
> > > +
> > > +static int
> > > +do_test (void)
> > > +{
> > > +  printf ("Hello\n");
> > > +  return 0;
> > > +}
> > > +
> > > +#include <support/test-driver.c>
> > > --
> > > 2.47.0
> > >
> >
> > LGTM.
> >
> > Think Carlos was also going to take a look at this (from monday review
> > minutes), so please wait for Carlos to take a look too before pushing.
>
> Hi Carlos,
>
> Do you have comments?
>
> Thanks.
>

I will check it in tomorrow.

Thanks.
Noah Goldstein Nov. 4, 2024, 4:39 p.m. UTC | #4
On Sun, Nov 3, 2024 at 5:19 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Thu, Oct 31, 2024 at 7:55 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Tue, Oct 29, 2024 at 1:33 PM Noah Goldstein <goldstein.w.n@gmail.com> wrote:
> > >
> > > On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > >
> > > > For a static PIE with non-zero load address, its PT_DYNAMIC segment
> > > > entries contain the relocated values for the load address in static PIE.
> > > > Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr of
> > > > the PT_LOAD segment with offset == 0 as the load address in static PIE
> > > > and adjust the entries of PT_DYNAMIC segment in static PIE by properly
> > > > setting the l_addr field for static PIE.  This fixes BZ #31799.
> > > >
> > > > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > > > ---
> > > >  configure                    | 74 ++++++++++++++++++++++++++++++++++++
> > > >  configure.ac                 | 36 ++++++++++++++++++
> > > >  elf/Makefile                 | 20 ++++++++++
> > > >  elf/dl-reloc-static-pie.c    | 30 +++++++++++----
> > > >  elf/tst-pie-address-static.c | 19 +++++++++
> > > >  elf/tst-pie-address.c        | 28 ++++++++++++++
> > > >  6 files changed, 200 insertions(+), 7 deletions(-)
> > > >  create mode 100644 elf/tst-pie-address-static.c
> > > >  create mode 100644 elf/tst-pie-address.c
> > > >
> > > > diff --git a/configure b/configure
> > > > index 9c0c0dce03..9bcf62dca5 100755
> > > > --- a/configure
> > > > +++ b/configure
> > > > @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default" >&6; }
> > > >  config_vars="$config_vars
> > > >  cc-pie-default = $libc_cv_cc_pie_default"
> > > >
> > > > +# Get Position Dependent Executable (PDE) load address to be used to
> > > > +# load static Position Independent Executable (PIE) at a known working
> > > > +# non-zero load address.  This is only used by glibc tests to verify
> > > > +# that PIE and static PIE with non-zero load address work correctly.
> > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load address" >&5
> > > > +printf %s "checking PDE load address... " >&6; }
> > > > +if test ${libc_cv_pde_load_address+y}
> > > > +then :
> > > > +  printf %s "(cached) " >&6
> > > > +else case e in #(
> > > > +  e) cat > conftest.S <<EOF
> > > > +.globl _start
> > > > +_start:
> > > > +.globl __start
> > > > +__start:
> > > > +EOF
> > > > +if test $libc_cv_cc_pie_default = yes; then
> > > > +  pde_ld_flags="-no-pie"
> > > > +fi
> > > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > > > +           -nostartfiles -nostdlib $no_ssp \
> > > > +           -o conftest conftest.S 1>&5 2>&5; then
> > > > +  # Get the load address of the first PT_LOAD segment.
> > > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > > > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > > > +else
> > > > +  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
> > > > +fi
> > > > +rm -f conftest* ;;
> > > > +esac
> > > > +fi
> > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_pde_load_address" >&5
> > > > +printf "%s\n" "$libc_cv_pde_load_address" >&6; }
> > > > +config_vars="$config_vars
> > > > +pde-load-address = $libc_cv_pde_load_address"
> > > > +
> > > > +# Get the linker command-line option to load executable at a non-zero
> > > > +# load address.  This is only used by glibc tests to verify that PIE and
> > > > +# static PIE with non-zero load address work correctly.
> > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
> > > > +printf %s "checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
> > > > +libc_linker_feature=no
> > > > +cat > conftest.c <<EOF
> > > > +int _start (void) { return 42; }
> > > > +EOF
> > > > +if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
> > > > +                 -Wl,-Ttext-segment=$libc_cv_pde_load_address -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=$?
> > > > +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
> > > > +  test $ac_status = 0; }; }
> > > > +then
> > > > +  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
> > > > +      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
> > > > +      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address ignored" > /dev/null 2>&1; then
> > > > +    true
> > > > +  else
> > > > +    libc_linker_feature=yes
> > > > +  fi
> > > > +fi
> > > > +rm -f conftest*
> > > > +if test $libc_linker_feature = yes; then
> > > > +  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
> > > > +else
> > > > +  libc_cv_load_address_ldflag=
> > > > +fi
> > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
> > > > +printf "%s\n" "$libc_linker_feature" >&6; }
> > > > +config_vars="$config_vars
> > > > +load-address-ldflag = $libc_cv_load_address_ldflag"
> > > > +
> > > >  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
> > > >  printf %s "checking if we can build programs as PIE... " >&6; }
> > > >  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> > > > diff --git a/configure.ac b/configure.ac
> > > > index d5a00461ff..895bd5267d 100644
> > > > --- a/configure.ac
> > > > +++ b/configure.ac
> > > > @@ -1763,6 +1763,42 @@ fi
> > > >  rm -f conftest.*])
> > > >  LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
> > > >
> > > > +# Get Position Dependent Executable (PDE) load address to be used to
> > > > +# load static Position Independent Executable (PIE) at a known working
> > > > +# non-zero load address.  This is only used by glibc tests to verify
> > > > +# that PIE and static PIE with non-zero load address work correctly.
> > > > +AC_CACHE_CHECK([PDE load address],
> > > > +              libc_cv_pde_load_address, [dnl
> > > > +cat > conftest.S <<EOF
> > > > +.globl _start
> > > > +_start:
> > > > +.globl __start
> > > > +__start:
> > > > +EOF
> > > > +if test $libc_cv_cc_pie_default = yes; then
> > > > +  pde_ld_flags="-no-pie"
> > > > +fi
> > > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > > > +           -nostartfiles -nostdlib $no_ssp \
> > > > +           -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
> > > > +  # Get the load address of the first PT_LOAD segment.
> > > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > > > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > > > +else
> > > > +  AC_MSG_ERROR([${CC-cc} can not create PDE])
> > > > +fi
> > > > +rm -f conftest*])
> > > > +LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
> > > > +
> > > > +# Get the linker command-line option to load executable at a non-zero
> > > > +# load address.  This is only used by glibc tests to verify that PIE and
> > > > +# static PIE with non-zero load address work correctly.
> > > > +LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
> > > > +                   [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
> > > > +                   [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
> > > > +                   [libc_cv_load_address_ldflag=])
> > > > +LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
> > > > +
> > > >  AC_MSG_CHECKING(if we can build programs as PIE)
> > > >  AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
> > > >  # error PIE is not supported
> > > > diff --git a/elf/Makefile b/elf/Makefile
> > > > index 9cfe738919..4eaca7af67 100644
> > > > --- a/elf/Makefile
> > > > +++ b/elf/Makefile
> > > > @@ -1091,6 +1091,25 @@ tests-pie += \
> > > >    tst-pie1 \
> > > >    tst-pie2 \
> > > >    # tests-pie
> > > > +ifneq (,$(load-address-ldflag))
> > > > +tests += \
> > > > +  tst-pie-address \
> > > > +  # tests
> > > > +tests-pie += \
> > > > +  tst-pie-address \
> > > > +  # tests-pie
> > > > +LDFLAGS-tst-pie-address += $(load-address-ldflag)=$(pde-load-address)
> > > > +ifeq (yes,$(enable-static-pie))
> > > > +tests += \
> > > > +  tst-pie-address-static \
> > > > +  # tests
> > > > +tests-static += \
> > > > +  tst-pie-address-static \
> > > > +  # tests-static
> > > > +LDFLAGS-tst-pie-address-static += \
> > > > +  $(load-address-ldflag)=$(pde-load-address)
> > > > +endif
> > > > +endif
> > > >  ifeq (yes,$(have-protected-data))
> > > >  tests += vismain
> > > >  tests-pie += vismain
> > > > @@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
> > > >
> > > >  CFLAGS-tst-pie1.c += $(pie-ccflag)
> > > >  CFLAGS-tst-pie2.c += $(pie-ccflag)
> > > > +CFLAGS-tst-pie-address.c += $(pie-ccflag)
> > > >
> > > >  $(objpfx)tst-piemod1.so: $(libsupport)
> > > >  $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
> > > > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
> > > > index 10c23d0bf0..bfee89dfc3 100644
> > > > --- a/elf/dl-reloc-static-pie.c
> > > > +++ b/elf/dl-reloc-static-pie.c
> > > > @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
> > > >  {
> > > >    struct link_map *main_map = _dl_get_dl_main_map ();
> > > >
> > > > -  /* Figure out the run-time load address of static PIE.  */
> > > > -  main_map->l_addr = elf_machine_load_address ();
> > > > -
> > > > -  /* Read our own dynamic section and fill in the info array.  */
> > > > -  main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
> > > > -
> > > > +  /* NB: elf_machine_load_address () returns the run-time load address
> > > > +     of static PIE.  The l_addr field contains the difference between the
> > > > +     link-time load address in the ELF file and the run-time load address
> > > > +     in memory.  We must subtract the link-time load address of static PIE,
> > > > +     which can be non-zero, when computing the l_addr field.  Since static
> > > > +     PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD
> > > > +     segment with offset == 0 as the load address of static PIE.  */
> > > > +  ElfW(Addr) file_p_vaddr = 0;
> > > >    const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
> > > >    size_t phnum = GL(dl_phnum);
> > > >    for (ph = phdr; ph < &phdr[phnum]; ++ph)
> > > > -    if (ph->p_type == PT_DYNAMIC)
> > > > +    switch (ph->p_type)
> > > >        {
> > > > +      case PT_LOAD:
> > > > +       if (ph->p_offset == 0)
> > > > +         file_p_vaddr = ph->p_vaddr;
> > > > +       break;
> > > > +      case PT_DYNAMIC:
> > > >         main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
> > > >         break;
> > > > +      default:
> > > > +       break;
> > > >        }
> > > >
> > > > +  /* Figure out the run-time load address of static PIE.  */
> > > > +  ElfW(Addr) l_addr = elf_machine_load_address ();
> > > > +  main_map->l_addr = l_addr - file_p_vaddr;
> > > > +
> > > > +  /* Read our own dynamic section and fill in the info array.  */
> > > > +  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
> > > > +
> > > >    elf_get_dynamic_info (main_map, false, true);
> > > >
> > > >  # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
> > > > diff --git a/elf/tst-pie-address-static.c b/elf/tst-pie-address-static.c
> > > > new file mode 100644
> > > > index 0000000000..be2831e9d6
> > > > --- /dev/null
> > > > +++ b/elf/tst-pie-address-static.c
> > > > @@ -0,0 +1,19 @@
> > > > +/* Test static PIE with non-zero load address.
> > > > +   Copyright (C) 2024 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-pie-address.c"
> > > > diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
> > > > new file mode 100644
> > > > index 0000000000..aa1ca0a9fd
> > > > --- /dev/null
> > > > +++ b/elf/tst-pie-address.c
> > > > @@ -0,0 +1,28 @@
> > > > +/* Test PIE with non-zero load address.
> > > > +   Copyright (C) 2024 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 <stdio.h>
> > > > +
> > > > +static int
> > > > +do_test (void)
> > > > +{
> > > > +  printf ("Hello\n");
> > > > +  return 0;
> > > > +}
> > > > +
> > > > +#include <support/test-driver.c>
> > > > --
> > > > 2.47.0
> > > >
> > >
> > > LGTM.
> > >
> > > Think Carlos was also going to take a look at this (from monday review
> > > minutes), so please wait for Carlos to take a look too before pushing.
> >
> > Hi Carlos,
> >
> > Do you have comments?
> >
> > Thanks.
> >
>
> I will check it in tomorrow.
>
> Thanks.

At least according to meeting notes, Carlos still wants to review this.
>
> --
> H.J.
H.J. Lu Nov. 4, 2024, 9:37 p.m. UTC | #5
On Tue, Nov 5, 2024, 12:39 AM Noah Goldstein <goldstein.w.n@gmail.com>
wrote:

> On Sun, Nov 3, 2024 at 5:19 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> >
> > On Thu, Oct 31, 2024 at 7:55 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> > >
> > > On Tue, Oct 29, 2024 at 1:33 PM Noah Goldstein <
> goldstein.w.n@gmail.com> wrote:
> > > >
> > > > On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com> wrote:
> > > > >
> > > > > For a static PIE with non-zero load address, its PT_DYNAMIC segment
> > > > > entries contain the relocated values for the load address in
> static PIE.
> > > > > Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr
> of
> > > > > the PT_LOAD segment with offset == 0 as the load address in static
> PIE
> > > > > and adjust the entries of PT_DYNAMIC segment in static PIE by
> properly
> > > > > setting the l_addr field for static PIE.  This fixes BZ #31799.
> > > > >
> > > > > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
> > > > > ---
> > > > >  configure                    | 74
> ++++++++++++++++++++++++++++++++++++
> > > > >  configure.ac                 | 36 ++++++++++++++++++
> > > > >  elf/Makefile                 | 20 ++++++++++
> > > > >  elf/dl-reloc-static-pie.c    | 30 +++++++++++----
> > > > >  elf/tst-pie-address-static.c | 19 +++++++++
> > > > >  elf/tst-pie-address.c        | 28 ++++++++++++++
> > > > >  6 files changed, 200 insertions(+), 7 deletions(-)
> > > > >  create mode 100644 elf/tst-pie-address-static.c
> > > > >  create mode 100644 elf/tst-pie-address.c
> > > > >
> > > > > diff --git a/configure b/configure
> > > > > index 9c0c0dce03..9bcf62dca5 100755
> > > > > --- a/configure
> > > > > +++ b/configure
> > > > > @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default"
> >&6; }
> > > > >  config_vars="$config_vars
> > > > >  cc-pie-default = $libc_cv_cc_pie_default"
> > > > >
> > > > > +# Get Position Dependent Executable (PDE) load address to be used
> to
> > > > > +# load static Position Independent Executable (PIE) at a known
> working
> > > > > +# non-zero load address.  This is only used by glibc tests to
> verify
> > > > > +# that PIE and static PIE with non-zero load address work
> correctly.
> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load
> address" >&5
> > > > > +printf %s "checking PDE load address... " >&6; }
> > > > > +if test ${libc_cv_pde_load_address+y}
> > > > > +then :
> > > > > +  printf %s "(cached) " >&6
> > > > > +else case e in #(
> > > > > +  e) cat > conftest.S <<EOF
> > > > > +.globl _start
> > > > > +_start:
> > > > > +.globl __start
> > > > > +__start:
> > > > > +EOF
> > > > > +if test $libc_cv_cc_pie_default = yes; then
> > > > > +  pde_ld_flags="-no-pie"
> > > > > +fi
> > > > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > > > > +           -nostartfiles -nostdlib $no_ssp \
> > > > > +           -o conftest conftest.S 1>&5 2>&5; then
> > > > > +  # Get the load address of the first PT_LOAD segment.
> > > > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > > > > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > > > > +else
> > > > > +  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
> > > > > +fi
> > > > > +rm -f conftest* ;;
> > > > > +esac
> > > > > +fi
> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result:
> $libc_cv_pde_load_address" >&5
> > > > > +printf "%s\n" "$libc_cv_pde_load_address" >&6; }
> > > > > +config_vars="$config_vars
> > > > > +pde-load-address = $libc_cv_pde_load_address"
> > > > > +
> > > > > +# Get the linker command-line option to load executable at a
> non-zero
> > > > > +# load address.  This is only used by glibc tests to verify that
> PIE and
> > > > > +# static PIE with non-zero load address work correctly.
> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker
> that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
> > > > > +printf %s "checking for linker that supports
> -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
> > > > > +libc_linker_feature=no
> > > > > +cat > conftest.c <<EOF
> > > > > +int _start (void) { return 42; }
> > > > > +EOF
> > > > > +if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
> > > > > +                 -Wl,-Ttext-segment=$libc_cv_pde_load_address
> -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=$?
> > > > > +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status"
> >&5
> > > > > +  test $ac_status = 0; }; }
> > > > > +then
> > > > > +  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
> -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
> > > > > +      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
> > > > > +      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address
> ignored" > /dev/null 2>&1; then
> > > > > +    true
> > > > > +  else
> > > > > +    libc_linker_feature=yes
> > > > > +  fi
> > > > > +fi
> > > > > +rm -f conftest*
> > > > > +if test $libc_linker_feature = yes; then
> > > > > +  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
> > > > > +else
> > > > > +  libc_cv_load_address_ldflag=
> > > > > +fi
> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result:
> $libc_linker_feature" >&5
> > > > > +printf "%s\n" "$libc_linker_feature" >&6; }
> > > > > +config_vars="$config_vars
> > > > > +load-address-ldflag = $libc_cv_load_address_ldflag"
> > > > > +
> > > > >  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can
> build programs as PIE" >&5
> > > > >  printf %s "checking if we can build programs as PIE... " >&6; }
> > > > >  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> > > > > diff --git a/configure.ac b/configure.ac
> > > > > index d5a00461ff..895bd5267d 100644
> > > > > --- a/configure.ac
> > > > > +++ b/configure.ac
> > > > > @@ -1763,6 +1763,42 @@ fi
> > > > >  rm -f conftest.*])
> > > > >  LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
> > > > >
> > > > > +# Get Position Dependent Executable (PDE) load address to be used
> to
> > > > > +# load static Position Independent Executable (PIE) at a known
> working
> > > > > +# non-zero load address.  This is only used by glibc tests to
> verify
> > > > > +# that PIE and static PIE with non-zero load address work
> correctly.
> > > > > +AC_CACHE_CHECK([PDE load address],
> > > > > +              libc_cv_pde_load_address, [dnl
> > > > > +cat > conftest.S <<EOF
> > > > > +.globl _start
> > > > > +_start:
> > > > > +.globl __start
> > > > > +__start:
> > > > > +EOF
> > > > > +if test $libc_cv_cc_pie_default = yes; then
> > > > > +  pde_ld_flags="-no-pie"
> > > > > +fi
> > > > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
> > > > > +           -nostartfiles -nostdlib $no_ssp \
> > > > > +           -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD
> 2>&AS_MESSAGE_LOG_FD; then
> > > > > +  # Get the load address of the first PT_LOAD segment.
> > > > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
> > > > > +                            | $AWK '/LOAD/ { print $3; exit 0; }')
> > > > > +else
> > > > > +  AC_MSG_ERROR([${CC-cc} can not create PDE])
> > > > > +fi
> > > > > +rm -f conftest*])
> > > > > +LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
> > > > > +
> > > > > +# Get the linker command-line option to load executable at a
> non-zero
> > > > > +# load address.  This is only used by glibc tests to verify that
> PIE and
> > > > > +# static PIE with non-zero load address work correctly.
> > > > > +LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
> > > > > +                   [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
> > > > > +
>  [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
> > > > > +                   [libc_cv_load_address_ldflag=])
> > > > > +LIBC_CONFIG_VAR([load-address-ldflag],
> [$libc_cv_load_address_ldflag])
> > > > > +
> > > > >  AC_MSG_CHECKING(if we can build programs as PIE)
> > > > >  AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
> > > > >  # error PIE is not supported
> > > > > diff --git a/elf/Makefile b/elf/Makefile
> > > > > index 9cfe738919..4eaca7af67 100644
> > > > > --- a/elf/Makefile
> > > > > +++ b/elf/Makefile
> > > > > @@ -1091,6 +1091,25 @@ tests-pie += \
> > > > >    tst-pie1 \
> > > > >    tst-pie2 \
> > > > >    # tests-pie
> > > > > +ifneq (,$(load-address-ldflag))
> > > > > +tests += \
> > > > > +  tst-pie-address \
> > > > > +  # tests
> > > > > +tests-pie += \
> > > > > +  tst-pie-address \
> > > > > +  # tests-pie
> > > > > +LDFLAGS-tst-pie-address +=
> $(load-address-ldflag)=$(pde-load-address)
> > > > > +ifeq (yes,$(enable-static-pie))
> > > > > +tests += \
> > > > > +  tst-pie-address-static \
> > > > > +  # tests
> > > > > +tests-static += \
> > > > > +  tst-pie-address-static \
> > > > > +  # tests-static
> > > > > +LDFLAGS-tst-pie-address-static += \
> > > > > +  $(load-address-ldflag)=$(pde-load-address)
> > > > > +endif
> > > > > +endif
> > > > >  ifeq (yes,$(have-protected-data))
> > > > >  tests += vismain
> > > > >  tests-pie += vismain
> > > > > @@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out:
> tst-array5-static.exp \
> > > > >
> > > > >  CFLAGS-tst-pie1.c += $(pie-ccflag)
> > > > >  CFLAGS-tst-pie2.c += $(pie-ccflag)
> > > > > +CFLAGS-tst-pie-address.c += $(pie-ccflag)
> > > > >
> > > > >  $(objpfx)tst-piemod1.so: $(libsupport)
> > > > >  $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
> > > > > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
> > > > > index 10c23d0bf0..bfee89dfc3 100644
> > > > > --- a/elf/dl-reloc-static-pie.c
> > > > > +++ b/elf/dl-reloc-static-pie.c
> > > > > @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
> > > > >  {
> > > > >    struct link_map *main_map = _dl_get_dl_main_map ();
> > > > >
> > > > > -  /* Figure out the run-time load address of static PIE.  */
> > > > > -  main_map->l_addr = elf_machine_load_address ();
> > > > > -
> > > > > -  /* Read our own dynamic section and fill in the info array.  */
> > > > > -  main_map->l_ld = ((void *) main_map->l_addr +
> elf_machine_dynamic ());
> > > > > -
> > > > > +  /* NB: elf_machine_load_address () returns the run-time load
> address
> > > > > +     of static PIE.  The l_addr field contains the difference
> between the
> > > > > +     link-time load address in the ELF file and the run-time load
> address
> > > > > +     in memory.  We must subtract the link-time load address of
> static PIE,
> > > > > +     which can be non-zero, when computing the l_addr field.
> Since static
> > > > > +     PIE usually doesn't have PT_PHDR segment, use p_vaddr of the
> PT_LOAD
> > > > > +     segment with offset == 0 as the load address of static PIE.
> */
> > > > > +  ElfW(Addr) file_p_vaddr = 0;
> > > > >    const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
> > > > >    size_t phnum = GL(dl_phnum);
> > > > >    for (ph = phdr; ph < &phdr[phnum]; ++ph)
> > > > > -    if (ph->p_type == PT_DYNAMIC)
> > > > > +    switch (ph->p_type)
> > > > >        {
> > > > > +      case PT_LOAD:
> > > > > +       if (ph->p_offset == 0)
> > > > > +         file_p_vaddr = ph->p_vaddr;
> > > > > +       break;
> > > > > +      case PT_DYNAMIC:
> > > > >         main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
> > > > >         break;
> > > > > +      default:
> > > > > +       break;
> > > > >        }
> > > > >
> > > > > +  /* Figure out the run-time load address of static PIE.  */
> > > > > +  ElfW(Addr) l_addr = elf_machine_load_address ();
> > > > > +  main_map->l_addr = l_addr - file_p_vaddr;
> > > > > +
> > > > > +  /* Read our own dynamic section and fill in the info array.  */
> > > > > +  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
> > > > > +
> > > > >    elf_get_dynamic_info (main_map, false, true);
> > > > >
> > > > >  # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
> > > > > diff --git a/elf/tst-pie-address-static.c
> b/elf/tst-pie-address-static.c
> > > > > new file mode 100644
> > > > > index 0000000000..be2831e9d6
> > > > > --- /dev/null
> > > > > +++ b/elf/tst-pie-address-static.c
> > > > > @@ -0,0 +1,19 @@
> > > > > +/* Test static PIE with non-zero load address.
> > > > > +   Copyright (C) 2024 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-pie-address.c"
> > > > > diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
> > > > > new file mode 100644
> > > > > index 0000000000..aa1ca0a9fd
> > > > > --- /dev/null
> > > > > +++ b/elf/tst-pie-address.c
> > > > > @@ -0,0 +1,28 @@
> > > > > +/* Test PIE with non-zero load address.
> > > > > +   Copyright (C) 2024 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 <stdio.h>
> > > > > +
> > > > > +static int
> > > > > +do_test (void)
> > > > > +{
> > > > > +  printf ("Hello\n");
> > > > > +  return 0;
> > > > > +}
> > > > > +
> > > > > +#include <support/test-driver.c>
> > > > > --
> > > > > 2.47.0
> > > > >
> > > >
> > > > LGTM.
> > > >
> > > > Think Carlos was also going to take a look at this (from monday
> review
> > > > minutes), so please wait for Carlos to take a look too before
> pushing.
> > >
> > > Hi Carlos,
> > >
> > > Do you have comments?
> > >
> > > Thanks.
> > >
> >
> > I will check it in tomorrow.
> >
> > Thanks.
>
> At least according to meeting notes, Carlos still wants to review this.
>

Hi Carlos,

Any estimate when you can review it?

>
> > --
> > H.J.
>
>
H.J. Lu Nov. 18, 2024, 4:12 a.m. UTC | #6
On Tue, Nov 5, 2024, 5:37 AM H.J. Lu <hjl.tools@gmail.com> wrote:

>
> On Tue, Nov 5, 2024, 12:39 AM Noah Goldstein <goldstein.w.n@gmail.com>
> wrote:
>
>> On Sun, Nov 3, 2024 at 5:19 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>> >
>> > On Thu, Oct 31, 2024 at 7:55 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>> > >
>> > > On Tue, Oct 29, 2024 at 1:33 PM Noah Goldstein <
>> goldstein.w.n@gmail.com> wrote:
>> > > >
>> > > > On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com>
>> wrote:
>> > > > >
>> > > > > For a static PIE with non-zero load address, its PT_DYNAMIC
>> segment
>> > > > > entries contain the relocated values for the load address in
>> static PIE.
>> > > > > Since static PIE usually doesn't have PT_PHDR segment, use
>> p_vaddr of
>> > > > > the PT_LOAD segment with offset == 0 as the load address in
>> static PIE
>> > > > > and adjust the entries of PT_DYNAMIC segment in static PIE by
>> properly
>> > > > > setting the l_addr field for static PIE.  This fixes BZ #31799.
>> > > > >
>> > > > > Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
>> > > > > ---
>> > > > >  configure                    | 74
>> ++++++++++++++++++++++++++++++++++++
>> > > > >  configure.ac                 | 36 ++++++++++++++++++
>> > > > >  elf/Makefile                 | 20 ++++++++++
>> > > > >  elf/dl-reloc-static-pie.c    | 30 +++++++++++----
>> > > > >  elf/tst-pie-address-static.c | 19 +++++++++
>> > > > >  elf/tst-pie-address.c        | 28 ++++++++++++++
>> > > > >  6 files changed, 200 insertions(+), 7 deletions(-)
>> > > > >  create mode 100644 elf/tst-pie-address-static.c
>> > > > >  create mode 100644 elf/tst-pie-address.c
>> > > > >
>> > > > > diff --git a/configure b/configure
>> > > > > index 9c0c0dce03..9bcf62dca5 100755
>> > > > > --- a/configure
>> > > > > +++ b/configure
>> > > > > @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default"
>> >&6; }
>> > > > >  config_vars="$config_vars
>> > > > >  cc-pie-default = $libc_cv_cc_pie_default"
>> > > > >
>> > > > > +# Get Position Dependent Executable (PDE) load address to be
>> used to
>> > > > > +# load static Position Independent Executable (PIE) at a known
>> working
>> > > > > +# non-zero load address.  This is only used by glibc tests to
>> verify
>> > > > > +# that PIE and static PIE with non-zero load address work
>> correctly.
>> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load
>> address" >&5
>> > > > > +printf %s "checking PDE load address... " >&6; }
>> > > > > +if test ${libc_cv_pde_load_address+y}
>> > > > > +then :
>> > > > > +  printf %s "(cached) " >&6
>> > > > > +else case e in #(
>> > > > > +  e) cat > conftest.S <<EOF
>> > > > > +.globl _start
>> > > > > +_start:
>> > > > > +.globl __start
>> > > > > +__start:
>> > > > > +EOF
>> > > > > +if test $libc_cv_cc_pie_default = yes; then
>> > > > > +  pde_ld_flags="-no-pie"
>> > > > > +fi
>> > > > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
>> > > > > +           -nostartfiles -nostdlib $no_ssp \
>> > > > > +           -o conftest conftest.S 1>&5 2>&5; then
>> > > > > +  # Get the load address of the first PT_LOAD segment.
>> > > > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
>> > > > > +                            | $AWK '/LOAD/ { print $3; exit 0;
>> }')
>> > > > > +else
>> > > > > +  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
>> > > > > +fi
>> > > > > +rm -f conftest* ;;
>> > > > > +esac
>> > > > > +fi
>> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result:
>> $libc_cv_pde_load_address" >&5
>> > > > > +printf "%s\n" "$libc_cv_pde_load_address" >&6; }
>> > > > > +config_vars="$config_vars
>> > > > > +pde-load-address = $libc_cv_pde_load_address"
>> > > > > +
>> > > > > +# Get the linker command-line option to load executable at a
>> non-zero
>> > > > > +# load address.  This is only used by glibc tests to verify that
>> PIE and
>> > > > > +# static PIE with non-zero load address work correctly.
>> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for
>> linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
>> > > > > +printf %s "checking for linker that supports
>> -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
>> > > > > +libc_linker_feature=no
>> > > > > +cat > conftest.c <<EOF
>> > > > > +int _start (void) { return 42; }
>> > > > > +EOF
>> > > > > +if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
>> > > > > +                 -Wl,-Ttext-segment=$libc_cv_pde_load_address
>> -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=$?
>> > > > > +  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status"
>> >&5
>> > > > > +  test $ac_status = 0; }; }
>> > > > > +then
>> > > > > +  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
>> -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
>> > > > > +      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1
>> \
>> > > > > +      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address
>> ignored" > /dev/null 2>&1; then
>> > > > > +    true
>> > > > > +  else
>> > > > > +    libc_linker_feature=yes
>> > > > > +  fi
>> > > > > +fi
>> > > > > +rm -f conftest*
>> > > > > +if test $libc_linker_feature = yes; then
>> > > > > +  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
>> > > > > +else
>> > > > > +  libc_cv_load_address_ldflag=
>> > > > > +fi
>> > > > > +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result:
>> $libc_linker_feature" >&5
>> > > > > +printf "%s\n" "$libc_linker_feature" >&6; }
>> > > > > +config_vars="$config_vars
>> > > > > +load-address-ldflag = $libc_cv_load_address_ldflag"
>> > > > > +
>> > > > >  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can
>> build programs as PIE" >&5
>> > > > >  printf %s "checking if we can build programs as PIE... " >&6; }
>> > > > >  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>> > > > > diff --git a/configure.ac b/configure.ac
>> > > > > index d5a00461ff..895bd5267d 100644
>> > > > > --- a/configure.ac
>> > > > > +++ b/configure.ac
>> > > > > @@ -1763,6 +1763,42 @@ fi
>> > > > >  rm -f conftest.*])
>> > > > >  LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
>> > > > >
>> > > > > +# Get Position Dependent Executable (PDE) load address to be
>> used to
>> > > > > +# load static Position Independent Executable (PIE) at a known
>> working
>> > > > > +# non-zero load address.  This is only used by glibc tests to
>> verify
>> > > > > +# that PIE and static PIE with non-zero load address work
>> correctly.
>> > > > > +AC_CACHE_CHECK([PDE load address],
>> > > > > +              libc_cv_pde_load_address, [dnl
>> > > > > +cat > conftest.S <<EOF
>> > > > > +.globl _start
>> > > > > +_start:
>> > > > > +.globl __start
>> > > > > +__start:
>> > > > > +EOF
>> > > > > +if test $libc_cv_cc_pie_default = yes; then
>> > > > > +  pde_ld_flags="-no-pie"
>> > > > > +fi
>> > > > > +if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
>> > > > > +           -nostartfiles -nostdlib $no_ssp \
>> > > > > +           -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD
>> 2>&AS_MESSAGE_LOG_FD; then
>> > > > > +  # Get the load address of the first PT_LOAD segment.
>> > > > > +  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
>> > > > > +                            | $AWK '/LOAD/ { print $3; exit 0;
>> }')
>> > > > > +else
>> > > > > +  AC_MSG_ERROR([${CC-cc} can not create PDE])
>> > > > > +fi
>> > > > > +rm -f conftest*])
>> > > > > +LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
>> > > > > +
>> > > > > +# Get the linker command-line option to load executable at a
>> non-zero
>> > > > > +# load address.  This is only used by glibc tests to verify that
>> PIE and
>> > > > > +# static PIE with non-zero load address work correctly.
>> > > > > +LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
>> > > > > +
>>  [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
>> > > > > +
>>  [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
>> > > > > +                   [libc_cv_load_address_ldflag=])
>> > > > > +LIBC_CONFIG_VAR([load-address-ldflag],
>> [$libc_cv_load_address_ldflag])
>> > > > > +
>> > > > >  AC_MSG_CHECKING(if we can build programs as PIE)
>> > > > >  AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
>> > > > >  # error PIE is not supported
>> > > > > diff --git a/elf/Makefile b/elf/Makefile
>> > > > > index 9cfe738919..4eaca7af67 100644
>> > > > > --- a/elf/Makefile
>> > > > > +++ b/elf/Makefile
>> > > > > @@ -1091,6 +1091,25 @@ tests-pie += \
>> > > > >    tst-pie1 \
>> > > > >    tst-pie2 \
>> > > > >    # tests-pie
>> > > > > +ifneq (,$(load-address-ldflag))
>> > > > > +tests += \
>> > > > > +  tst-pie-address \
>> > > > > +  # tests
>> > > > > +tests-pie += \
>> > > > > +  tst-pie-address \
>> > > > > +  # tests-pie
>> > > > > +LDFLAGS-tst-pie-address +=
>> $(load-address-ldflag)=$(pde-load-address)
>> > > > > +ifeq (yes,$(enable-static-pie))
>> > > > > +tests += \
>> > > > > +  tst-pie-address-static \
>> > > > > +  # tests
>> > > > > +tests-static += \
>> > > > > +  tst-pie-address-static \
>> > > > > +  # tests-static
>> > > > > +LDFLAGS-tst-pie-address-static += \
>> > > > > +  $(load-address-ldflag)=$(pde-load-address)
>> > > > > +endif
>> > > > > +endif
>> > > > >  ifeq (yes,$(have-protected-data))
>> > > > >  tests += vismain
>> > > > >  tests-pie += vismain
>> > > > > @@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out:
>> tst-array5-static.exp \
>> > > > >
>> > > > >  CFLAGS-tst-pie1.c += $(pie-ccflag)
>> > > > >  CFLAGS-tst-pie2.c += $(pie-ccflag)
>> > > > > +CFLAGS-tst-pie-address.c += $(pie-ccflag)
>> > > > >
>> > > > >  $(objpfx)tst-piemod1.so: $(libsupport)
>> > > > >  $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
>> > > > > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
>> > > > > index 10c23d0bf0..bfee89dfc3 100644
>> > > > > --- a/elf/dl-reloc-static-pie.c
>> > > > > +++ b/elf/dl-reloc-static-pie.c
>> > > > > @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
>> > > > >  {
>> > > > >    struct link_map *main_map = _dl_get_dl_main_map ();
>> > > > >
>> > > > > -  /* Figure out the run-time load address of static PIE.  */
>> > > > > -  main_map->l_addr = elf_machine_load_address ();
>> > > > > -
>> > > > > -  /* Read our own dynamic section and fill in the info array.  */
>> > > > > -  main_map->l_ld = ((void *) main_map->l_addr +
>> elf_machine_dynamic ());
>> > > > > -
>> > > > > +  /* NB: elf_machine_load_address () returns the run-time load
>> address
>> > > > > +     of static PIE.  The l_addr field contains the difference
>> between the
>> > > > > +     link-time load address in the ELF file and the run-time
>> load address
>> > > > > +     in memory.  We must subtract the link-time load address of
>> static PIE,
>> > > > > +     which can be non-zero, when computing the l_addr field.
>> Since static
>> > > > > +     PIE usually doesn't have PT_PHDR segment, use p_vaddr of
>> the PT_LOAD
>> > > > > +     segment with offset == 0 as the load address of static
>> PIE.  */
>> > > > > +  ElfW(Addr) file_p_vaddr = 0;
>> > > > >    const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
>> > > > >    size_t phnum = GL(dl_phnum);
>> > > > >    for (ph = phdr; ph < &phdr[phnum]; ++ph)
>> > > > > -    if (ph->p_type == PT_DYNAMIC)
>> > > > > +    switch (ph->p_type)
>> > > > >        {
>> > > > > +      case PT_LOAD:
>> > > > > +       if (ph->p_offset == 0)
>> > > > > +         file_p_vaddr = ph->p_vaddr;
>> > > > > +       break;
>> > > > > +      case PT_DYNAMIC:
>> > > > >         main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
>> > > > >         break;
>> > > > > +      default:
>> > > > > +       break;
>> > > > >        }
>> > > > >
>> > > > > +  /* Figure out the run-time load address of static PIE.  */
>> > > > > +  ElfW(Addr) l_addr = elf_machine_load_address ();
>> > > > > +  main_map->l_addr = l_addr - file_p_vaddr;
>> > > > > +
>> > > > > +  /* Read our own dynamic section and fill in the info array.  */
>> > > > > +  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
>> > > > > +
>> > > > >    elf_get_dynamic_info (main_map, false, true);
>> > > > >
>> > > > >  # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
>> > > > > diff --git a/elf/tst-pie-address-static.c
>> b/elf/tst-pie-address-static.c
>> > > > > new file mode 100644
>> > > > > index 0000000000..be2831e9d6
>> > > > > --- /dev/null
>> > > > > +++ b/elf/tst-pie-address-static.c
>> > > > > @@ -0,0 +1,19 @@
>> > > > > +/* Test static PIE with non-zero load address.
>> > > > > +   Copyright (C) 2024 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-pie-address.c"
>> > > > > diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
>> > > > > new file mode 100644
>> > > > > index 0000000000..aa1ca0a9fd
>> > > > > --- /dev/null
>> > > > > +++ b/elf/tst-pie-address.c
>> > > > > @@ -0,0 +1,28 @@
>> > > > > +/* Test PIE with non-zero load address.
>> > > > > +   Copyright (C) 2024 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 <stdio.h>
>> > > > > +
>> > > > > +static int
>> > > > > +do_test (void)
>> > > > > +{
>> > > > > +  printf ("Hello\n");
>> > > > > +  return 0;
>> > > > > +}
>> > > > > +
>> > > > > +#include <support/test-driver.c>
>> > > > > --
>> > > > > 2.47.0
>> > > > >
>> > > >
>> > > > LGTM.
>> > > >
>> > > > Think Carlos was also going to take a look at this (from monday
>> review
>> > > > minutes), so please wait for Carlos to take a look too before
>> pushing.
>> > >
>> > > Hi Carlos,
>> > >
>> > > Do you have comments?
>> > >
>> > > Thanks.
>> > >
>> >
>> > I will check it in tomorrow.
>> >
>> > Thanks.
>>
>> At least according to meeting notes, Carlos still wants to review this.
>>
>
> Hi Carlos,
>
> Any estimate when you can review it?
>

I will check it in this week.


> >
>> > --
>> > H.J.
>>
>>
>>
diff mbox series

Patch

diff --git a/configure b/configure
index 9c0c0dce03..9bcf62dca5 100755
--- a/configure
+++ b/configure
@@ -8107,6 +8107,80 @@  printf "%s\n" "$libc_cv_cc_pie_default" >&6; }
 config_vars="$config_vars
 cc-pie-default = $libc_cv_cc_pie_default"
 
+# Get Position Dependent Executable (PDE) load address to be used to
+# load static Position Independent Executable (PIE) at a known working
+# non-zero load address.  This is only used by glibc tests to verify
+# that PIE and static PIE with non-zero load address work correctly.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load address" >&5
+printf %s "checking PDE load address... " >&6; }
+if test ${libc_cv_pde_load_address+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) cat > conftest.S <<EOF
+.globl _start
+_start:
+.globl __start
+__start:
+EOF
+if test $libc_cv_cc_pie_default = yes; then
+  pde_ld_flags="-no-pie"
+fi
+if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
+	    -nostartfiles -nostdlib $no_ssp \
+	    -o conftest conftest.S 1>&5 2>&5; then
+  # Get the load address of the first PT_LOAD segment.
+  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
+			     | $AWK '/LOAD/ { print $3; exit 0; }')
+else
+  as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
+fi
+rm -f conftest* ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_pde_load_address" >&5
+printf "%s\n" "$libc_cv_pde_load_address" >&6; }
+config_vars="$config_vars
+pde-load-address = $libc_cv_pde_load_address"
+
+# Get the linker command-line option to load executable at a non-zero
+# load address.  This is only used by glibc tests to verify that PIE and
+# static PIE with non-zero load address work correctly.
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
+printf %s "checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
+libc_linker_feature=no
+cat > conftest.c <<EOF
+int _start (void) { return 42; }
+EOF
+if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
+		  -Wl,-Ttext-segment=$libc_cv_pde_load_address -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=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+then
+  if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
+      -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
+      | grep "warning: -Ttext-segment=$libc_cv_pde_load_address ignored" > /dev/null 2>&1; then
+    true
+  else
+    libc_linker_feature=yes
+  fi
+fi
+rm -f conftest*
+if test $libc_linker_feature = yes; then
+  libc_cv_load_address_ldflag=-Wl,-Ttext-segment
+else
+  libc_cv_load_address_ldflag=
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
+printf "%s\n" "$libc_linker_feature" >&6; }
+config_vars="$config_vars
+load-address-ldflag = $libc_cv_load_address_ldflag"
+
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
 printf %s "checking if we can build programs as PIE... " >&6; }
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
diff --git a/configure.ac b/configure.ac
index d5a00461ff..895bd5267d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1763,6 +1763,42 @@  fi
 rm -f conftest.*])
 LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
 
+# Get Position Dependent Executable (PDE) load address to be used to
+# load static Position Independent Executable (PIE) at a known working
+# non-zero load address.  This is only used by glibc tests to verify
+# that PIE and static PIE with non-zero load address work correctly.
+AC_CACHE_CHECK([PDE load address],
+	       libc_cv_pde_load_address, [dnl
+cat > conftest.S <<EOF
+.globl _start
+_start:
+.globl __start
+__start:
+EOF
+if test $libc_cv_cc_pie_default = yes; then
+  pde_ld_flags="-no-pie"
+fi
+if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
+	    -nostartfiles -nostdlib $no_ssp \
+	    -o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
+  # Get the load address of the first PT_LOAD segment.
+  libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
+			     | $AWK '/LOAD/ { print $3; exit 0; }')
+else
+  AC_MSG_ERROR([${CC-cc} can not create PDE])
+fi
+rm -f conftest*])
+LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
+
+# Get the linker command-line option to load executable at a non-zero
+# load address.  This is only used by glibc tests to verify that PIE and
+# static PIE with non-zero load address work correctly.
+LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
+		    [-Wl,-Ttext-segment=$libc_cv_pde_load_address],
+		    [libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
+		    [libc_cv_load_address_ldflag=])
+LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
+
 AC_MSG_CHECKING(if we can build programs as PIE)
 AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
 # error PIE is not supported
diff --git a/elf/Makefile b/elf/Makefile
index 9cfe738919..4eaca7af67 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1091,6 +1091,25 @@  tests-pie += \
   tst-pie1 \
   tst-pie2 \
   # tests-pie
+ifneq (,$(load-address-ldflag))
+tests += \
+  tst-pie-address \
+  # tests
+tests-pie += \
+  tst-pie-address \
+  # tests-pie
+LDFLAGS-tst-pie-address += $(load-address-ldflag)=$(pde-load-address)
+ifeq (yes,$(enable-static-pie))
+tests += \
+  tst-pie-address-static \
+  # tests
+tests-static += \
+  tst-pie-address-static \
+  # tests-static
+LDFLAGS-tst-pie-address-static += \
+  $(load-address-ldflag)=$(pde-load-address)
+endif
+endif
 ifeq (yes,$(have-protected-data))
 tests += vismain
 tests-pie += vismain
@@ -1937,6 +1956,7 @@  $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
 
 CFLAGS-tst-pie1.c += $(pie-ccflag)
 CFLAGS-tst-pie2.c += $(pie-ccflag)
+CFLAGS-tst-pie-address.c += $(pie-ccflag)
 
 $(objpfx)tst-piemod1.so: $(libsupport)
 $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
index 10c23d0bf0..bfee89dfc3 100644
--- a/elf/dl-reloc-static-pie.c
+++ b/elf/dl-reloc-static-pie.c
@@ -37,21 +37,37 @@  _dl_relocate_static_pie (void)
 {
   struct link_map *main_map = _dl_get_dl_main_map ();
 
-  /* Figure out the run-time load address of static PIE.  */
-  main_map->l_addr = elf_machine_load_address ();
-
-  /* Read our own dynamic section and fill in the info array.  */
-  main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
-
+  /* NB: elf_machine_load_address () returns the run-time load address
+     of static PIE.  The l_addr field contains the difference between the
+     link-time load address in the ELF file and the run-time load address
+     in memory.  We must subtract the link-time load address of static PIE,
+     which can be non-zero, when computing the l_addr field.  Since static
+     PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD
+     segment with offset == 0 as the load address of static PIE.  */
+  ElfW(Addr) file_p_vaddr = 0;
   const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
   size_t phnum = GL(dl_phnum);
   for (ph = phdr; ph < &phdr[phnum]; ++ph)
-    if (ph->p_type == PT_DYNAMIC)
+    switch (ph->p_type)
       {
+      case PT_LOAD:
+	if (ph->p_offset == 0)
+	  file_p_vaddr = ph->p_vaddr;
+	break;
+      case PT_DYNAMIC:
 	main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
 	break;
+      default:
+	break;
       }
 
+  /* Figure out the run-time load address of static PIE.  */
+  ElfW(Addr) l_addr = elf_machine_load_address ();
+  main_map->l_addr = l_addr - file_p_vaddr;
+
+  /* Read our own dynamic section and fill in the info array.  */
+  main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
+
   elf_get_dynamic_info (main_map, false, true);
 
 # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
diff --git a/elf/tst-pie-address-static.c b/elf/tst-pie-address-static.c
new file mode 100644
index 0000000000..be2831e9d6
--- /dev/null
+++ b/elf/tst-pie-address-static.c
@@ -0,0 +1,19 @@ 
+/* Test static PIE with non-zero load address.
+   Copyright (C) 2024 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-pie-address.c"
diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
new file mode 100644
index 0000000000..aa1ca0a9fd
--- /dev/null
+++ b/elf/tst-pie-address.c
@@ -0,0 +1,28 @@ 
+/* Test PIE with non-zero load address.
+   Copyright (C) 2024 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 <stdio.h>
+
+static int
+do_test (void)
+{
+  printf ("Hello\n");
+  return 0;
+}
+
+#include <support/test-driver.c>