| git.druid.rocks | index | druid520 | kaboom | mk/ | bu.sh |
mk/bu.sh
#!/bin/sh
# builds every userspace program under src/user/ into a trimmed,
# ready-to-place-in-kfs elf binary at $out/user/<name> -- disk-image
# building is now a separate step, mk/bd.sh (`mk . bd`), so a fresh
# binary sitting in $out/user can be inspected/tested standalone before
# it's baked onto a disk image. every program links against user.ld
# (0x400000) -- now that each process gets its own real address space
# (vmm.nsc), there's no reason for sh to need a different address from
# anything it runs. src/user/lib.nsc, mem.nsc, string.nsc, ctype.nsc, malloc.nsc,
# stdio.nsc, and crt.s are shared support (the userspace libc), not
# programs of their own, and are compiled once below rather than in
# the program loop -- nsc has no #include-and-compile-together model,
# but nothing stops sharing compiled objects across multiple final
# links. lib.o is linked into every program unconditionally (always
# has been); the newer modules (mem/string/ctype/malloc/stdio) are
# opt-in PER PROGRAM based on which of their own ".nsh" headers a
# program actually includes -- linking all of them into everything
# unconditionally was tried first and measured to add ~19kb of dead
# code to every single binary, which pushed ed over disk.pl's binary
# size cap for zero benefit to programs that never call any of it.
. ./mk.conf
set -e
userdir="$src/user"
outdir="$out/user"
mkdir -p "$outdir"
libmods="lib mem string ctype malloc stdio"
optmods="mem string ctype malloc stdio"
for mod in $libmods; do
"$nscc" "$userdir/$mod.nsc" -o "$outdir/$mod.s"
"$as" $asflgs "$outdir/$mod.s" -o "$outdir/$mod.o"
done
"$as" $asflgs "$userdir/crt.s" -o "$outdir/crt.o"
for prog in "$userdir"/*.nsc; do
name=$(basename "$prog" .nsc)
skip=0
for mod in $libmods; do
[ "$name" = "$mod" ] && skip=1
done
[ "$skip" = 1 ] && continue
"$nscc" "$prog" -o "$outdir/$name.s"
"$as" $asflgs "$outdir/$name.s" -o "$outdir/$name.o"
# which optional libc modules does this program actually pull in
# (by its own "X.nsh" includes), plus each module's own one-level
# object dependency -- string.nsc and stdio.nsc both call mem.nsc's
# functions, so their object needs mem.o on the link line too even
# for a program that never includes mem.nsh itself directly.
wanted=""
for mod in $optmods; do
if grep -q "\"$mod\.nsh\"" "$prog"; then
wanted="$wanted $mod"
fi
done
case " $wanted " in
*" string "*|*" stdio "*)
case " $wanted " in
*" mem "*) ;;
*) wanted="$wanted mem" ;;
esac
;;
esac
libobjs="$outdir/lib.o"
for mod in $optmods; do
case " $wanted " in
*" $mod "*) libobjs="$libobjs $outdir/$mod.o" ;;
esac
done
ldscript="$userdir/user.ld"
# plain flags here, not $ldflgs (the kernel's strict set). NOT -n
# any more: user.ld now defines two explicit
# PT_LOAD segments (R+X, R+W) via PHDRS instead of relying on -n's
# single-combined-segment behavior, which is what was triggering
# ld's "RWX permissions" warning on every single userspace binary
# (a real one, not cosmetic -- an actual OS with paging enforces
# exactly what that warning is about; this kernel doesn't yet, but
# there's no reason to keep shipping executable+writable segments
# once splitting them costs nothing). -z max-page-size/
# common-page-size are set far below the real 4096 specifically
# because splitting into two segments would otherwise cost up to
# ~4095 padding bytes per boundary to satisfy real page alignment
# that this loader (src/kernel/elf.nsc) has no actual use for --
# see user.ld's own comment for the full reasoning.
"$ld" --build-id=none -z max-page-size=16 -z common-page-size=16 -T "$ldscript" -o "$outdir/$name.elf.full" \
"$outdir/$name.o" $libobjs "$outdir/crt.o"
strip -s "$outdir/$name.elf.full" -o "$outdir/$name.elf.stripped"
perl mk/trim-elf.pl "$outdir/$name.elf.stripped" "$outdir/$name.elf"
rm -f "$outdir/$name.elf.full" "$outdir/$name.elf.stripped"
done
echo "built userspace programs in $outdir"