diff mbox series

[uclibc-ng-devel,v3] Static PIE support for i386, x86_64, and arm

Message ID CANP1oa1COU-943DTbcJ=ECYUxxFT4MJyfitJZUXDMqDyZLDVuA@mail.gmail.com
State Superseded
Headers show
Series [uclibc-ng-devel,v3] Static PIE support for i386, x86_64, and arm | expand

Commit Message

linted July 17, 2022, 6:04 p.m. UTC
Hello,
This is an updated patch for static pie support. I have corrected
formatting and code standard issues which appeared in my previous patches.
I also updated the commit message to be clearer on what is occurring and
why.

-linted

From 92056b7db87be00e6daea59a4f82d022bfc7f223 Mon Sep 17 00:00:00 2001
From: linted <linted@users.noreply.github.com>
Date: Sun, 17 Jul 2022 13:38:49 -0400
Subject: [PATCH] Added support for creation of Static Position-Independent
 Executables (PIE) on i386, x86_64, and arm.

This patch adds the generation of rcrt1.o which is used by gcc when
compiling with the --static-pie flag.

rcrt1.o differs from crt1.o and Scrt1.o in that it the executable has a
dynamic section but no relocations have been performed prior to _start
being called.
crt1.o assumes there to be no dynamic relocations, and Scrt1.o has all
relocations performed prior to execution by lsdo.

The new reloc_static_pie function handles parsing the elf headers, locating
the dynamic section, and performing the relocations in a architecture
agnostic method.
This allows for easier porting of static-pie support to additional
architectures.

Signed-off-by: linted <linted@users.noreply.github.com>
---
 Makerules                              |  5 ++++
 extra/Configs/Config.in                |  5 ++++
 libc/misc/internals/Makefile.in        |  1 +
 libc/misc/internals/reloc_static_pie.c | 41 ++++++++++++++++++++++++++
 libc/sysdeps/linux/arm/crt1.S          | 15 ++++++++++
 libc/sysdeps/linux/i386/crt1.S         | 20 +++++++++++++
 libc/sysdeps/linux/x86_64/crt1.S       | 16 +++++++++-
 7 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 libc/misc/internals/reloc_static_pie.c

**),
    int argc, char *argv,
@@ -107,7 +121,7 @@ _start:
    which grow downwards).  */
  pushq %rsp

-#if defined(L_Scrt1)
+#if defined(L_Scrt1) || defined(L_rcrt1)
  /* Give address for main() */
  movq main@GOTPCREL(%rip), %rdi

Comments

Lance Fredrickson July 18, 2022, 8:06 p.m. UTC | #1
So giving this a try on arm, I patched the latest uclibc-ng from git 
with this v3 patch and enabled it with the "STATIC_PIE=y" option. I see 
that rcrt1.o is now built in my toolchain.

I try to compile -static-pie binary but get the following.
arm-linux-gcc -static-pie hello.c -o hello
/opt/tomatoware/arm-soft-mmc/lib/gcc/arm-tomatoware-linux-uclibcgnueabi/12.1.0/../../../../arm-tomatoware-linux-uclibcgnueabi/bin/ld: 
/opt/tomatoware/arm-soft-mmc/arm-tomatoware-linux-uclibcgnueabi/sysroot/usr/lib/rcrt1.o: 
in function `_start':
(.text+0x24): undefined reference to `reloc_static_pie'

I see symbol "reloc_static_pie" exists in rcrt1.o and libc.a, so I'm not 
sure at this point. Symbol needs to be exported maybe?  On alpine I see 
"gcc -static-pie hello.c -o hello" is enough to get static-pie

thanks,
Lance

