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
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
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
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
-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/043704d5f827af775cf796b9ec144b72...
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
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/043704d5f827af775cf796b9ec144b72...
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
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/043704d5f827af775cf796b9ec144b72...
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=...
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/043704d5f827af775cf796b9ec144b72...
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=...
devel mailing list -- devel@uclibc-ng.org To unsubscribe send an email to devel-leave@uclibc-ng.org
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?)
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
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