summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Ungerer <gerg@kernel.org>2023-11-28 23:29:43 +1000
committerWaldemar Brodkorb <wbx@openadk.org>2023-12-12 05:51:34 +0100
commit74d5b684253ce61404c1b72f2726599f00eb0a14 (patch)
tree6aab797e63c89b3c9575c2df35440499a35f5b00
parent75a5fc9e5033f47e955406e300a070004c14b8ae (diff)
elf: support ELF binaries in noMMU
The Linux kernels ELF-FDPIC binfmt program loader can support loading and running conventional ELF format binaries on noMMU kernels when compiled appropriately. That is when they are constant displacement binaries such as generated using the -pie compile option. Add a configure option to allow selecting ELF binary support in noMMU mode configurations on architectures that support this. The main requirement is to generate the ldso run-time loader to perform relocation at load time. These configurations do not support shared libraries, so there is no need to generate a full shared library, only the static version is required. The use of ELF format binaries does mean a slightly simpler toolchain generation (does not require a -uclinux- for some architectures) and does not require an extra tool like elf2flt. This initial support targets M68K, ARM and RISC-V architectures. No kernel changes are required, the required support for this is already in mainline kernels (certainly as of linux-6.6). Note that for the M68K and ARM architectures that the initialized registers and stack layout at process startup is slightly different for the flat format loader and the ELF/ELF-FDPIC loaders. So we need some changes to the startup code (crt1.S) for them. I have not done extensive testing outside of M68K, ARM and RISC-V. I had to make changes to a couple of the dl-startup.h architecture files to get them to build for this noMMU case. I did not dig down too deep on the reasons, but they still seem ok for the MMU case as well. Signed-off-by: Greg Ungerer <gerg@linux-m68k.org>
-rw-r--r--Makerules3
-rw-r--r--Rules.mak2
-rw-r--r--extra/Configs/Config.in9
-rw-r--r--extra/Configs/Config.in.arch8
-rw-r--r--ldso/include/dl-defs.h2
-rwxr-xr-xldso/include/ldso.h2
-rw-r--r--ldso/ldso/arm/dl-startup.h2
-rw-r--r--ldso/ldso/m68k/dl-startup.h3
-rw-r--r--ldso/ldso/m68k/dl-sysdep.h2
-rw-r--r--ldso/ldso/riscv64/dl-startup.h2
-rw-r--r--libc/sysdeps/linux/arm/crt1.S2
-rw-r--r--libc/sysdeps/linux/m68k/crt1.S10
12 files changed, 39 insertions, 8 deletions
diff --git a/Makerules b/Makerules
index 845d81897..1a7443c39 100644
--- a/Makerules
+++ b/Makerules
@@ -22,6 +22,9 @@ ifeq ($(UCLIBC_FORMAT_SHARED_FLAT),y)
libs: $(lib-gdb-y)
endif
libs: $(lib-a-y)
+ifeq ($(HAVE_LDSO),y)
+$(lib-a-y): | $(ldso)
+endif
endif
objs: all_objs
$(lib-so-y) $(lib-a-y): | $(top_builddir)lib
diff --git a/Rules.mak b/Rules.mak
index 5b9154b72..2aacee521 100644
--- a/Rules.mak
+++ b/Rules.mak
@@ -167,6 +167,8 @@ endif
ifneq ($(HAVE_SHARED),y)
libc :=
+endif
+ifneq ($(HAVE_LDSO),y)
interp :=
ldso :=
endif
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index 287db13d2..18748d54b 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -333,8 +333,9 @@ 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 || TARGET_aarch64 || \
- TARGET_mips || TARGET_xtensa || TARGET_powerpc)
+ (TARGET_aarch64 || TARGET_arm || TARGET_i386 || \
+ TARGET_m68k || TARGET_mips || TARGET_powerpc || \
+ TARGET_riscv64 || TARGET_x86_64 || TARGET_xtensa)
config ARCH_HAS_NO_SHARED
bool
@@ -346,9 +347,13 @@ config ARCH_HAS_NO_LDSO
config ARCH_HAS_UCONTEXT
bool
+config HAVE_LDSO
+ bool
+
config HAVE_SHARED
bool "Enable shared libraries"
depends on !ARCH_HAS_NO_SHARED
+ select HAVE_LDSO
default y
help
If you wish to build uClibc with support for shared libraries then
diff --git a/extra/Configs/Config.in.arch b/extra/Configs/Config.in.arch
index 91b639493..4bcf3ff3f 100644
--- a/extra/Configs/Config.in.arch
+++ b/extra/Configs/Config.in.arch
@@ -10,6 +10,14 @@
if !ARCH_USE_MMU
choice
prompt "Target File Format"
+config UCLIBC_FORMAT_ELF
+ bool "ELF (using ELF_FDPIC loader)"
+ depends on !ARCH_USE_MMU && (TARGET_arm || TARGET_m68k || \
+ TARGET_riscv64)
+ select DOPIC
+ select STATIC_PIE
+ select ARCH_HAS_NO_SHARED
+ select HAVE_LDSO
config UCLIBC_FORMAT_FDPIC_ELF
bool "FDPIC ELF"
depends on !ARCH_USE_MMU && (TARGET_bfin || TARGET_frv || TARGET_arm)
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index daa6685cb..839239f4c 100644
--- a/ldso/include/dl-defs.h
+++ b/ldso/include/dl-defs.h
@@ -72,7 +72,7 @@ typedef struct {
#endif
#ifdef _LIBC
-#ifndef __ARCH_HAS_NO_SHARED__
+#ifndef __ARCH_HAS_NO_LDSO__
/* arch specific defines */
#include <dl-sysdep.h>
#endif
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 8d9d057a0..80d5d5dd5 100755
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -48,7 +48,7 @@
/* Pull in the MIN macro */
#include <sys/param.h>
/* Pull in the ldso syscalls and string functions */
-#ifndef __ARCH_HAS_NO_SHARED__
+#if !defined(__ARCH_HAS_NO_SHARED__) || !defined(__ARCH_HAS_NO_LDSO__)
#include <dl-syscall.h>
#include <dl-string.h>
/* Now the ldso specific headers */
diff --git a/ldso/ldso/arm/dl-startup.h b/ldso/ldso/arm/dl-startup.h
index cacd461e1..d00e7b053 100644
--- a/ldso/ldso/arm/dl-startup.h
+++ b/ldso/ldso/arm/dl-startup.h
@@ -301,3 +301,5 @@ int raise(int sig)
_dl_exit(1);
}
#endif /* __FDPIC__ */
+
+#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR)
diff --git a/ldso/ldso/m68k/dl-startup.h b/ldso/ldso/m68k/dl-startup.h
index dfece443f..9c3285e27 100644
--- a/ldso/ldso/m68k/dl-startup.h
+++ b/ldso/ldso/m68k/dl-startup.h
@@ -55,6 +55,9 @@ _dl_start_user:\n\
* do something a little more subtle here. */
#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *) ARGS) + 1)
+/* We can't call functions earlier in the dl startup process */
+#define NO_FUNCS_BEFORE_BOOTSTRAP
+
/* Handle relocation of the symbols in the dynamic loader. */
static __always_inline
void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
diff --git a/ldso/ldso/m68k/dl-sysdep.h b/ldso/ldso/m68k/dl-sysdep.h
index 21937b259..5d2d7a097 100644
--- a/ldso/ldso/m68k/dl-sysdep.h
+++ b/ldso/ldso/m68k/dl-sysdep.h
@@ -83,3 +83,5 @@ elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
*reloc_addr = load_off + rpnt->r_addend;
} while (--relative_count);
}
+
+#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR)
diff --git a/ldso/ldso/riscv64/dl-startup.h b/ldso/ldso/riscv64/dl-startup.h
index dabe1bebd..82e525e66 100644
--- a/ldso/ldso/riscv64/dl-startup.h
+++ b/ldso/ldso/riscv64/dl-startup.h
@@ -88,3 +88,5 @@ void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, ElfW(Addr) *reloc_addr,
_dl_exit(1);
}
}
+
+#define DL_UPDATE_LOADADDR_HDR(LOADADDR, ADDR, PHDR)
diff --git a/libc/sysdeps/linux/arm/crt1.S b/libc/sysdeps/linux/arm/crt1.S
index fade1d25c..799f11080 100644
--- a/libc/sysdeps/linux/arm/crt1.S
+++ b/libc/sysdeps/linux/arm/crt1.S
@@ -245,7 +245,7 @@ _start:
mov fp, #0
mov lr, #0
-#ifdef __ARCH_USE_MMU__
+#if defined(__ARCH_USE_MMU__) || defined(__UCLIBC_FORMAT_ELF__)
#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)*/
diff --git a/libc/sysdeps/linux/m68k/crt1.S b/libc/sysdeps/linux/m68k/crt1.S
index 815a6076f..e7292682b 100644
--- a/libc/sysdeps/linux/m68k/crt1.S
+++ b/libc/sysdeps/linux/m68k/crt1.S
@@ -78,9 +78,13 @@ _start:
sub.l %fp, %fp
#if !defined __ARCH_USE_MMU__ && defined __PIC__
+#ifdef UCLIBC_FORMAT_ELF
+ move.l #_GLOBAL_OFFSET_TABLE_, %a5
+#else
/* Set up the global pointer. The GOT is at the beginning of the
data segment, whose address is in %d5. */
move.l %d5,%a5
+#endif
.equ have_current_got, 1
#endif
@@ -92,11 +96,11 @@ _start:
arguments for `main': argc, argv. envp will be determined
later in __libc_start_main. */
move.l (%sp)+, %d0 /* Pop the argument count. */
-#ifndef __ARCH_USE_MMU__
- move.l (%sp)+, %a0
-#else
+#if defined(__ARCH_USE_MMU__) || defined(__UCLIBC_FORMAT_ELF__)
move.l %sp, %a0 /* The argument vector starts just at the
current stack top. */
+#else
+ move.l (%sp)+, %a0
#endif
/* Provide the highest stack address to the user code (for stacks