On 7/17/2022 12:04 PM, linted wrote:
> Hello,
> This is an updated patch for static pie support. I have corrected 
> formatting and code standard issues which appeared in my previous 
> patches. I also updated the commit message to be clearer on what is 
> occurring and why.
>
> -linted
>
> From 92056b7db87be00e6daea59a4f82d022bfc7f223 Mon Sep 17 00:00:00 2001
> From: linted <linted@users.noreply.github.com>
> Date: Sun, 17 Jul 2022 13:38:49 -0400
> Subject: [PATCH] Added support for creation of Static Position-Independent
>  Executables (PIE) on i386, x86_64, and arm.
>
> This patch adds the generation of rcrt1.o which is used by gcc when 
> compiling with the --static-pie flag.
>
> rcrt1.o differs from crt1.o and Scrt1.o in that it the executable has 
> a dynamic section but no relocations have been performed prior to 
> _start being called.
> crt1.o assumes there to be no dynamic relocations, and Scrt1.o has all 
> relocations performed prior to execution by lsdo.
>
> The new reloc_static_pie function handles parsing the elf headers, 
> locating the dynamic section, and performing the relocations in a 
> architecture agnostic method.
> This allows for easier porting of static-pie support to additional 
> architectures.
>
> Signed-off-by: linted <linted@users.noreply.github.com>
> ---
>  Makerules                              |  5 ++++
>  extra/Configs/Config.in                |  5 ++++
>  libc/misc/internals/Makefile.in        |  1 +
>  libc/misc/internals/reloc_static_pie.c | 41 ++++++++++++++++++++++++++
>  libc/sysdeps/linux/arm/crt1.S          | 15 ++++++++++
>  libc/sysdeps/linux/i386/crt1.S         | 20 +++++++++++++
>  libc/sysdeps/linux/x86_64/crt1.S       | 16 +++++++++-
>  7 files changed, 102 insertions(+), 1 deletion(-)
>  create mode 100644 libc/misc/internals/reloc_static_pie.c
>
> diff --git a/Makerules b/Makerules
> index fd40e6c7b..845d81897 100644
> --- a/Makerules
> +++ b/Makerules
> @@ -405,8 +405,13 @@ else
>  CRTS=$(top_builddir)lib/$(CRT).o
>  endif
>
> +ifeq ($(STATIC_PIE),y)
> +CRTS+=$(top_builddir)lib/r$(CRT).o
> +endif
> +
>  ASFLAGS-$(CRT).o := -DL_$(CRT)
>  ASFLAGS-S$(CRT).o := $(PIEFLAG) -DL_S$(CRT)
> +ASFLAGS-r$(CRT).o := $(PIEFLAG) -DL_r$(CRT)
>  $(CRTS): $(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH)/$(CRT).S
>   $(compile.S)
>   $(Q)$(STRIPTOOL) -x -R .note -R .comment $@
> diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
> index a58ceb265..a49278b30 100644
> --- a/extra/Configs/Config.in
> +++ b/extra/Configs/Config.in
> @@ -301,6 +301,11 @@ config DOPIC
>    If you wish to build all of uClibc as PIC objects, then answer Y here.
>    If you are unsure, then you should answer N.
>
> +config STATIC_PIE
> + bool "Add support for Static Position Independent Executables (PIE)"
> + default n
> + depends on DOPIC && !UCLIBC_FORMAT_FDPIC_ELF && (TARGET_arm || 
> TARGET_i386 || TARGET_x86_64)
> +
>  config ARCH_HAS_NO_SHARED
>   bool
>
> diff --git a/libc/misc/internals/Makefile.in 
> b/libc/misc/internals/Makefile.in
> index a8e4e36f9..4a6e73d2d 100644
> --- a/libc/misc/internals/Makefile.in
> +++ b/libc/misc/internals/Makefile.in
> @@ -34,6 +34,7 @@ libc-static-$(UCLIBC_FORMAT_FLAT_SEP_DATA) += \
>  libc-static-$(UCLIBC_FORMAT_SHARED_FLAT) += \
>    $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \
>    $(MISC_INTERNALS_OUT)/shared_flat_add_library.o
> +libc-static-$(STATIC_PIE) += $(MISC_INTERNALS_OUT)/reloc_static_pie.o
>  libc-shared-$(UCLIBC_FORMAT_SHARED_FLAT) += \
>    $(MISC_INTERNALS_OUT)/shared_flat_initfini.os \
>    $(MISC_INTERNALS_OUT)/shared_flat_add_library.os
> diff --git a/libc/misc/internals/reloc_static_pie.c 
> b/libc/misc/internals/reloc_static_pie.c
> new file mode 100644
> index 000000000..9a8066b84
> --- /dev/null
> +++ b/libc/misc/internals/reloc_static_pie.c
> @@ -0,0 +1,41 @@
> +/* Support for relocating static PIE.
> +   Copyright (C) 2017-2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <link.h>
> +#include <elf.h>
> +#include <dl-elf.h>
> +
> +void
> +reloc_static_pie (ElfW(Addr) load_addr)
> +{
> +    ElfW(Word) relative_count = 0;
> +    ElfW(Addr) rel_addr = NULL;
> +    ElfW(Dyn) * dyn_addr = NULL;
> +    unsigned long dynamic_info[DYNAMIC_SIZE] = {0};
> +
> +    /* Read our own dynamic section and fill in the info array.  */
> +    dyn_addr = ((void *) load_addr + elf_machine_dynamic ());
> +
> +    /* Use the underlying function to avoid TLS access before 
> initialization */
> +    __dl_parse_dynamic_info(dyn_addr, dynamic_info, NULL, load_addr);
> +
> +    /* Perform relocations */
> +    relative_count = dynamic_info[DT_RELCONT_IDX];
> +    rel_addr = dynamic_info[DT_RELOC_TABLE_ADDR];
> +    elf_machine_relative(load_addr, rel_addr, relative_count);
> +}
> diff --git a/libc/sysdeps/linux/arm/crt1.S b/libc/sysdeps/linux/arm/crt1.S
> index a1d7f0f23..2aa2a5234 100644
> --- a/libc/sysdeps/linux/arm/crt1.S
> +++ b/libc/sysdeps/linux/arm/crt1.S
> @@ -246,6 +246,18 @@ _start:
>   mov lr, #0
>
>  #ifdef __ARCH_USE_MMU__
> +#ifdef L_rcrt1
> + /* We don't need to save a1 since no dynamic linker should have run */
> + ldr a1, .L_GOT          /* Get value at .L_GOT + 0  (offset to GOT)*/
> + adr a2, .L_GOT          /* Get address of .L_GOT */
> + ldr a3, .L_GOT+16       /* get value of _start(GOT) stored in .L_GOT */
> + adr a4, _start          /* get address of _start after relocation 
> (changes to pc - ~30 or so) */
> + add a1, a1, a2          /* calculate where the GOT is */
> + ldr a2, [a1, a3]        /* GOT + _start(GOT) = offset of _start from 
> begin of file */
> + sub a1, a4, a2          /* current addr of _start - offset from 
> beginning of file = load addr */
> + bl reloc_static_pie
> + mov a1, #0              /* Clean up a1 so that a random address 
> won't get called at the end of program */
> +#endif
>   /* Pop argc off the stack and save a pointer to argv */
>   ldr a2, [sp], #4
>   mov a3, sp
> @@ -309,6 +321,9 @@ _start:
>   .word _fini(GOT)
>   .word _init(GOT)
>   .word main(GOT)
> +#ifdef L_rcrt1
> + .word _start(GOT)
> +#endif
>  #endif
>  #endif
>
> diff --git a/libc/sysdeps/linux/i386/crt1.S 
> b/libc/sysdeps/linux/i386/crt1.S
> index 35a6552e8..decc68967 100644
> --- a/libc/sysdeps/linux/i386/crt1.S
> +++ b/libc/sysdeps/linux/i386/crt1.S
> @@ -67,6 +67,9 @@
>  #endif
>  .type   main,%function
>  .type   __uClibc_main,%function
> +#ifdef L_rcrt1
> +.type reloc_static_pie,%function
> +#endif
>  _start:
>   /* Clear the frame pointer.  The ABI suggests this be done, to mark
>     the outermost frame obviously.  */
> @@ -100,6 +103,23 @@ _start:
>   pop %ebx
>   addl $_GLOBAL_OFFSET_TABLE_+[.-.L0],%ebx
>
> +#ifdef L_rcrt1
> + /* We cannot rely on _DYNAMIC being usable here due to RELRO.
> +   Instead we calculate the load address based off a symbol
> +   that we know will exist, _start. */
> + pushl %ecx                      /* Save ecx so it won't get clobbered */
> + pushl %ebx                      /* Save ebx so it won't get clobbered */
> + xorl %ecx, %ecx                 /* Clear ecx */
> + addl _start@GOT(%ebx), %ecx     /* Get the offset of _start */
> + movl _start@GOT(%ebx), %eax     /* Get the run time address of _start */
> + subl %ecx, %eax                 /* Subtract to find the load address */
> + pushl %eax                      /* Pass the load address */
> + call reloc_static_pie@PLT
> + popl %eax                       /* Clean up from function call */
> + popl %ebx                       /* Restore the GOT address */
> + popl %ecx                       /* restore ecx */
> +#endif
> +
>   /* Push address of our own entry points to .fini and .init.  */
>   pushl _fini@GOT(%ebx)
>   pushl _init@GOT(%ebx)
> diff --git a/libc/sysdeps/linux/x86_64/crt1.S 
> b/libc/sysdeps/linux/x86_64/crt1.S
> index 87777dd5d..701cbf2f6 100644
> --- a/libc/sysdeps/linux/x86_64/crt1.S
> +++ b/libc/sysdeps/linux/x86_64/crt1.S
> @@ -80,6 +80,20 @@ _start:
>     the outermost frame obviously.  */
>   xorl %ebp, %ebp
>
> +#ifdef L_rcrt1
> + pushq %rdi                          /* save rdi (but should be 0...) */
> + pushq %rdx                          /* store rdx (rtld_fini) */
> + xorq %rcx, %rcx                     /* ensure rcx is 0 */
> + addq _start@GOTPCREL(%rip), %rcx    /* get offset of _start from 
> beginning of file */
> + movq _start@GOTPCREL(%rip), %rax    /* get run time address of _start */
> + subq %rcx, %rax                     /* calculate run time load offset */
> + movq %rax, %rdi                     /* load offset -> param 1 */
> + call reloc_static_pie               /* relocate dynamic addrs */
> + xorq %rax, %rax                     /* cleanup */
> + popq %rdx
> + popq %rdi
> +#endif
> +
>   /* Extract the arguments as encoded on the stack and set up
>     the arguments for __libc_start_main (int (*main) (int, char **, 
> char **),
>     int argc, char *argv,
> @@ -107,7 +121,7 @@ _start:
>     which grow downwards).  */
>   pushq %rsp
>
> -#if defined(L_Scrt1)
> +#if defined(L_Scrt1) || defined(L_rcrt1)
>   /* Give address for main() */
>   movq main@GOTPCREL(%rip), %rdi
>
> -- 
> 2.34.1
>
>
>
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
Yann Sionneau July 18, 2022, 8:41 p.m. UTC | #2
Hello,

