Re: [Automated-testing] Call for nommu LTP maintainer [was: Re: [PATCH 00/36] Remove UCLINUX from LTP]

From: Greg Ungerer
Date: Thu Jan 11 2024 - 08:22:43 EST



On 11/1/24 23:11, Geert Uytterhoeven wrote:
Hi Rob,

On Wed, Jan 10, 2024 at 8:17 PM Rob Landley <rob@xxxxxxxxxxx> wrote:
You can't fork() on nommu because copies of the mappings have different
addresses, meaning any pointers in the copied mappings would point into the OLD
mappings (belonging to the parent process), and fixing them up is 100%
equivalent to the "garbage collection in C" problem. (It's AI-complete. Of the
C3PO kind, not the "autocorrect with syntax checking" kind.) People get hung up
on the "it would be very inefficient to do that because no copy-on-write"
problem and miss the "the child couldn't FUNCTION because its pointer variables
all contain parent addresses" problem.

Actually you can implement fork(), if you teach the compiler to use
separate stacks for return addresses and data:
- The first stack would contain only absolute addresses, to be
relocated after copying,
- The second stack would contain integers and relative pointers
(see FDPIC below), which do not need relocation after copying.

The OTHER fun thing about nommu is you can't run conventional ELF binaries,
because everything is linked at fixed address. So you might be able to run ONE
instance of the program as your init task, assuming those addresses were
available even then, but as soon as you try to run a second one it's a conflict.

The quick and dirty work around is to make PIE binaries, which can relocate
everything into available space, which works but doesn't scale. The problem with
ELF PIE is that everything is linked contiguously from a single base pointer,
meaning your text, rodata, data, and bss segments are all one linear blob. So if
you run two instances of bash, you've loaded two copies of the test and the
rodoata. This fills up your memory fast.

AND PIE requires contiguous memory, which nommu is bad at providing because it
has no page tables to remap stuff. With an mmu it can coalesce scattered
physical pages into a virtually contiguous range, but without an mmu you can
have plenty of memory free but in tiny chunks, none big enough to satisfy an
allocation request.

So they invented FDPIC, which is ELF with FOUR base pointers. Each major section
(rodata, text, data, and bss) has its own base pointer, so you need to find
smaller chunks of memory to load them into (and thus it can work on a more
fragmented system), AND it means that two instances of the same program can
share the read-only sections (rodata and text) so you only need new copies of
the writeable segments (data and bss. And the heap. And the stack.)

Or Amiga LoadSeg() relocatable binaries and shared libraries ;-)
As this supported splitting code, data, and bss in lots of smaller
hunks, it could counter fragmented memory quite well.

BTW, can't you run and thus test nommu-binaries under normal Linux, too?

Yes, you can. The flat format loader can be built for MMU arm and m68k Linux.
It will happily load and run flat format binaries on normal VM Linux.
I test that often on m68k (on ColdFire platforms).

Regards
Greg