foundry
Foundry OS: the operating system built on the Rustbelt kernel
| author | Grok Bot <grokbot@localhost> | 2026-10-31 19:04:02 -0700 |
|---|---|---|
| commit | 7cf3556ce83e3d8d018ab0da3d9961df733566b2 | |
| parent | 909242193c97a959e835a276764fa1067519c3fc | |
| tree | browse files at this commit | |
toolchain: foundry-cc + musl-pie.specs, every C program and port is static-PIE Based on Clarke's 0.19.0 re-test (clarke-scratch/tc/musl-pie.specs and rb-cc-pie, read only): rcrt1.o + --no-dynamic-linker. Upstream musl-gcc.specs makes a dynamic PIE with PT_INTERP, which Rustbelt refuses (ENOEXEC). make musl now installs out/sysroot/lib/musl-pie.specs; checked: c/hello-musl.c -> ET_DYN with no PT_INTERP. rb-cc is retired.
| M | README.md | +2 -2 |
| M | c/README.md | +1 -1 |
| M | c/hello-musl.c | +1 -1 |
| M | docs/porting.md | +25 -21 |
| M | docs/proposal.md | +1 -1 |
| M | ports/README.md | +7 -1 |
| A | toolchain/foundry-cc | +8 -0 |
| M | toolchain/musl/build.sh | +8 -3 |
| A | toolchain/musl/musl-pie.specs.in | +32 -0 |
9 files changed, 85 insertions, 30 deletions
@@ -35,7 +35,7 @@ the packages the kernel needs plus `make` (all already on the box): | `make test` | headless boot, self-test, ~90 expected-output checks; exit 0 = pass | | `make test-reference` | the same test on the kernel's *own* disk image (the baseline) | | `make compare` | compares our image with the kernel's, file by file |-| `make musl` | downloads (into `cache/`) and builds musl into `out/sysroot` (for M2) |+| `make musl` | downloads (into `cache/`) and builds musl into `out/sysroot`; then `toolchain/foundry-cc` builds static-PIE C programs (M2) | | `make clean` | `rm -rf out` (`make distclean` also empties `cache/`) | ## What is where@@ -52,7 +52,7 @@ foundry/ │ └── link.ld puts programs at address 0x80_0040_0000 ├── rootfs/ files copied onto the disk as they are (readme, notes, the self-test) │ └── etc/ passwd, hosts... for the later ext2 root (not in the image yet)-├── toolchain/musl/ musl C library: pinned by SHA256, downloaded into cache/+├── toolchain/ foundry-cc (gcc + musl, static-PIE); musl/ pinned by SHA256, downloaded into cache/ ├── c/ our own C programs (M2) ├── ports/ other people's C programs, one directory each (dash first) ├── scripts/ mkimage, build-kernel, run-qemu, run-headless, compare-image...
@@ -3,4 +3,4 @@ libc smoke tests for Foundry OS, built against musl. Not in the image yet (milestone M2 adds them to /bin and to the self-test). -- `hello-musl.c`: prints one line; build with `musl-gcc -static-pie`.+- `hello-musl.c`: prints one line; build with `toolchain/foundry-cc` (static-PIE; `make musl` first).
@@ -1,5 +1,5 @@ /* The first Foundry OS C program (milestone M2): plain C against musl.- * Build: musl-gcc -O2 -static-pie hello-musl.c -o hello-musl+ * Build: toolchain/foundry-cc -O2 c/hello-musl.c -o out/hello-musl (after `make musl`) * (Rustbelt 0.19.0 loads static-PIE programs, so no special link flags.) */ #include <stdio.h> #include <sys/utsname.h>
@@ -4,33 +4,37 @@ ## The toolchain -Rustbelt 0.19.0 loads **static-PIE** programs, so C programs need no special-tricks any more. With Debian's musl (`musl-tools`):+Rustbelt 0.19.0 loads **static-PIE** programs (`ET_DYN` with no+`PT_INTERP`), so C programs need no special link tricks any more. Every C+program and port is built as a static-PIE: ```sh-musl-gcc -O2 -static-pie c/hello-musl.c -o out/hello-musl+make musl # once: musl into out/sysroot (+ musl-pie.specs)+toolchain/foundry-cc -O2 c/hello-musl.c -o out/hello-musl+readelf -l out/hello-musl | grep INTERP # must print nothing ``` -That makes an `ET_DYN` file with no `PT_INTERP`: a static-PIE. It runs on the-Linux host too, which is handy (configure scripts run their test programs).+`toolchain/foundry-cc` is three lines: `gcc -specs out/sysroot/lib/musl-pie.specs+-static-pie "$@"`. The specs file (`toolchain/musl/musl-pie.specs.in`, from+Clarke's 0.19.0 re-test) points gcc at our musl headers and libraries and,+for `-static-pie`, uses musl's self-relocating start file **`rcrt1.o`** and+links with **`--no-dynamic-linker`**. -The old `rb-cc` wrapper from the proposal (crt1.o, `-Ttext-segment`,-`--defsym=_DYNAMIC`, `--no-relax`) was only needed for `ET_EXEC` at-Rustbelt's high user base. Don't use it for new programs. The kernel keeps-one program built that way (`vdsotest`) as a loader test.--## Our own musl (`make musl`)+**The gotcha:** the `musl-gcc` wrapper that musl itself installs (into+`out/sysroot/bin`) uses upstream `musl-gcc.specs`, and with `-static-pie`+that makes a *dynamic* PIE: it still has a `PT_INTERP`+(`/lib/ld-musl-x86_64.so.1`). Rustbelt refuses that with `ENOEXEC`. So use+`foundry-cc`, not that `musl-gcc`. Debian's `musl-gcc -static-pie`+(package `musl-tools`) also works; the kernel builds its own musl fixtures+with it. -`make musl` downloads musl into `cache/` (SHA256-checked, see-`toolchain/musl/`) and installs a static-only musl into `out/sysroot`-(`include/`, `lib/libc.a`, the `crt*.o` start files, and a `bin/musl-gcc`-wrapper).+The binaries also run on the Linux host, which is handy because configure+scripts run their test programs. -**Known gap (M2 to-do):** musl's own generated `musl-gcc` wrapper does not-handle `-static-pie`. Its specs file always adds the dynamic-loader path, so-the result gets a `PT_INTERP` and is refused. Debian's `musl-gcc` handles-this properly, so use that until `toolchain/musl/` ships its own-`musl-gcc.specs` (or a small `foundry-cc` wrapper) with the `static-pie` case.+The old `rb-cc` wrapper from the proposal (crt1.o, `-Ttext-segment`,+`--defsym=_DYNAMIC`, `--no-relax`, for `ET_EXEC` at Rustbelt's high user+base) is retired. The kernel keeps one program built that way (`vdsotest`)+as a loader test. ## Adding a port @@ -38,7 +42,7 @@ this properly, so use that until `toolchain/musl/` ships its own ports/<name>/<name>.sha256 "SHA256 <tarball>" ports/<name>/<name>.url where to download it ports/<name>/patches/ 0001-*.patch ...-ports/<name>/build.sh unpack from cache/, patch, CC=musl-gcc ./configure --host=x86_64-linux-musl,+ports/<name>/build.sh unpack from cache/, patch, CC=toolchain/foundry-cc ./configure --host=x86_64-linux-musl, make, install into out/staging (busybox/sbase: under /usr/lib/busybox) ```
@@ -487,7 +487,7 @@ rustbelt-os/ │ │ ├── fetch.sh download + SHA256 check │ │ ├── build.sh unpack → patch → configure → make → install into out/sysroot │ │ └── patches/ 0001-*.patch, applied in order (empty at first)-│ └── (no rb-cc: Rustbelt 0.19.0 runs static-PIE, so plain musl-gcc -static-pie works)+│ └── foundry-cc gcc -specs musl-pie.specs -static-pie (no rb-cc hacks: 0.19.0 runs static-PIE) │ ├── c/ small C programs of our own (hello-musl.c, mprobe.c = libc smoke tests) │
@@ -8,7 +8,13 @@ ports/<name>/ ├── <name>.sha256 the pinned release tarball: "SHA256 file-name" ├── <name>.url where to download it (into the git-ignored cache/) ├── patches/ our changes, applied in order (0001-*.patch, ...)-└── build.sh unpack -> patch -> configure -> make -> install into out/staging+└── build.sh unpack -> patch -> CC=toolchain/foundry-cc configure -> make -> install into out/staging+```++Every port is built as a **static-PIE** with `toolchain/foundry-cc` (see+docs/porting.md).++``` ``` No tarball is ever committed; `cache/` is git-ignored and every download is
@@ -0,0 +1,8 @@+#!/bin/sh+# foundry-cc: the C compiler for Foundry OS programs and ports.+# Plain gcc + our musl sysroot (make musl), always static-PIE: Rustbelt+# 0.19.0 loads static-PIE, so there are no link tricks (the old rb-cc).+# Based on Clarke's 0.19.0 re-test wrapper (clarke-scratch/tc/rb-cc-pie).+# SYSROOT defaults to out/sysroot of this repo.+SYSROOT=${FOUNDRY_SYSROOT:-$(cd "$(dirname "$0")/.." && pwd)/out/sysroot}+exec gcc -specs "$SYSROOT/lib/musl-pie.specs" -static-pie "$@"
@@ -4,9 +4,11 @@ # the crt*.o start files in lib/, plus a musl-gcc wrapper in bin/). # # Not used by the contract-v1 image yet (milestone M2). Since Rustbelt-# 0.19.0 loads static-PIE programs, the plan is plain-# out/sysroot/bin/musl-gcc -static-pie hello.c-# with none of the old rb-cc link tricks (see docs/porting.md).+# 0.19.0 loads static-PIE programs, C programs are built with+# toolchain/foundry-cc hello.c -o hello (gcc + musl-pie.specs, -static-pie)+# with none of the old rb-cc link tricks (see docs/porting.md). Do NOT use+# the musl-gcc that musl installs into SYSROOT/bin for -static-pie: its+# specs add a PT_INTERP. # # Usage: toolchain/musl/build.sh CACHE_DIR BUILD_DIR SYSROOT set -euo pipefail@@ -24,4 +26,7 @@ cd "$src" ./configure --prefix="$SYSROOT" --syslibdir="$SYSROOT/lib" --disable-shared >/dev/null make -j"$(nproc)" >/dev/null make install >/dev/null+# Our static-PIE specs (musl's own musl-gcc.specs makes a dynamic PIE with+# PT_INTERP, which Rustbelt refuses); toolchain/foundry-cc uses it.+sed "s#@SYSROOT@#$SYSROOT#g" "$HERE/musl-pie.specs.in" > "$SYSROOT/lib/musl-pie.specs" echo "[musl] installed into $SYSROOT ($(ls "$SYSROOT/lib" | wc -l) files in lib/)"
@@ -0,0 +1,32 @@+%rename cpp_options old_cpp_options++*cpp_options:+-nostdinc -isystem @SYSROOT@/include -isystem include%s %(old_cpp_options)++*cc1:+%(cc1_cpu) -nostdinc -isystem @SYSROOT@/include -isystem include%s++*link_libgcc:+-L@SYSROOT@/lib -L .%s++*libgcc:+libgcc.a%s %:if-exists(libgcc_eh.a%s)++*startfile:+%{shared:;static-pie:@SYSROOT@/lib/rcrt1.o; :@SYSROOT@/lib/Scrt1.o} @SYSROOT@/lib/crti.o crtbeginS.o%s++*endfile:+crtendS.o%s @SYSROOT@/lib/crtn.o++*link:+-dynamic-linker /lib/ld-musl-x86_64.so.1 -nostdlib %{shared:-shared} %{static:-static} %{static-pie:-static -pie --no-dynamic-linker} %{rdynamic:-export-dynamic}++*esp_link:+++*esp_options:+++*esp_cpp_options:++