Thanks for the patch, I'll give it a try and report back.

Regards,

Yann

Le 17/07/2022 à 20:04, linted a écrit :
> Hello,
> This is an updated patch for static pie support. I have corrected 
> formatting and code standard issues which appeared in my previous 
> patches. I also updated the commit message to be clearer on what is 
> occurring and why.
>
> -linted
>
> From 92056b7db87be00e6daea59a4f82d022bfc7f223 Mon Sep 17 00:00:00 2001
> From: linted <linted@users.noreply.github.com>
> Date: Sun, 17 Jul 2022 13:38:49 -0400
> Subject: [PATCH] Added support for creation of Static Position-Independent
>  Executables (PIE) on i386, x86_64, and arm.
>
> This patch adds the generation of rcrt1.o which is used by gcc when 
> compiling with the --static-pie flag.
>
> rcrt1.o differs from crt1.o and Scrt1.o in that it the executable has 
> a dynamic section but no relocations have been performed prior to 
> _start being called.
> crt1.o assumes there to be no dynamic relocations, and Scrt1.o has all 
> relocations performed prior to execution by lsdo.
>
> The new reloc_static_pie function handles parsing the elf headers, 
> locating the dynamic section, and performing the relocations in a 
> architecture agnostic method.
> This allows for easier porting of static-pie support to additional 
> architectures.
>
> Signed-off-by: linted <linted@users.noreply.github.com>
> ---
>  Makerules                              |  5 ++++
>  extra/Configs/Config.in                |  5 ++++
>  libc/misc/internals/Makefile.in        |  1 +
>  libc/misc/internals/reloc_static_pie.c | 41 ++++++++++++++++++++++++++
>  libc/sysdeps/linux/arm/crt1.S          | 15 ++++++++++
>  libc/sysdeps/linux/i386/crt1.S         | 20 +++++++++++++
>  libc/sysdeps/linux/x86_64/crt1.S       | 16 +++++++++-
>  7 files changed, 102 insertions(+), 1 deletion(-)
>  create mode 100644 libc/misc/internals/reloc_static_pie.c
>
> diff --git a/Makerules b/Makerules
> index fd40e6c7b..845d81897 100644
> --- a/Makerules
> +++ b/Makerules
> @@ -405,8 +405,13 @@ else
>  CRTS=$(top_builddir)lib/$(CRT).o
>  endif
>
> +ifeq ($(STATIC_PIE),y)
> +CRTS+=$(top_builddir)lib/r$(CRT).o
> +endif
> +
>  ASFLAGS-$(CRT).o := -DL_$(CRT)
>  ASFLAGS-S$(CRT).o := $(PIEFLAG) -DL_S$(CRT)
> +ASFLAGS-r$(CRT).o := $(PIEFLAG) -DL_r$(CRT)
>  $(CRTS): $(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH)/$(CRT).S
>   $(compile.S)
>   $(Q)$(STRIPTOOL) -x -R .note -R .comment $@
> diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
> index a58ceb265..a49278b30 100644
> --- a/extra/Configs/Config.in
> +++ b/extra/Configs/Config.in
> @@ -301,6 +301,11 @@ config DOPIC
>    If you wish to build all of uClibc as PIC objects, then answer Y here.
>    If you are unsure, then you should answer N.
>
> +config STATIC_PIE
> + bool "Add support for Static Position Independent Executables (PIE)"
> + default n
> + depends on DOPIC && !UCLIBC_FORMAT_FDPIC_ELF && (TARGET_arm || 
> TARGET_i386 || TARGET_x86_64)
> +
>  config ARCH_HAS_NO_SHARED
>   bool
>
> diff --git a/libc/misc/internals/Makefile.in 
> b/libc/misc/internals/Makefile.in
> index a8e4e36f9..4a6e73d2d 100644
> --- a/libc/misc/internals/Makefile.in
> +++ b/libc/misc/internals/Makefile.in
> @@ -34,6 +34,7 @@ libc-static-$(UCLIBC_FORMAT_FLAT_SEP_DATA) += \
>  libc-static-$(UCLIBC_FORMAT_SHARED_FLAT) += \
>    $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \
>    $(MISC_INTERNALS_OUT)/shared_flat_add_library.o
> +libc-static-$(STATIC_PIE) += $(MISC_INTERNALS_OUT)/reloc_static_pie.o
>  libc-shared-$(UCLIBC_FORMAT_SHARED_FLAT) += \
>    $(MISC_INTERNALS_OUT)/shared_flat_initfini.os \
>    $(MISC_INTERNALS_OUT)/shared_flat_add_library.os
> diff --git a/libc/misc/internals/reloc_static_pie.c 
> b/libc/misc/internals/reloc_static_pie.c
> new file mode 100644
> index 000000000..9a8066b84
> --- /dev/null
> +++ b/libc/misc/internals/reloc_static_pie.c
> @@ -0,0 +1,41 @@
> +/* Support for relocating static PIE.
> +   Copyright (C) 2017-2022 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <link.h>
> +#include <elf.h>
> +#include <dl-elf.h>
> +
> +void
> +reloc_static_pie (ElfW(Addr) load_addr)
> +{
> +    ElfW(Word) relative_count = 0;
> +    ElfW(Addr) rel_addr = NULL;
> +    ElfW(Dyn) * dyn_addr = NULL;
> +    unsigned long dynamic_info[DYNAMIC_SIZE] = {0};
> +
> +    /* Read our own dynamic section and fill in the info array.  */
> +    dyn_addr = ((void *) load_addr + elf_machine_dynamic ());
> +
> +    /* Use the underlying function to avoid TLS access before 
> initialization */
> +    __dl_parse_dynamic_info(dyn_addr, dynamic_info, NULL, load_addr);
> +
> +    /* Perform relocations */
> +    relative_count = dynamic_info[DT_RELCONT_IDX];
> +    rel_addr = dynamic_info[DT_RELOC_TABLE_ADDR];
> +    elf_machine_relative(load_addr, rel_addr, relative_count);
> +}
> diff --git a/libc/sysdeps/linux/arm/crt1.S b/libc/sysdeps/linux/arm/crt1.S
> index a1d7f0f23..2aa2a5234 100644
> --- a/libc/sysdeps/linux/arm/crt1.S
> +++ b/libc/sysdeps/linux/arm/crt1.S
> @@ -246,6 +246,18 @@ _start:
>   mov lr, #0
>
>  #ifdef __ARCH_USE_MMU__
> +#ifdef L_rcrt1
> + /* We don't need to save a1 since no dynamic linker should have run */
> + ldr a1, .L_GOT          /* Get value at .L_GOT + 0  (offset to GOT)*/
> + adr a2, .L_GOT          /* Get address of .L_GOT */
> + ldr a3, .L_GOT+16       /* get value of _start(GOT) stored in .L_GOT */
> + adr a4, _start          /* get address of _start after relocation 
> (changes to pc - ~30 or so) */
> + add a1, a1, a2          /* calculate where the GOT is */
> + ldr a2, [a1, a3]        /* GOT + _start(GOT) = offset of _start from 
> begin of file */
> + sub a1, a4, a2          /* current addr of _start - offset from 
> beginning of file = load addr */
> + bl reloc_static_pie
> + mov a1, #0              /* Clean up a1 so that a random address 
> won't get called at the end of program */
> +#endif
>   /* Pop argc off the stack and save a pointer to argv */
>   ldr a2, [sp], #4
>   mov a3, sp
> @@ -309,6 +321,9 @@ _start:
>   .word _fini(GOT)
>   .word _init(GOT)
>   .word main(GOT)
> +#ifdef L_rcrt1
> + .word _start(GOT)
> +#endif
>  #endif
>  #endif
>
> diff --git a/libc/sysdeps/linux/i386/crt1.S 
> b/libc/sysdeps/linux/i386/crt1.S
> index 35a6552e8..decc68967 100644
> --- a/libc/sysdeps/linux/i386/crt1.S
> +++ b/libc/sysdeps/linux/i386/crt1.S
> @@ -67,6 +67,9 @@
>  #endif
>  .type   main,%function
>  .type   __uClibc_main,%function
> +#ifdef L_rcrt1
> +.type reloc_static_pie,%function
> +#endif
>  _start:
>   /* Clear the frame pointer.  The ABI suggests this be done, to mark
>     the outermost frame obviously.  */
> @@ -100,6 +103,23 @@ _start:
>   pop %ebx
>   addl $_GLOBAL_OFFSET_TABLE_+[.-.L0],%ebx
>
> +#ifdef L_rcrt1
> + /* We cannot rely on _DYNAMIC being usable here due to RELRO.
> +   Instead we calculate the load address based off a symbol
> +   that we know will exist, _start. */
> + pushl %ecx                      /* Save ecx so it won't get clobbered */
> + pushl %ebx                      /* Save ebx so it won't get clobbered */
> + xorl %ecx, %ecx                 /* Clear ecx */
> + addl _start@GOT(%ebx), %ecx     /* Get the offset of _start */
> + movl _start@GOT(%ebx), %eax     /* Get the run time address of _start */
> + subl %ecx, %eax                 /* Subtract to find the load address */
> + pushl %eax                      /* Pass the load address */
> + call reloc_static_pie@PLT
> + popl %eax                       /* Clean up from function call */
> + popl %ebx                       /* Restore the GOT address */
> + popl %ecx                       /* restore ecx */
> +#endif
> +
>   /* Push address of our own entry points to .fini and .init.  */
>   pushl _fini@GOT(%ebx)
>   pushl _init@GOT(%ebx)
> diff --git a/libc/sysdeps/linux/x86_64/crt1.S 
> b/libc/sysdeps/linux/x86_64/crt1.S
> index 87777dd5d..701cbf2f6 100644
> --- a/libc/sysdeps/linux/x86_64/crt1.S
> +++ b/libc/sysdeps/linux/x86_64/crt1.S
> @@ -80,6 +80,20 @@ _start:
>     the outermost frame obviously.  */
>   xorl %ebp, %ebp
>
> +#ifdef L_rcrt1
> + pushq %rdi                          /* save rdi (but should be 0...) */
> + pushq %rdx                          /* store rdx (rtld_fini) */
> + xorq %rcx, %rcx                     /* ensure rcx is 0 */
> + addq _start@GOTPCREL(%rip), %rcx    /* get offset of _start from 
> beginning of file */
> + movq _start@GOTPCREL(%rip), %rax    /* get run time address of _start */
> + subq %rcx, %rax                     /* calculate run time load offset */
> + movq %rax, %rdi                     /* load offset -> param 1 */
> + call reloc_static_pie               /* relocate dynamic addrs */
> + xorq %rax, %rax                     /* cleanup */
> + popq %rdx
> + popq %rdi
> +#endif
> +
>   /* Extract the arguments as encoded on the stack and set up
>     the arguments for __libc_start_main (int (*main) (int, char **, 
> char **),
>     int argc, char *argv,
> @@ -107,7 +121,7 @@ _start:
>     which grow downwards).  */
>   pushq %rsp
>
> -#if defined(L_Scrt1)
> +#if defined(L_Scrt1) || defined(L_rcrt1)
>   /* Give address for main() */
>   movq main@GOTPCREL(%rip), %rdi
>
> -- 
> 2.34.1
>
>
>
> _______________________________________________
> devel mailing list --devel@uclibc-ng.org
> To unsubscribe send an email todevel-leave@uclibc-ng.org
Lance Fredrickson July 18, 2022, 9:30 p.m. UTC | #3
With some hackery I got a hello world program compiled as static-pie, 
but maybe needs gcc patching.  I think it's not passing the right things 
to the linker.

