exec, mmap, musl: dynamic linking

A program that names an interpreter in PT_INTERP gets it loaded too, at
the bottom of the mmap area, and started instead -- with AT_PHDR,
AT_PHENT, AT_PHNUM, AT_BASE and AT_ENTRY to find the program by. ET_DYN
images are placed at a base: the interpreter there, a PIE program where
a fixed one would go. Static musl programs get AT_PHDR now as well,
which is how musl finds their TLS template.

mmap(MAP_FIXED) of a file handed back zeroed pages whatever the
descriptor said, and kept no record of them, so fork() did not copy
them. A dynamic linker maps every library segment after the first that
way. Fixed mappings now read the file and are recorded wherever no
mapping already covers them.

musl is built shared as well as static, and libc.so ships as
/lib/ld-musl-x86_64.so.1 -- libc and loader in one file. Every port
still links -static on purpose.

cmd/dynhello is the test: against libc.so and a library of its own,
checking TLS, the heap, and a fork whose child still has both.
mprotect is accepted and not enforced yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 10:59:52 +02:00
commit 43305768cb
6 changed files with 328 additions and 35 deletions

View file

@ -128,7 +128,7 @@ KERN_NOENTRY = $(filter-out $(BUILD)/kernel/arch/x86_64/entry.o, $(KERNOBJS))
# Third-party software does NOT go here — see ports/.
# -----------------------------------------------------------------------
ULIB = $(addprefix $(BUILD)/lib/, start.o glue.o usys.o)
CMDS = schinit schinitd fbinfo shmtest socktest inputtest nettest reflink schattr ping chvt loadkeys sigtest memfdtest pcitest vgpud schdbg schdbgd resolvconf httpd schmode netecho ldlsd tone hwreport
CMDS = schinit schinitd fbinfo shmtest socktest inputtest nettest reflink schattr ping chvt loadkeys sigtest memfdtest pcitest vgpud schdbg schdbgd resolvconf httpd schmode netecho ldlsd tone hwreport dynhello
CMDBINS = $(addprefix $(BUILD)/cmd/, $(CMDS))
# -----------------------------------------------------------------------
@ -1047,6 +1047,33 @@ $(BUILD)/cmd/ldlsd: cmd/ldlsd/main.c $(ULIB) $(LDLS_GUEST)
$(BUILD)/cmd/ldlsd.o $(LDLS_GUEST) $(ULIB)
$(OBJCOPY) -S $@
# dynhello is a musl program, and the only dynamically linked one: the test
# that the kernel loads an interpreter and the interpreter maps libraries.
# Not -static, against libc.so rather than libc.a, with musl's loader named as
# the interpreter, and with a shared library of its own beside it -- see
# cmd/dynhello/main.c.
DYNCC = $(PORTCC) -O2 -D__SCHOS__ -I$(MUSLPREFIX)/include -fno-stack-protector
DYNLD = -Wl,-dynamic-linker,/lib/ld-musl-x86_64.so.1 -Wl,-rpath,/lib
$(MUSLPREFIX)/lib/libc.so:
$(MAKE) -C ports musl CC=gcc
$(BUILD)/cmd/libdynhello.so: cmd/dynhello/lib.c $(MUSLPREFIX)/lib/libc.so
@mkdir -p $(BUILD)/cmd
$(DYNCC) -fPIC -c $< -o $(BUILD)/cmd/libdynhello.o
$(DYNCC) -shared -nostdlib -Wl,-soname,libdynhello.so -o $@ \
$(BUILD)/cmd/libdynhello.o -L$(MUSLPREFIX)/lib -lc
$(BUILD)/cmd/dynhello: cmd/dynhello/main.c $(BUILD)/cmd/libdynhello.so
$(DYNCC) -fno-pic -c $< -o $(BUILD)/cmd/dynhello.o
$(DYNCC) -no-pie -nostdlib $(DYNLD) -o $@ \
$(MUSLPREFIX)/lib/crt1.o $(MUSLPREFIX)/lib/crti.o $(BUILD)/cmd/dynhello.o \
-L$(BUILD)/cmd -ldynhello -L$(MUSLPREFIX)/lib -lc $(PORTEND)
$(SYSROOT)/lib/libdynhello.so: $(BUILD)/cmd/libdynhello.so
@mkdir -p $(SYSROOT)/lib
cp $< $@
$(BUILD)/cmd/%: cmd/%/main.c $(ULIB)
@mkdir -p $(BUILD)/cmd
$(CC) $(CFLAGS) -c $< -o $(BUILD)/cmd/$*.o
@ -1321,7 +1348,7 @@ SYSROOT_DIRS = dev proc sys run tmp root
# After lwIP is unpacked: `make -C ports` below unpacks it too, and the two
# unzips running at once under -j trip over each other.
sysroot-install: $(addprefix $(SYSROOT)/bin/, $(CMDS)) etc-install | $(LWIPDIR)
sysroot-install: $(addprefix $(SYSROOT)/bin/, $(CMDS)) $(SYSROOT)/lib/libdynhello.so etc-install | $(LWIPDIR)
@mkdir -p $(addprefix $(SYSROOT)/, $(SYSROOT_DIRS))
ifdef WINHOST
@echo "ports: skipped (Windows host) -- musl/mksh/toybox are used as already staged in $(SYSROOT)"