[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <41f185e0-1721-4f3c-9979-785d4a1ca6db@linux-m68k.org>
Date: Fri, 16 Jan 2026 23:09:51 +1000
From: Greg Ungerer <gerg@...ux-m68k.org>
To: Daniel Palmer <daniel@...ngy.jp>, w@....eu, linux@...ssschuh.net,
dalias@...c.org
Cc: linux-m68k@...ts.linux-m68k.org, linux-kernel@...r.kernel.org
Subject: Re: [RFC PATCH] tools/nolibc: HACK!: Add basic self relocation for
static PIE for m68k nommu FDPIC
Hi Daniel,
On 16/1/26 22:28, Daniel Palmer wrote:
> This is some very quick hacky code to test if this works and get some ideas..
>
> - I'm messing with m68k nommu. Currently I use FLAT binaries and this is working with nolibc
> as-is mostly. Sometimes some relocations that elf2flat doesn't like get generated and the
> resulting FLAT binary doesn't have any relocation information and crashes which isn't good
> if you don't have an mmu.
>
> - Since commit 1bde925d2354 ("fs/binfmt_elf_fdpic.c: provide NOMMU loader for regular ELF binaries")
> the FDPIC loader has apparently been able to load non-FDPIC binaries as long as they are
> PIE and can be relocated. I have been messing with this thinking that maybe I can stop using
> FLAT binaries.
>
> - By default linking with -pie is trying to set ld.so as the interpreter to do the
> relocation. I don't think I have anything that can do that in my system. I am using uclibc but
> statically linked. Aside from my programs written with nolibc there is a busybox FLAT that is
> statically linked to uclibc and nothing else.
If you are using uClibc-ng as the C library and you select this config:
UCLIBC_FORMAT_ELF=y
instead of the UCLIBC_FORMAT_FLAT* options then it will generate the usual
libc.a static library, and also a run time linker ld-uClibc.so. That will do
the usual link/load at application run time.
Here is a script I use to test it all, generating for the mcf5208 nommu qemu target:
https://github.com/gregungerer/simple-linux/blob/master/build-m68knommu-linux-uclibc-elf.sh
> Eitherway, the plan is not to have any libc and have everything compiled with nolibc. I'm writing
> a small init, shell etc with nolibc that will replace busybox and not cause constant OOMs.
>
> - So, I can generate PIE binaries but they can't work because I have no linker to relocate them but
> apparently static PIE is a thing and with a normal toolchain you'd get a crt that does the relocation
> before jumping to main().
I messed around a few years back with a really basic stand alone link loader
that might be useful:
https://github.com/gregungerer/uldso
It probably doesn't work for all possible ELF files, but it worked good enough to load
and run busybox for example. And I only used uClibc-ng as the C library too. I never
tried with nolibc.
> - I thought it shouldn't be too hard to add something like that to crt.h in nolibc and then pass
> --no-dynamic-linker when linking to not set an interpreter.
Something like the uldso above avoids adding anything extra to the start up code,
since it runs as the interpreter. That feels like a better solution.
Regards
Greg
> - I got it working enough that a static pie "hello, world" loads and runs:
>
> / # /root/test.elf
> [ 9.970000] FDPIC ____ LOAD 23 ____
> [ 9.970000] FDPIC Mapped Object [executable]:
> [ 9.970000] FDPIC - elfhdr : 6d8000
> [ 9.970000] FDPIC - entry : 6d83e4
> [ 9.970000] FDPIC - PHDR[] : 6d8034
> [ 9.970000] FDPIC - DYNAMIC[]: 6da7b0
> [ 9.970000] FDPIC - LOAD[0] : 006d8000-006d87ad [va=0 ms=7ae]
> [ 9.970000] FDPIC - LOAD[1] : 006da7b0-006da873 [va=27b0 ms=c4]
> [ 9.970000] FDPIC - start_code 6d8000
> [ 9.970000] FDPIC - end_code 6d87ae
> [ 9.970000] FDPIC - start_data 6da7b0
> [ 9.970000] FDPIC - end_data 6da874
> [ 9.970000] FDPIC - start_brk 6e0000
> [ 9.970000] FDPIC - brk 6e0000
> [ 9.970000] FDPIC - start_stack 6fff00
> hello, world!
> [ 9.980000] test.elf (23) used greatest stack depth: 5348 bytes left
>
> Questions:
>
> - My use case is weird/niche but maybe there are uses for static pie nolibc binaries?
> - If so what would be a cleaner way of implementing this?
>
> - Right now the base address offset all of the relocations against is hardcoded.
> Maybe someone knows how I'm meant to get that properly?
>
> Signed-off-by: Daniel Palmer <daniel@...ngy.jp>
> ---
> tools/include/nolibc/crt.h | 56 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 56 insertions(+)
>
> diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h
> index d9262998dae9..0931915280d8 100644
> --- a/tools/include/nolibc/crt.h
> +++ b/tools/include/nolibc/crt.h
> @@ -10,6 +10,7 @@
> #ifndef NOLIBC_NO_RUNTIME
>
> #include "compiler.h"
> +#include "elf.h"
>
> char **environ __attribute__((weak));
> const unsigned long *_auxv __attribute__((weak));
> @@ -47,6 +48,61 @@ void _start_c(long *sp)
> /* initialize stack protector */
> __stack_chk_init();
>
> +#ifdef NOLIBC_STATIC_PIE
> +#define R_68K_RELATIVE 22
> +{
> + void *base = (void *) 0x6d8000; // TODO: how to actually get this?
> + unsigned int rela_count = 0;
> + unsigned int rela_off = 0;
> + unsigned long dyn_addr;
> + Elf32_Rela *rela;
> + Elf32_Addr *addr;
> + Elf32_Dyn *dyn;
> + int i;
> +
> + /* For m68k with the FDPIC loader d5 contains the offset to the DYNAMIC segment */
> + __asm__ volatile (
> + "move.l %%d5, %0\n"
> + : "=r" (dyn_addr)
> + );
> + dyn = (Elf32_Dyn *) dyn_addr;
> +
> + /* Go through the DYNAMIC segment and get the offset to rela and the number of relocations */
> + for (; dyn->d_tag != DT_NULL; dyn++) {
> + switch (dyn->d_tag) {
> + case DT_RELA:
> + rela_off = dyn->d_un.d_ptr;
> + break;
> + case DT_RELACOUNT:
> + rela_count = dyn->d_un.d_val;
> + break;
> + }
> + }
> +
> + if (!rela_off || !rela_count)
> + exit(42); //TODO nonsense error
> +
> + rela = base + rela_off;
> +
> + /* Do the relocations, only R_68K_RELATIVE for now */
> + for (i = 0; i < rela_count; i++) {
> + Elf32_Rela *entry = &rela[i];
> +
> + switch (ELF32_R_TYPE(entry->r_info)) {
> + case R_68K_RELATIVE:
> + {
> + addr = (Elf32_Addr *)(base + entry->r_offset);
> + *addr = (Elf32_Addr) (base + entry->r_addend);
> + }
> + break;
> + default:
> + exit(43); //TODO nonsense error
> + break;
> + }
> + }
> +}
> +#endif
> +
> /*
> * sp : argc <-- argument count, required by main()
> * argv: argv[0] <-- argument vector, required by main()
Powered by blists - more mailing lists