Lance
Lance Fredrickson July 19, 2022, 5:38 p.m. UTC | #4
-static-pie on arm is working well for me.  As it turns out GCC doesn't 
currently handle -static-pie with arm, and is not passing the correct 
options to the linker.  This patch applies onto GCC 12.1 which fixes 
that, and I will try to upstream.

https://github.com/lancethepants/gcc/commit/043704d5f827af775cf796b9ec144b72fc8d524f

One thing that threw me for a while is that the 'file' command in Debian 
10 is apparently too old to know what static-pie is, and reports it as 
dynamically linked but without a reference to to the dynamic linker.

Nice patch! I'm glad to see this feature come to uclibc-ng. I saw you 
had a arm64 branch in your repo so would be cool to see that too.

thanks,
Lance
linted July 19, 2022, 11:27 p.m. UTC | #5
I'm glad you were able to figure it out. I'm planning on submitting patches
for as many architectures as I can. Since you needed to submit patches for
gcc on arm, I have a feeling the other architectures might need similar
patches in gcc.

On Tue, Jul 19, 2022 at 1:38 PM Lance Fredrickson <lancethepants@gmail.com>
wrote:

> -static-pie on arm is working well for me.  As it turns out GCC doesn't
> currently handle -static-pie with arm, and is not passing the correct
> options to the linker.  This patch applies onto GCC 12.1 which fixes
> that, and I will try to upstream.
>
>
> https://github.com/lancethepants/gcc/commit/043704d5f827af775cf796b9ec144b72fc8d524f
>
> One thing that threw me for a while is that the 'file' command in Debian
> 10 is apparently too old to know what static-pie is, and reports it as
> dynamically linked but without a reference to to the dynamic linker.
>
> Nice patch! I'm glad to see this feature come to uclibc-ng. I saw you
> had a arm64 branch in your repo so would be cool to see that too.
>
> thanks,
> Lance
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
Yann Sionneau July 20, 2022, 7:35 a.m. UTC | #6
I can confirm that with both patches applied (Lance's patch on GCC and 
linted's patch on uClibc-ng) I can build a working hello world for ARM 
with -fpie --static-pie.

Btw your GCC patch also applies well to GCC 10.3.0. (Tested with Buildroot)

Tested-by: Yann Sionneau <yann@sionneau.net>

Yann

On 19/07/2022 19:38, Lance Fredrickson wrote:
> -static-pie on arm is working well for me.  As it turns out GCC 
> doesn't currently handle -static-pie with arm, and is not passing the 
> correct options to the linker.  This patch applies onto GCC 12.1 which 
> fixes that, and I will try to upstream.
>
> https://github.com/lancethepants/gcc/commit/043704d5f827af775cf796b9ec144b72fc8d524f 
>
>
> One thing that threw me for a while is that the 'file' command in 
> Debian 10 is apparently too old to know what static-pie is, and 
> reports it as dynamically linked but without a reference to to the 
> dynamic linker.
>
> Nice patch! I'm glad to see this feature come to uclibc-ng. I saw you 
> had a arm64 branch in your repo so would be cool to see that too.
>
> thanks,
> Lance
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
>
> To declare a filtering error, please use the following link : 
> https://www.security-mail.net/reporter.php?mid=140bd.62d6ec2c.e850f.0&r=ysionneau%40kalray.eu&s=devel-bounces%40uclibc-ng.org&o=%5Buclibc-ng-devel%5D+Re%3A+%5BPatch+v3%5D+Static+PIE+support+for+i386%2C+x86_64%2C+and+arm&verdict=C&c=72a852ff65a09cfdea1522d68402bf734ba4b342
>
Lance Fredrickson July 20, 2022, 1:10 p.m. UTC | #7
So trying to compile more complex programs than a hello_world, I'm 
seeing segmentation faults on arm, haven't tried other arches. Here's 
the backtrace all the failing programs produce. I'll have to try getting 
a better backtrace.

(gdb) backtrace
#0  0x2a023248 in _memcpy ()
#1  0x2a0167d8 in __libc_setup_tls ()
#2  0x2a015f64 in __uClibc_init ()
#3  0x2a016194 in __uClibc_main ()
#4  0xbeb50684 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

On 7/20/2022 1:35 AM, Yann Sionneau wrote:
> I can confirm that with both patches applied (Lance's patch on GCC and 
> linted's patch on uClibc-ng) I can build a working hello world for ARM 
> with -fpie --static-pie.
>
> Btw your GCC patch also applies well to GCC 10.3.0. (Tested with 
> Buildroot)
>
> Tested-by: Yann Sionneau <yann@sionneau.net>
>
> Yann
>
> On 19/07/2022 19:38, Lance Fredrickson wrote:
>> -static-pie on arm is working well for me.  As it turns out GCC 
>> doesn't currently handle -static-pie with arm, and is not passing the 
>> correct options to the linker. This patch applies onto GCC 12.1 which 
>> fixes that, and I will try to upstream.
>>
>> https://github.com/lancethepants/gcc/commit/043704d5f827af775cf796b9ec144b72fc8d524f 
>>
>>
>> One thing that threw me for a while is that the 'file' command in 
>> Debian 10 is apparently too old to know what static-pie is, and 
>> reports it as dynamically linked but without a reference to to the 
>> dynamic linker.
>>
>> Nice patch! I'm glad to see this feature come to uclibc-ng. I saw you 
>> had a arm64 branch in your repo so would be cool to see that too.
>>
>> thanks,
>> Lance
>> _______________________________________________
>> devel mailing list -- devel@uclibc-ng.org
>> To unsubscribe send an email to devel-leave@uclibc-ng.org
>>
>>
>> To declare a filtering error, please use the following link : 
>> https://www.security-mail.net/reporter.php?mid=140bd.62d6ec2c.e850f.0&r=ysionneau%40kalray.eu&s=devel-bounces%40uclibc-ng.org&o=%5Buclibc-ng-devel%5D+Re%3A+%5BPatch+v3%5D+Static+PIE+support+for+i386%2C+x86_64%2C+and+arm&verdict=C&c=72a852ff65a09cfdea1522d68402bf734ba4b342
>>
>
>
>
>
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
Lance Fredrickson July 20, 2022, 1:41 p.m. UTC | #8
Here is a more detailed backtrace.

Program received signal SIGSEGV, Segmentation fault.
_memcpy () at libc/string/arm/_memcpy.S:445
445     libc/string/arm/_memcpy.S: No such file or directory.
(gdb) backtrace
#0  _memcpy () at libc/string/arm/_memcpy.S:445
#1  0x2a027ce4 in __libc_setup_tls (tcbsize=8, tcbalign=16) at 
./libpthread/nptl/sysdeps/generic/libc-tls.c:212
#2  0x2a026ac0 in __uClibc_init () at 
libc/misc/internals/__uClibc_main.c:284
#3  0x2a026e74 in __uClibc_main (main=0x2a002c68 <main>, argc=1, 
argv=0xbef29684, app_init=0x2a0006d0 <_init>, app_fini=0x2a053694 
<_fini>, rtld_fini=0x0, stack_end=0xbef29684) at 
libc/misc/internals/__uClibc_main.c:423
#4  0x2a0280a4 in reloc_static_pie (load_addr=<error reading variable: 
Cannot access memory at address 0xffffff30>) at 
libc/misc/internals/reloc_static_pie.c:29
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
linted July 22, 2022, 3:50 p.m. UTC | #9
I did some digging and it looks like lr is getting modified when calling
reloc_static_pie. I'm going to submit a new patch which makes sure any
applicable registers are appropriately cleaned up after returning from
reloc_static_pie.

