Hello,
While looking at some uClibc code, I stumbled across the following
snippet in Rules.mak:
UCLIBC_LDSO_NAME := ld-uClibc
ARCH_NATIVE_BIT := 32
ifneq ($(findstring $(TARGET_ARCH) , hppa64 ia64 powerpc64 s390x sparc64 x86_64 kvx ),)
UCLIBC_LDSO_NAME := ld64-uClibc
ARCH_NATIVE_BIT := 64
else
ifeq ($(CONFIG_MIPS_N64_ABI),y)
UCLIBC_LDSO_NAME := ld64-uClibc
ARCH_NATIVE_BIT := 64
endif
endif
I was surprised not to see aarch64 in the list of 64-bit architectures
here. Turns out that the situation is not that simple in fact. Indeed,
gcc does not expect all 64-bit architecture to have their dynamic
loader called ld64-uClibc. For aarch64 specifically, it indeed assumes
the dynamic loader is called ld-uClibc, which explains why it is
working today.
However, it means that ARCH_NATIVE_BIT is defined to 32 on aarch64,
which is obviously (?) wrong.
But turns out that ARCH_NATIVE_BIT is only used in utils/porting.h to
define __WORDSIZE and __WORDSIZE is only used in utils/ldd.c.
So to me, it seems like this would gain in being clarified. Something
like (completely untested):
diff --git a/Rules.mak b/Rules.mak
index 3fb64c728..a0b012d7f 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -142,17 +142,8 @@ export MAJOR_VERSION MINOR_VERSION SUBLEVEL VERSION ABI_VERSION LC_ALL
LIBC := libc
SHARED_LIBNAME := $(LIBC).so.$(ABI_VERSION)
-UCLIBC_LDSO_NAME := ld-uClibc
-ARCH_NATIVE_BIT := 32
-ifneq ($(findstring $(TARGET_ARCH) , hppa64 ia64 powerpc64 s390x sparc64 x86_64 kvx ),)
-UCLIBC_LDSO_NAME := ld64-uClibc
-ARCH_NATIVE_BIT := 64
-else
-ifeq ($(CONFIG_MIPS_N64_ABI),y)
-UCLIBC_LDSO_NAME := ld64-uClibc
-ARCH_NATIVE_BIT := 64
-endif
-endif
+UCLIBC_LDSO_NAME := $(call qstrip,$(TARGET_LDSO_NAME))
+ARCH_NATIVE_BIT := $(call qstrip,$(TARGET_ARCH_BITS))
UCLIBC_LDSO := $(UCLIBC_LDSO_NAME).so.$(ABI_VERSION)
NONSHARED_LIBNAME := uclibc_nonshared.a
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index a49278b30..e6369bd82 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -145,6 +145,26 @@ config TARGET_xtensa
endchoice
+config TARGET_LDSO_NAME
+ string
+ default "ld64-uClibc" if TARGET_ia64
+ default "ld64-uClibc" if TARGET_powerpc64
+ default "ld64-uClibc" if TARGET_sparc64
+ default "ld64-uClibc" if TARGET_x86_64
+ default "ld64-uClibc" if TARGET_kvx
+ default "ld64-uClibc" if CONFIG_MIPS_N64_ABI
+ default "ld-uClibc"
+
+config TARGET_ARCH_BITS
+ int
+ default 64 if TARGET_aarch64
+ default 64 if TARGET_ia64
+ default 64 if TARGET_powerpc64
+ default 64 if TARGET_sparc64
+ default 64 if TARGET_x86_64
+ default 64 if TARGET_kvx
+ default 64 if CONFIG_MIPS_N64_ABI
+ default 32
menu "Target Architecture Features and Options"
Best regards,
Thomas Petazzoni
--
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com
Hello,
Here is the next installment of static-pie support. This time it is for
aarch64 (arm64). It uses the same relocation methods as i386, x86_64, and
arm.
The only other major difference is the disabling of stack protectors in
reloc_static_pie.c since it can lead to access of dynamic memory prior to
relocation.
---
From b55075957b6a95e120095fb5d5dcc96bd500749e Mon Sep 17 00:00:00 2001
From: linted <linted(a)users.noreply.github.com>
Date: Sat, 16 Jul 2022 16:23:45 -0400
Subject: [PATCH] Added support for creation of Static Position-Independent
Executables (PIE) on aarch64
Updated config to allow compilation of rcrt1.o for aarch64 and modified
it's crt1.S to relocate dynamic section prior to __uClibc_main.
Disabled stack protector when compiling reloc_static_pie.c to avoid TLS
access prior to it being setup.
Signed-off-by: linted <linted(a)users.noreply.github.com>
---
extra/Configs/Config.in | 2 +-
libc/misc/internals/Makefile.in | 2 +-
libc/sysdeps/linux/aarch64/crt1.S | 14 ++++++++++++++
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index a49278b30..7d7d374c3 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -304,7 +304,7 @@ config DOPIC
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)
+ depends on DOPIC && !UCLIBC_FORMAT_FDPIC_ELF && (TARGET_arm ||
TARGET_i386 || TARGET_x86_64 || TARGET_aarch64)
config ARCH_HAS_NO_SHARED
bool
diff --git a/libc/misc/internals/Makefile.in
b/libc/misc/internals/Makefile.in
index 4a6e73d2d..69af8b76e 100644
--- a/libc/misc/internals/Makefile.in
+++ b/libc/misc/internals/Makefile.in
@@ -17,7 +17,7 @@ MISC_INTERNALS_SRC := $(patsubst
%.c,$(MISC_INTERNALS_DIR)/%.c,$(CSRC-y))
MISC_INTERNALS_OBJ := $(patsubst %.c,$(MISC_INTERNALS_OUT)/%.o,$(CSRC-y))
CFLAGS-__uClibc_main.c := $(SSP_DISABLE_FLAGS)
-
+CFLAGS-reloc_static_pie.c := $(SSP_DISABLE_FLAGS)
libc-y += $(MISC_INTERNALS_OBJ)
ifneq ($(UCLIBC_FORMAT_SHARED_FLAT),y)
diff --git a/libc/sysdeps/linux/aarch64/crt1.S
b/libc/sysdeps/linux/aarch64/crt1.S
index 09d0327ac..e9f946894 100644
--- a/libc/sysdeps/linux/aarch64/crt1.S
+++ b/libc/sysdeps/linux/aarch64/crt1.S
@@ -48,6 +48,20 @@ _start:
mov x29, #0
mov x30, #0
+#ifdef L_rcrt1
+ /* Save off the atexit pointer */
+ mov x19, x0
+
+ /* Calculate load address... idk how this works, but it does */
+ adrp x0, _start
+
+ /* Do relocations */
+ bl reloc_static_pie
+
+ /* restore atexit pointer */
+ mov x0, x19
+#endif
+
/* Setup _fini in argument register */
mov x5, x0
--
2.34.1
Hello,
I first want to apologize for so many patch versions.
This version of the patch correctly adjusts the offset of the TLS initimage
used by __libc_setup_tls when copying.
I would love feedback on my modifications to libc-tls.c as I had to use a
new global variable defined in reloc_static_pie.c containing the load
address. Originally I attempted to copy how glibc pulls the load address
from a memory map when initializing the TLS, however I could not find a
similar structure available in __libc_setup_tls. I would love to know if
there is a better method which I overlooked.
From 30b435a0b7a7f2d4323eafea2bcebb087cc62462 Mon Sep 17 00:00:00 2001
From: linted <linted(a)users.noreply.github.com>
Date: Sat, 23 Jul 2022 16:25:41 -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 dynamic section, and
performing the relocations in a architecture agnostic method.
It also sets _dl_load_base which is used when initalizing TLS to ensure
loading from the proper location.
This allows for easier porting of static-pie support to additional
architectures as only modifications to crt1.S to find the load address are
required.
Signed-off-by: linted <linted(a)users.noreply.github.com>
---
Makerules | 5 +++
extra/Configs/Config.in | 5 +++
libc/misc/internals/Makefile.in | 1 +
libc/misc/internals/reloc_static_pie.c | 47 +++++++++++++++++++++
libc/sysdeps/linux/arm/crt1.S | 19 +++++++++
libc/sysdeps/linux/i386/crt1.S | 20 +++++++++
libc/sysdeps/linux/x86_64/crt1.S | 16 ++++++-
libpthread/nptl/sysdeps/generic/Makefile.in | 4 ++
libpthread/nptl/sysdeps/generic/libc-tls.c | 4 ++
9 files changed, 120 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..578202d23
--- /dev/null
+++ b/libc/misc/internals/reloc_static_pie.c
@@ -0,0 +1,47 @@
+/* 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>
+
+ElfW(Addr) _dl_load_base = NULL;
+
+void
+reloc_static_pie (ElfW(Addr) load_addr);
+
+void
+reloc_static_pie (ElfW(Addr) load_addr)
+{
+ ElfW(Word) relative_count = 0;
+ ElfW(Addr) rel_addr = 0;
+ 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);
+ _dl_load_base = load_addr;
+}
diff --git a/libc/sysdeps/linux/arm/crt1.S b/libc/sysdeps/linux/arm/crt1.S
index a1d7f0f23..fade1d25c 100644
--- a/libc/sysdeps/linux/arm/crt1.S
+++ b/libc/sysdeps/linux/arm/crt1.S
@@ -246,6 +246,22 @@ _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 */
+
+ /* Clear the frame pointer and link register again since it might be
modified by previous call */
+ mov fp, #0
+ mov lr, #0
+#endif
/* Pop argc off the stack and save a pointer to argv */
ldr a2, [sp], #4
mov a3, sp
@@ -309,6 +325,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
diff --git a/libpthread/nptl/sysdeps/generic/Makefile.in
b/libpthread/nptl/sysdeps/generic/Makefile.in
index eb656ee17..a5ba9bbe8 100644
--- a/libpthread/nptl/sysdeps/generic/Makefile.in
+++ b/libpthread/nptl/sysdeps/generic/Makefile.in
@@ -13,6 +13,10 @@ subdirs += libpthread/nptl/sysdeps/generic
libpthread_generic_DIR := $(top_srcdir)libpthread/nptl/sysdeps/generic
libpthread_generic_OUT := $(top_builddir)libpthread/nptl/sysdeps/generic
+ifeq ($(STATIC_PIE),y)
+CFLAGS-libc-tls.c := -DSTATIC_PIE
+endif
+
libpthread_generic_libc_a_CSRC = libc-tls.c
libpthread_generic_libc_a_COBJ = $(patsubst
%.c,$(libpthread_generic_OUT)/%.o,$(libpthread_generic_libc_a_CSRC))
libpthread_generic_libc_a_OBJS = $(libpthread_generic_libc_a_COBJ)
diff --git a/libpthread/nptl/sysdeps/generic/libc-tls.c
b/libpthread/nptl/sysdeps/generic/libc-tls.c
index d746c9a38..0c8c558d0 100644
--- a/libpthread/nptl/sysdeps/generic/libc-tls.c
+++ b/libpthread/nptl/sysdeps/generic/libc-tls.c
@@ -142,6 +142,10 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
initimage = (void *) &__tdata_start;
#else
initimage = (void *) phdr->p_vaddr;
+#if !defined(SHARED) && defined(STATIC_PIE)
+ extern ElfW(Addr) _dl_load_base;
+ initimage += _dl_load_base;
+#endif
#endif
align = phdr->p_align;
if (phdr->p_align > max_align)
--
2.34.1
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(a)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(a)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
Hello,
Buildroot supports building ARM 32-bit systems for ARMv8 cores (even
though those would more classically run an AArch64 system).
Unfortunately, it seems like uClibc-ng doesn't support this situation,
as it exhibits the following build failure:
CC libpthread/linuxthreads/mutex.os
/tmp/ccn8SFKU.s: Assembler messages:
/tmp/ccn8SFKU.s:162: Error: swp{b} use is obsoleted for ARMv8 and later
/tmp/ccn8SFKU.s:186: Error: swp{b} use is obsoleted for ARMv8 and later
/tmp/ccn8SFKU.s:203: Error: swp{b} use is obsoleted for ARMv8 and later
/tmp/ccn8SFKU.s:224: Error: swp{b} use is obsoleted for ARMv8 and later
make[1]: *** [Makerules:369: libpthread/linuxthreads/mutex.os] Error 1
See
http://autobuild.buildroot.net/results/1e2e5e6c752901a818630d0c0816f43874bf…
for a more detailed log.
This is due to libpthread/linuxthreads/sysdeps/arm/pt-machine.h which
uses the swp instruction that is not allowed on ARMv8.
Best regards,
Thomas
--
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com
Hello,
This is an updated patch for static pie support on i386, x86_64, and arm. I
added dependency checks to ensure it only affects supported architectures.
I also added a check to ensure an MMU is present on arm since there is no
support for FDPIC yet.
Hello,
I implemented support for static pie generation 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. The main difference in rcrt1.o is
that it is required to perform dynamic relocations which would normally
occur in ldso. The new reloc_static_pie function handles parsing the elf
headers, locating the dynamic section, and performing the relocations.