On Wed, Jul 20, 2022 at 9:41 AM Lance Fredrickson <lancethepants@gmail.com>
wrote:

> Here is a more detailed backtrace.
>
> Program received signal SIGSEGV, Segmentation fault.
> _memcpy () at libc/string/arm/_memcpy.S:445
> 445     libc/string/arm/_memcpy.S: No such file or directory.
> (gdb) backtrace
> #0  _memcpy () at libc/string/arm/_memcpy.S:445
> #1  0x2a027ce4 in __libc_setup_tls (tcbsize=8, tcbalign=16) at
> ./libpthread/nptl/sysdeps/generic/libc-tls.c:212
> #2  0x2a026ac0 in __uClibc_init () at
> libc/misc/internals/__uClibc_main.c:284
> #3  0x2a026e74 in __uClibc_main (main=0x2a002c68 <main>, argc=1,
> argv=0xbef29684, app_init=0x2a0006d0 <_init>, app_fini=0x2a053694
> <_fini>, rtld_fini=0x0, stack_end=0xbef29684) at
> libc/misc/internals/__uClibc_main.c:423
> #4  0x2a0280a4 in reloc_static_pie (load_addr=<error reading variable:
> Cannot access memory at address 0xffffff30>) at
> libc/misc/internals/reloc_static_pie.c:29
> Backtrace stopped: previous frame inner to this frame (corrupt stack?)
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
linted July 22, 2022, 9:14 p.m. UTC | #10
I was actually completely incorrect as to the root cause. My initial
assumption that the TLS virtual address was being updated correctly when
the .rel.dyn was being updated by elf_machine_relative was flawed. The way
that I updated that value is only valid when used with an ldso. This is
because __libc_setup_tls pulls the virtual address of the TLS out of the
auxvals, which i'm not currently updating. I'm trying to figure out if
there is a way to either have __libc_setup_tls check to see if there is a
TLS entry in the dynamic relocations or make an efficient method of
updating the auxval entry prior to __uClibc_main.

On Fri, Jul 22, 2022 at 11:50 AM linted <linted90@gmail.com> wrote:

> I did some digging and it looks like lr is getting modified when calling
> reloc_static_pie. I'm going to submit a new patch which makes sure any
> applicable registers are appropriately cleaned up after returning from
> reloc_static_pie.
>
> On Wed, Jul 20, 2022 at 9:41 AM Lance Fredrickson <lancethepants@gmail.com>
> wrote:
>
>> Here is a more detailed backtrace.
>>
>> Program received signal SIGSEGV, Segmentation fault.
>> _memcpy () at libc/string/arm/_memcpy.S:445
>> 445     libc/string/arm/_memcpy.S: No such file or directory.
>> (gdb) backtrace
>> #0  _memcpy () at libc/string/arm/_memcpy.S:445
>> #1  0x2a027ce4 in __libc_setup_tls (tcbsize=8, tcbalign=16) at
>> ./libpthread/nptl/sysdeps/generic/libc-tls.c:212
>> #2  0x2a026ac0 in __uClibc_init () at
>> libc/misc/internals/__uClibc_main.c:284
>> #3  0x2a026e74 in __uClibc_main (main=0x2a002c68 <main>, argc=1,
>> argv=0xbef29684, app_init=0x2a0006d0 <_init>, app_fini=0x2a053694
>> <_fini>, rtld_fini=0x0, stack_end=0xbef29684) at
>> libc/misc/internals/__uClibc_main.c:423
>> #4  0x2a0280a4 in reloc_static_pie (load_addr=<error reading variable:
>> Cannot access memory at address 0xffffff30>) at
>> libc/misc/internals/reloc_static_pie.c:29
>> Backtrace stopped: previous frame inner to this frame (corrupt stack?)
>> _______________________________________________
>> devel mailing list -- devel@uclibc-ng.org
>> To unsubscribe send an email to devel-leave@uclibc-ng.org
>>
>
diff mbox series

Patch

From 92056b7db87be00e6daea59a4f82d022bfc7f223 Mon Sep 17 00:00:00 2001
From: linted <linted@users.noreply.github.com>
Date: Sun, 17 Jul 2022 13:38:49 -0400
Subject: [PATCH] Added support for creation of Static Position-Independent
 Executables (PIE) on i386, x86_64, and arm.

This patch adds the generation of rcrt1.o which is used by gcc when compiling with the --static-pie flag.

rcrt1.o differs from crt1.o and Scrt1.o in that it the executable has a dynamic section but no relocations have been performed prior to _start being called.
crt1.o assumes there to be no dynamic relocations, and Scrt1.o has all relocations performed prior to execution by lsdo.

The new reloc_static_pie function handles parsing the elf headers, locating the dynamic section, and performing the relocations in a architecture agnostic method.
This allows for easier porting of static-pie support to additional architectures.

Signed-off-by: linted <linted@users.noreply.github.com>
---
 Makerules                              |  5 ++++
 extra/Configs/Config.in                |  5 ++++
 libc/misc/internals/Makefile.in        |  1 +
 libc/misc/internals/reloc_static_pie.c | 41 ++++++++++++++++++++++++++
 libc/sysdeps/linux/arm/crt1.S          | 15 ++++++++++
 libc/sysdeps/linux/i386/crt1.S         | 20 +++++++++++++
 libc/sysdeps/linux/x86_64/crt1.S       | 16 +++++++++-
 7 files changed, 102 insertions(+), 1 deletion(-)
 create mode 100644 libc/misc/internals/reloc_static_pie.c

diff --git a/Makerules b/Makerules
index fd40e6c7b..845d81897 100644
--- a/Makerules
+++ b/Makerules
@@ -405,8 +405,13 @@  else
 CRTS=$(top_builddir)lib/$(CRT).o
 endif
 
+ifeq ($(STATIC_PIE),y)
+CRTS+=$(top_builddir)lib/r$(CRT).o
+endif
+
 ASFLAGS-$(CRT).o := -DL_$(CRT)
 ASFLAGS-S$(CRT).o := $(PIEFLAG) -DL_S$(CRT)
+ASFLAGS-r$(CRT).o := $(PIEFLAG) -DL_r$(CRT)
 $(CRTS): $(top_srcdir)libc/sysdeps/linux/$(TARGET_ARCH)/$(CRT).S
 	$(compile.S)
 	$(Q)$(STRIPTOOL) -x -R .note -R .comment $@
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index a58ceb265..a49278b30 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -301,6 +301,11 @@  config DOPIC
 	  If you wish to build all of uClibc as PIC objects, then answer Y here.
 	  If you are unsure, then you should answer N.
 
+config STATIC_PIE
+	bool "Add support for Static Position Independent Executables (PIE)"
+	default n
+	depends on DOPIC && !UCLIBC_FORMAT_FDPIC_ELF && (TARGET_arm || TARGET_i386 || TARGET_x86_64)
+
 config ARCH_HAS_NO_SHARED
 	bool
 
diff --git a/libc/misc/internals/Makefile.in b/libc/misc/internals/Makefile.in
index a8e4e36f9..4a6e73d2d 100644
--- a/libc/misc/internals/Makefile.in
+++ b/libc/misc/internals/Makefile.in
@@ -34,6 +34,7 @@  libc-static-$(UCLIBC_FORMAT_FLAT_SEP_DATA) += \
 libc-static-$(UCLIBC_FORMAT_SHARED_FLAT) += \
   $(MISC_INTERNALS_OUT)/shared_flat_initfini.o \
   $(MISC_INTERNALS_OUT)/shared_flat_add_library.o
+libc-static-$(STATIC_PIE) += $(MISC_INTERNALS_OUT)/reloc_static_pie.o
 libc-shared-$(UCLIBC_FORMAT_SHARED_FLAT) += \
   $(MISC_INTERNALS_OUT)/shared_flat_initfini.os \
   $(MISC_INTERNALS_OUT)/shared_flat_add_library.os
diff --git a/libc/misc/internals/reloc_static_pie.c b/libc/misc/internals/reloc_static_pie.c
new file mode 100644
index 000000000..9a8066b84
--- /dev/null
+++ b/libc/misc/internals/reloc_static_pie.c
@@ -0,0 +1,41 @@ 
+/* Support for relocating static PIE.
+   Copyright (C) 2017-2022 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <link.h>
+#include <elf.h>
+#include <dl-elf.h>
+
+void
+reloc_static_pie (ElfW(Addr) load_addr)
+{
+    ElfW(Word) relative_count = 0;
+    ElfW(Addr) rel_addr = NULL;
+    ElfW(Dyn) * dyn_addr = NULL;
+    unsigned long dynamic_info[DYNAMIC_SIZE] = {0};   
+
+    /* Read our own dynamic section and fill in the info array.  */
+    dyn_addr = ((void *) load_addr + elf_machine_dynamic ());
+
+    /* Use the underlying function to avoid TLS access before initialization */
+    __dl_parse_dynamic_info(dyn_addr, dynamic_info, NULL, load_addr);
+
+    /* Perform relocations */
+    relative_count = dynamic_info[DT_RELCONT_IDX];
+    rel_addr = dynamic_info[DT_RELOC_TABLE_ADDR];
+    elf_machine_relative(load_addr, rel_addr, relative_count);
+}
diff --git a/libc/sysdeps/linux/arm/crt1.S b/libc/sysdeps/linux/arm/crt1.S
index a1d7f0f23..2aa2a5234 100644
--- a/libc/sysdeps/linux/arm/crt1.S
+++ b/libc/sysdeps/linux/arm/crt1.S
@@ -246,6 +246,18 @@  _start:
 	mov lr, #0
 
 #ifdef __ARCH_USE_MMU__
+#ifdef L_rcrt1
+	/* We don't need to save a1 since no dynamic linker should have run */
+	ldr a1, .L_GOT          /* Get value at .L_GOT + 0  (offset to GOT)*/
+	adr a2, .L_GOT          /* Get address of .L_GOT */
+	ldr a3, .L_GOT+16       /* get value of _start(GOT) stored in .L_GOT */
+	adr a4, _start          /* get address of _start after relocation (changes to pc - ~30 or so) */
+	add a1, a1, a2          /* calculate where the GOT is */
+	ldr a2, [a1, a3]        /* GOT + _start(GOT) = offset of _start from begin of file */
+	sub a1, a4, a2          /* current addr of _start - offset from beginning of file = load addr */
+	bl reloc_static_pie
+	mov a1, #0              /* Clean up a1 so that a random address won't get called at the end of program */
+#endif
 	/* Pop argc off the stack and save a pointer to argv */
 	ldr a2, [sp], #4
 	mov a3, sp
@@ -309,6 +321,9 @@  _start:
 	.word _fini(GOT)
 	.word _init(GOT)
 	.word main(GOT)
+#ifdef L_rcrt1
+	.word _start(GOT)
+#endif
 #endif
 #endif
 
diff --git a/libc/sysdeps/linux/i386/crt1.S b/libc/sysdeps/linux/i386/crt1.S
index 35a6552e8..decc68967 100644
--- a/libc/sysdeps/linux/i386/crt1.S
+++ b/libc/sysdeps/linux/i386/crt1.S
@@ -67,6 +67,9 @@ 
 #endif
 .type   main,%function
 .type   __uClibc_main,%function
+#ifdef L_rcrt1
+.type	reloc_static_pie,%function
+#endif
 _start:
 	/* Clear the frame pointer.  The ABI suggests this be done, to mark
 	   the outermost frame obviously.  */
@@ -100,6 +103,23 @@  _start:
 	pop %ebx
 	addl $_GLOBAL_OFFSET_TABLE_+[.-.L0],%ebx
 
+#ifdef L_rcrt1
+	/* We cannot rely on _DYNAMIC being usable here due to RELRO.
+	   Instead we calculate the load address based off a symbol
+	   that we know will exist, _start. */
+	pushl %ecx                      /* Save ecx so it won't get clobbered */
+	pushl %ebx                      /* Save ebx so it won't get clobbered */
+	xorl %ecx, %ecx                 /* Clear ecx */
+	addl _start@GOT(%ebx), %ecx     /* Get the offset of _start */
+	movl _start@GOT(%ebx), %eax     /* Get the run time address of _start */
+	subl %ecx, %eax                 /* Subtract to find the load address */
+	pushl %eax                      /* Pass the load address */
+	call reloc_static_pie@PLT
+	popl %eax                       /* Clean up from function call */
+	popl %ebx                       /* Restore the GOT address */
+	popl %ecx                       /* restore ecx */
+#endif
+
 	/* Push address of our own entry points to .fini and .init.  */
 	pushl _fini@GOT(%ebx)
 	pushl _init@GOT(%ebx)
diff --git a/libc/sysdeps/linux/x86_64/crt1.S b/libc/sysdeps/linux/x86_64/crt1.S
index 87777dd5d..701cbf2f6 100644
--- a/libc/sysdeps/linux/x86_64/crt1.S
+++ b/libc/sysdeps/linux/x86_64/crt1.S
@@ -80,6 +80,20 @@  _start:
 	   the outermost frame obviously.  */
 	xorl %ebp, %ebp
 
+#ifdef L_rcrt1
+	pushq %rdi                          /* save rdi (but should be 0...) */
+	pushq %rdx                          /* store rdx (rtld_fini) */
+	xorq %rcx, %rcx                     /* ensure rcx is 0 */
+	addq _start@GOTPCREL(%rip), %rcx    /* get offset of _start from beginning of file */
+	movq _start@GOTPCREL(%rip), %rax    /* get run time address of _start */
+	subq %rcx, %rax                     /* calculate run time load offset */
+	movq %rax, %rdi                     /* load offset -> param 1 */
+	call reloc_static_pie               /* relocate dynamic addrs */
+	xorq %rax, %rax                     /* cleanup */
+	popq %rdx
+	popq %rdi
+#endif
+
 	/* Extract the arguments as encoded on the stack and set up
 	   the arguments for __libc_start_main (int (*main) (int, char **, char **),
 		   int argc, char *argv,
@@ -107,7 +121,7 @@  _start:
 	   which grow downwards).  */
 	pushq %rsp
 
-#if defined(L_Scrt1)
+#if defined(L_Scrt1) || defined(L_rcrt1)
 	/* Give address for main() */
 	movq main@GOTPCREL(%rip), %rdi
 
-- 
2.34.1