boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit a644ff4bc3fef5e1e2a76a8ad904ab7d574dd57b
parent 8dbebe704dfca3ef0d2a69b99862f1a5f7fa5f4f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon,  4 May 2026 15:17:13 -0700

Shrink boot.sh dep surface

Cut tools the build depends on, both host-side and inside the
scratch+busybox container.

  - sed: ported musl's tools/mkalltypes.sed to scripts/mkalltypes.awk
    (byte-identical output verified for all three arches); replaced
    the SYS_*/-help one-liners with awk equivalents.
  - patch: vendored the post-patch state of musl-1.2.5 as
    vendor/upstream/musl-1.2.5-overrides/ (17 files) +
    musl-1.2.5-deletes.txt (151 paths). boot4 now overlays + rms
    instead of running patch + the belt-and-braces 0-byte-stub
    cleanup. scripts/musl-vendor.sh regenerates these from the
    upstream tarball + tcc patch on a dev host (off the boot path).
  - ln: cp -R the per-arch mes-libc include tree instead of symlinking.
  - cat: hello.c heredocs moved to scripts/boot-hello.c (single
    source, used by both boot3 and boot4).
  - head, tail: dropped diagnostic log tails.
  - tar in container: extract on host, container cp -R's the unpacked
    tree into tmpfs.
  - cmp, wc in container: boot3 emits both tcc2 and tcc3 to staging;
    fixed-point check + size logging happen on the host.

Container-side surface is now sh, awk, cp, mkdir, rm, chmod (down
from 14). Host-side drops sed, patch, ln, cat, head, tail.

Diffstat:
Mdocs/MUSL.md | 17+++++++++++------
Ascripts/boot-hello.c | 13+++++++++++++
Mscripts/boot3.sh | 51+++++++++++++++++++--------------------------------
Mscripts/boot4.sh | 138+++++++++++++++++++++++++++++--------------------------------------------------
Mscripts/libc-flatten.sh | 12++++++------
Ascripts/mkalltypes.awk | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/musl-vendor.sh | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mscripts/stage1-flatten.sh | 6++----
Avendor/upstream/musl-1.2.5-deletes.txt | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/arch/aarch64/atomic_arch.h | 28++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/arch/aarch64/crt_arch.h | 36++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/arch/aarch64/pthread_arch.h | 14++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/arch/aarch64/syscall_arch.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/arch/x86_64/syscall_arch.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/include/complex.h | 10++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/include/features.h | 15+++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/atomic.s | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/get_tp.s | 17+++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/syscall.s | 22++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/internal/syscall.h | 413+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/internal/x86_64/syscall.s | 13+++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/network/lookup.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/network/lookup_ipliteral.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/network/lookup_name.c | 437+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/network/lookup_serv.c | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Avendor/upstream/musl-1.2.5-overrides/src/thread/aarch64/__set_thread_area.s | 23+++++++++++++++++++++++
26 files changed, 1904 insertions(+), 135 deletions(-)

diff --git a/docs/MUSL.md b/docs/MUSL.md @@ -24,7 +24,8 @@ scripts/boot4.sh <amd64|aarch64|riscv64> | `build/$ARCH/boot3/libtcc1.a` | tcc runtime archive produced by boot3 | | `build/tcc/$TCC_TARGET/tcc-0.9.26-1147-gee75a10c/include` | staged tcc headers | | `vendor/upstream/musl-1.2.5.tar.gz` | pristine upstream musl source | -| `vendor/upstream/musl-1.2.5-tcc.patch` | tcc-compat musl patch | +| `vendor/upstream/musl-1.2.5-overrides/` | post-patch files vendored as a tree (replaces the old patch + `patch` binary) | +| `vendor/upstream/musl-1.2.5-deletes.txt` | upstream files removed by the same patch set, one path per line | | `scripts/boot4-musl-shim-$ARCH.h` | per-arch `__builtin_va_list` bridge | Architecture mapping: @@ -50,10 +51,14 @@ The staging copy under `build/$ARCH/.boot4-stage/` is disposable. ## Pipeline 1. Copy boot3 `tcc3`, boot3 `libtcc1.a`, tcc headers, musl tarball, - musl patch, and the per-arch shim into `build/$ARCH/.boot4-stage/in`. -2. Extract musl, apply `musl-1.2.5-tcc.patch`, and remove unsupported - arch-specific override files so portable C fallbacks are selected - where possible. + the `musl-1.2.5-overrides/` tree, the `musl-1.2.5-deletes.txt` list, + and the per-arch shim into `build/$ARCH/.boot4-stage/in`. The musl + tarball is extracted on the host (the container has no `tar`). +2. Copy the unpacked musl tree into the container's tmpfs, overlay the + override files on top, then remove every path listed in + `musl-1.2.5-deletes.txt`. This produces the same tree the old + `patch + belt-and-braces rm` recipe did, but without depending on a + `patch` binary. 3. Configure musl with `CC=$TCC AR=true RANLIB=true`, `--disable-shared`, and `--disable-wrapper`. 4. Generate `bits/alltypes.h`, `bits/syscall.h`, and `version.h`. @@ -69,7 +74,7 @@ Assembler inputs must not receive the va-list shim. tcc 0.9.26 applies ## Compatibility Surface -The musl patch keeps upstream musl mostly intact and replaces only the +The musl overrides keep upstream musl mostly intact and replace only the surfaces tcc 0.9.26 cannot compile: | Area | Rule | diff --git a/scripts/boot-hello.c b/scripts/boot-hello.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +extern char *strdup(char const *); + +int main(int argc, char **argv) { + printf("hello from tcc-built libc; argc=%d\n", argc); + char *s = strdup("works"); + printf("strdup: %s, strlen: %d\n", s, (int) strlen(s)); + free(s); + return 0; +} diff --git a/scripts/boot3.sh b/scripts/boot3.sh @@ -210,23 +210,7 @@ cp "$LIBC_FLAT" "$STAGE/in/libc.flat.c" cp -R "$TCC_DIR/include/." "$STAGE/in/tcc-include/" cp -R vendor/mes-libc/include/. "$STAGE/in/mes-include/" -cat > "$STAGE/in/hello.c" <<'EOF' -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -extern char *strdup (char const *); - -int -main (int argc, char **argv) -{ - printf ("hello from boot3 (tcc-built mes libc); argc=%d\n", argc); - char *s = strdup ("works"); - printf ("strdup: %s, strlen: %d\n", s, (int) strlen (s)); - free (s); - return 0; -} -EOF +cp scripts/boot-hello.c "$STAGE/in/hello.c" # Every arch's tcc-boot2 has CONFIG_TCC_ASM and assembles .S inputs # itself inside the container — no host cross-asm step. @@ -359,19 +343,16 @@ archive_runtime $OUT/tcc2 /tmp/stage3 link_tcc_with_runtime $OUT/tcc2 /tmp/stage3 $OUT/tcc3 chmod +x $OUT/tcc3 -if ! cmp -s $OUT/tcc2 $OUT/tcc3; then - s2=$(wc -c <$OUT/tcc2) - s3=$(wc -c <$OUT/tcc3) - echo "[boot3] FIXED-POINT FAIL: tcc2 ($s2) != tcc3 ($s3)" >&2 - exit 1 -fi - +# Fixed-point check (tcc2 == tcc3) is performed on the host after this +# container exits — both files are emitted to /work/out so the host can +# cmp them. Same for size reporting (no wc inside the container). +# # Publish the tcc2-built mes-libc link closure and prove it can link -# and run a normal C program. tcc2 and tcc3 are byte-identical by the -# check above, so rebuilding these artifacts with tcc3 would only repeat -# the same fixed-point compiler cycle. crt1.o is kept separate because -# it must lead the final link; the rest of the runtime is hidden behind -# libc.a. +# and run a normal C program. tcc2 and tcc3 will be byte-identical +# (asserted on the host); rebuilding these artifacts with tcc3 would +# only repeat the same fixed-point compiler cycle. crt1.o is kept +# separate because it must lead the final link; the rest of the runtime +# is hidden behind libc.a. cp /tmp/stage3/crt1.o /tmp/stage3/libc.a /tmp/stage3/libtcc1.a "$OUT/" "$OUT/tcc2" -nostdlib -I "$TCC_INC" -I "$MES_INC" \ @@ -379,13 +360,18 @@ cp /tmp/stage3/crt1.o /tmp/stage3/libc.a /tmp/stage3/libtcc1.a "$OUT/" "$OUT/libc.a" "$OUT/libtcc1.a" "$OUT/libc.a" \ -o "$OUT/hello" chmod +x "$OUT/hello" -echo "libtcc1.a: $(wc -c <"$OUT/libtcc1.a") bytes" -echo "libc.a: $(wc -c <"$OUT/libc.a") bytes" -echo "hello: $(wc -c <"$OUT/hello") bytes" echo "--- run ---" "$OUT/hello" a b c CONTAINER +# ── fixed-point check (host-side; container has no cmp) ────────────── +if ! cmp -s "$STAGE/out/tcc2" "$STAGE/out/tcc3"; then + s2=$(wc -c <"$STAGE/out/tcc2") + s3=$(wc -c <"$STAGE/out/tcc3") + echo "[boot3 $ARCH] FIXED-POINT FAIL: tcc2 ($s2) != tcc3 ($s3)" >&2 + exit 1 +fi + # ── copy outputs to final destination ───────────────────────────────── rm -f "$OUT/tcc0" "$OUT/tcc1" "$OUT/tcc2" \ "$OUT/start.o" "$OUT/sys_stubs.o" "$OUT/mem.o" "$OUT/libc.o" @@ -394,4 +380,5 @@ for f in tcc3 crt1.o libc.a libtcc1.a hello; do done chmod 0700 "$OUT/tcc3" "$OUT/hello" +echo "[boot3 $ARCH] sizes: libtcc1.a=$(wc -c <"$OUT/libtcc1.a") libc.a=$(wc -c <"$OUT/libc.a") hello=$(wc -c <"$OUT/hello")" echo "[boot3 $ARCH] OK -> $OUT/{tcc3, crt1.o, libc.a, libtcc1.a, hello} (fixed point: tcc2 == tcc3)" diff --git a/scripts/boot4.sh b/scripts/boot4.sh @@ -16,9 +16,16 @@ ## — staged by stage1-flatten.sh during boot3 ## vendor/upstream/musl-1.2.5.tar.gz ## — pristine musl source -## vendor/upstream/musl-1.2.5-tcc.patch -## — tcc-compat patch (currently x86_64-only; -## see docs/MUSL.md "multi-arch status") +## vendor/upstream/musl-1.2.5-overrides/ +## — tree of files that replace upstream +## ones (tcc-compat patches; the post- +## patch state vendored directly so the +## build needs no `patch` binary). See +## docs/MUSL.md. +## vendor/upstream/musl-1.2.5-deletes.txt +## — list of upstream files removed by the +## same patch set (one path per line, +## relative to musl-1.2.5/). ## scripts/boot4-musl-shim-$ARCH.h ## — per-arch __builtin_va_list bridge ## @@ -67,16 +74,18 @@ OUT=build/$ARCH/boot4 STAGE=build/$ARCH/.boot4-stage TCC_DIR=build/tcc/$TCC_TARGET/tcc-0.9.26-1147-gee75a10c MUSL_TARBALL=vendor/upstream/musl-1.2.5.tar.gz -MUSL_PATCH=vendor/upstream/musl-1.2.5-tcc.patch +MUSL_OVERRIDES=vendor/upstream/musl-1.2.5-overrides +MUSL_DELETES=vendor/upstream/musl-1.2.5-deletes.txt SHIM_FILE=scripts/boot4-musl-shim-$ARCH.h # ── prerequisites ───────────────────────────────────────────────────── -[ -x "$BOOT3/tcc3" ] || { echo "[boot4 $ARCH] missing $BOOT3/tcc3 (run scripts/boot3.sh $ARCH)" >&2; exit 1; } -[ -e "$BOOT3/libtcc1.a" ] || { echo "[boot4 $ARCH] missing $BOOT3/libtcc1.a (run scripts/boot3.sh $ARCH)" >&2; exit 1; } -[ -d "$TCC_DIR/include" ] || { echo "[boot4 $ARCH] missing $TCC_DIR/include (run scripts/boot3.sh $ARCH first)" >&2; exit 1; } -[ -e "$MUSL_TARBALL" ] || { echo "[boot4 $ARCH] missing $MUSL_TARBALL" >&2; exit 1; } -[ -e "$MUSL_PATCH" ] || { echo "[boot4 $ARCH] missing $MUSL_PATCH" >&2; exit 1; } -[ -e "$SHIM_FILE" ] || { echo "[boot4 $ARCH] missing $SHIM_FILE" >&2; exit 1; } +[ -x "$BOOT3/tcc3" ] || { echo "[boot4 $ARCH] missing $BOOT3/tcc3 (run scripts/boot3.sh $ARCH)" >&2; exit 1; } +[ -e "$BOOT3/libtcc1.a" ] || { echo "[boot4 $ARCH] missing $BOOT3/libtcc1.a (run scripts/boot3.sh $ARCH)" >&2; exit 1; } +[ -d "$TCC_DIR/include" ] || { echo "[boot4 $ARCH] missing $TCC_DIR/include (run scripts/boot3.sh $ARCH first)" >&2; exit 1; } +[ -e "$MUSL_TARBALL" ] || { echo "[boot4 $ARCH] missing $MUSL_TARBALL" >&2; exit 1; } +[ -d "$MUSL_OVERRIDES" ] || { echo "[boot4 $ARCH] missing $MUSL_OVERRIDES" >&2; exit 1; } +[ -e "$MUSL_DELETES" ] || { echo "[boot4 $ARCH] missing $MUSL_DELETES" >&2; exit 1; } +[ -e "$SHIM_FILE" ] || { echo "[boot4 $ARCH] missing $SHIM_FILE" >&2; exit 1; } if ! podman image exists "$IMAGE"; then echo "[boot4 $ARCH] building $IMAGE" @@ -93,22 +102,17 @@ cp "$BOOT3/tcc3" "$STAGE/in/tcc" cp "$BOOT3/libtcc1.a" "$STAGE/in/libtcc1.a" cp -R "$TCC_DIR/include/." "$STAGE/in/tcc-include/" -cp "$MUSL_TARBALL" "$STAGE/in/musl.tar.gz" -cp "$MUSL_PATCH" "$STAGE/in/musl.patch" -cp "$SHIM_FILE" "$STAGE/in/musl-shim.h" +# Extract musl on the host (where tar is always available) instead of +# inside the container — the container has no tar and the unpacked tree +# is read-only input from its perspective. The container cp -R's it to +# /tmp before mutating. +tar xzf "$MUSL_TARBALL" -C "$STAGE/in/" +cp -R "$MUSL_OVERRIDES" "$STAGE/in/musl-overrides" +cp "$MUSL_DELETES" "$STAGE/in/musl-deletes.txt" +cp "$SHIM_FILE" "$STAGE/in/musl-shim.h" +cp scripts/mkalltypes.awk "$STAGE/in/mkalltypes.awk" -cat > "$STAGE/in/hello.c" <<'EOF' -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -int main(int argc, char **argv) { - printf("hello from boot4 (tcc-built musl); argc=%d\n", argc); - char *s = strdup("works"); - printf("strdup: %s, strlen: %zu\n", s, strlen(s)); - free(s); - return 0; -} -EOF +cp scripts/boot-hello.c "$STAGE/in/hello.c" # ── run pipeline in scratch+busybox container ───────────────────────── echo "[boot4 $ARCH] boot3/libtcc1.a + musl libc.a + crt -> hello" @@ -123,72 +127,35 @@ OUT=/work/out TCC=$IN/tcc TCC_INC=$IN/tcc-include -# ── Stage A: extract + patch musl ───────────────────────────────────── +# ── Stage A: stage unpacked musl in tmpfs + apply overrides + deletes ── +# musl-1.2.5/ was extracted on the host (bind-mount is read-only input); +# copy into /tmp so we have a writable working tree, then overlay the +# vendored overrides on top, then remove the files listed in +# musl-deletes.txt. Replaces the old `patch + belt-and-braces rm` block: +# vendoring the post-patch state means no `patch` binary dep and no +# 0-byte-stub cleanup. See vendor/upstream/musl-1.2.5-overrides/ + +# vendor/upstream/musl-1.2.5-deletes.txt for the contents. cd /tmp -tar xzf "$IN/musl.tar.gz" -patch -p1 < "$IN/musl.patch" -# Belt-and-braces: ensure files marked "deleted file mode" really vanish -# (busybox patch leaves 0-byte stubs for delete-mode hunks). The deleted -# files are all per-arch overrides — harmless to remove on any arch -# build since they only matter when MUSL_ARCH matches. -rm -rf musl-1.2.5/src/complex -rm -f musl-1.2.5/src/fenv/x86_64/fenv.s -rm -f musl-1.2.5/src/math/x86_64/*.c -rm -f musl-1.2.5/src/signal/x86_64/sigsetjmp.s -# aarch64 sweep: arch-specific overrides whose inline asm or mnemonics -# arm64-asm.c phase 1+2 can't yet handle. Portable C in src/{math, -# string,fenv} takes over for the .c/.S files in those trees; the -# thread/setjmp/signal .s files have no portable fallback (libc.a will -# lack clone, syscall_cp, setjmp/longjmp/sigsetjmp, etc.) — fine for -# hello.c, revisit when a future test references them. -rm -f musl-1.2.5/src/math/aarch64/*.c -rm -f musl-1.2.5/src/string/aarch64/memset.S -rm -f musl-1.2.5/src/string/aarch64/memcpy.S -rm -f musl-1.2.5/src/fenv/aarch64/fenv.s -rm -f musl-1.2.5/src/thread/aarch64/clone.s -rm -f musl-1.2.5/src/thread/aarch64/syscall_cp.s -rm -f musl-1.2.5/src/thread/aarch64/__unmapself.s -# __set_thread_area.s is REPLACED in the patch (msr as raw .long), not deleted — -# __init_tls.c calls it during process init. -rm -f musl-1.2.5/src/setjmp/aarch64/setjmp.s -rm -f musl-1.2.5/src/setjmp/aarch64/longjmp.s -rm -f musl-1.2.5/src/signal/aarch64/sigsetjmp.s -# riscv64 sweep: math overrides use FPU inline asm with "=f" operand -# constraints (subst_asm_operand stub on riscv64-asm.c); fenv.S / -# setjmp.S / clone.s / etc. use displacement-load syntax, csr* -# mnemonics, and the `j` / `ret` pseudos absent from riscv64-tok.h. -# Drop them — portable C in src/{math,fenv} takes over; libc.a will -# lack clone, syscall_cp, setjmp/longjmp/sigsetjmp, vfork, restore, -# fenv. Boot4 hello doesn't reach them. -rm -f musl-1.2.5/src/math/riscv64/*.c -rm -f musl-1.2.5/src/fenv/riscv64/fenv.S -rm -f musl-1.2.5/src/fenv/riscv64/fenv-sf.c -rm -f musl-1.2.5/src/setjmp/riscv64/setjmp.S -rm -f musl-1.2.5/src/setjmp/riscv64/longjmp.S -rm -f musl-1.2.5/src/signal/riscv64/sigsetjmp.s -rm -f musl-1.2.5/src/signal/riscv64/restore.s -rm -f musl-1.2.5/src/thread/riscv64/clone.s -rm -f musl-1.2.5/src/thread/riscv64/syscall_cp.s -rm -f musl-1.2.5/src/thread/riscv64/__unmapself.s -# (keep src/thread/riscv64/__set_thread_area.s — patched to use the -# explicit `jalr x0, x1, 0` form of `ret`. It's on the __init_tp / -# __libc_start_main path; linker would fail at start otherwise.) -rm -f musl-1.2.5/src/process/riscv64/vfork.s +cp -R "$IN/musl-1.2.5" . +cp -R "$IN/musl-overrides/." musl-1.2.5/ +while read -r p; do + [ -n "$p" ] && rm -rf "musl-1.2.5/$p" +done < "$IN/musl-deletes.txt" # ── Stage B: configure + generate musl headers ──────────────────────── cd /tmp/musl-1.2.5 CC=$TCC AR=true RANLIB=true sh ./configure \ --target=$MUSL_ARCH-linux-musl --disable-shared --disable-wrapper \ --prefix=/tmp/musl-install >/tmp/cfg.log 2>&1 \ - || { echo "configure failed:"; tail -n 40 /tmp/cfg.log; exit 1; } -echo "configure: ok ($(wc -l </tmp/cfg.log) lines)" + || { echo "configure failed (see /tmp/cfg.log)"; exit 1; } +echo "configure: ok" mkdir -p obj/include/bits obj/src/internal -sed -f tools/mkalltypes.sed \ +awk -f $IN/mkalltypes.awk \ arch/$MUSL_ARCH/bits/alltypes.h.in include/alltypes.h.in \ > obj/include/bits/alltypes.h cp arch/$MUSL_ARCH/bits/syscall.h.in obj/include/bits/syscall.h -sed -n -e 's/__NR_/SYS_/p' < arch/$MUSL_ARCH/bits/syscall.h.in \ +awk 'sub(/__NR_/, "SYS_") { print }' < arch/$MUSL_ARCH/bits/syscall.h.in \ >> obj/include/bits/syscall.h echo '#define VERSION "1.2.5-tcc-boot4"' > obj/src/internal/version.h @@ -245,8 +212,7 @@ for b in $BASE_SRCS; do done KEEP="$KEEP $ARCH_SRCS" -n_total=$(echo $KEEP | wc -w) -echo "compiling musl ($n_total sources; skip-on-fail mode)" +echo "compiling musl (skip-on-fail mode)" mkdir -p obj/lib OBJS=""; n=0; n_ok=0; n_skip=0 : >/tmp/skipped.txt @@ -266,11 +232,9 @@ for src in $KEEP; do echo "$src" >>/tmp/skipped.txt fi n=$((n+1)) - [ $((n % 200)) -eq 0 ] && echo " $n/$n_total (ok=$n_ok skip=$n_skip)" + [ $((n % 200)) -eq 0 ] && echo " $n done (ok=$n_ok skip=$n_skip)" done -echo " compiled=$n_ok skipped=$n_skip / $n_total" -echo "--- first 30 skipped ---" -head -30 /tmp/skipped.txt +echo " compiled=$n_ok skipped=$n_skip total=$n (skips listed in /tmp/skipped.txt)" # ── Stage D: CRT + libc.a ───────────────────────────────────────────── # musl's per-arch crti.s/crtn.s wins over the top-level crt/crti.c if @@ -292,9 +256,9 @@ echo "archiving libc.a" $TCC -ar rcs lib/libc.a $OBJS cp lib/libc.a lib/crt1.o lib/crti.o lib/crtn.o "$OUT/" -echo "libc.a: $(wc -c <"$OUT/libc.a") bytes" # ── Stage E: smoke test — link + run hello ──────────────────────────── +# Size reporting (wc) is done on the host after this container exits. $TCC -static -nostdinc -nostdlib \ -include "$IN/musl-shim.h" \ -I./include -I./arch/$MUSL_ARCH -I./arch/generic -Iobj/include \ @@ -302,7 +266,6 @@ $TCC -static -nostdinc -nostdlib \ -L./lib -lc -L"$IN" -ltcc1 -L./lib -lc \ -o "$OUT/hello" -echo "hello: $(wc -c <"$OUT/hello") bytes" echo "--- run ---" "$OUT/hello" a b c CONTAINER @@ -312,4 +275,5 @@ for f in libc.a crt1.o crti.o crtn.o hello; do cp "$STAGE/out/$f" "$OUT/$f" done +echo "[boot4 $ARCH] sizes: libc.a=$(wc -c <"$OUT/libc.a") hello=$(wc -c <"$OUT/hello")" echo "[boot4 $ARCH] OK -> $OUT/{libc.a, crt1.o, crti.o, crtn.o, hello}" diff --git a/scripts/libc-flatten.sh b/scripts/libc-flatten.sh @@ -28,7 +28,7 @@ ARCH=aarch64 while [ $# -gt 0 ]; do case "$1" in --arch) ARCH=$2; shift 2 ;; - -h|--help) sed -n 's/^## \{0,1\}//p' "$0"; exit 0 ;; + -h|--help) awk '/^##/ { sub(/^## ?/, ""); print }' "$0"; exit 0 ;; *) echo "unknown arg: $1" >&2; exit 2 ;; esac done @@ -60,9 +60,10 @@ cp -R "$VENDOR/." "$STAGE/" # mes's sys/stat.h, signal.h, dirent.h reach for <arch/kernel-stat.h> # and similar; the per-arch tree under include/linux/<MES_ARCH>/ is what -# they want. Drop a sibling include/arch -> include/linux/<MES_ARCH> -# symlink so the unprefixed `arch/...` includes resolve. -ln -sfn "linux/$MES_ARCH" "$STAGE/include/arch" +# they want. Copy the per-arch tree into include/arch so the unprefixed +# `arch/...` includes resolve. (cp -R, not ln -sfn — keeps the dep set +# down to coreutils we already use.) +cp -R "$STAGE/include/linux/$MES_ARCH" "$STAGE/include/arch" # --- (2) patches ------------------------------------------------------ @@ -180,6 +181,5 @@ HOST_CC=${HOST_CC:-cc} -D inline= \ "$STAGE/unified-libc.c" > "$FLAT" -LINES=$(wc -l < "$FLAT") BYTES=$(wc -c < "$FLAT") -echo "produced $FLAT ($LINES lines, $BYTES bytes)" +echo "produced $FLAT ($BYTES bytes)" diff --git a/scripts/mkalltypes.awk b/scripts/mkalltypes.awk @@ -0,0 +1,81 @@ +# mkalltypes.awk — port of musl-1.2.5/tools/mkalltypes.sed. +# +# Reads alltypes.h.in (per-arch + generic, concatenated). Lines starting +# with TYPEDEF / STRUCT / UNION are expanded into the standard +# #if defined(__NEED_X) && !defined(__DEFINED_X) ... #endif +# guard blocks. All other lines pass through unchanged. +# +# Output is byte-identical to running `sed -f tools/mkalltypes.sed` on +# the same inputs (the original sed preserves the input's internal +# alignment whitespace, so this awk does the same — no field splitting). + +# Match sed `TYPEDEF \(.*\) \([^ ]*\);$` — greedy first capture, last +# space-delimited token is the name. Returns 1 on match, sets t and n. +function split_typedef(line, _, pos, last) { + if (substr(line, length(line)) != ";") return 0 + line = substr(line, 1, length(line) - 1) + # locate the last space + last = 0 + for (pos = length(line); pos >= 1; pos--) { + if (substr(line, pos, 1) == " ") { last = pos; break } + } + if (last == 0) return 0 + t = substr(line, 1, last - 1) + n = substr(line, last + 1) + return 1 +} + +/^TYPEDEF / { + rest = substr($0, 9) + if (split_typedef(rest)) { + printf "#if defined(__NEED_%s) && !defined(__DEFINED_%s)\n", n, n + printf "typedef %s %s;\n", t, n + printf "#define __DEFINED_%s\n", n + printf "#endif\n\n" + next + } +} + +# sed: STRUCT * \([^ ]*\) \(.*\);$ +# After STRUCT and any spaces, first non-space-run is the name; rest +# (space then body) ends with ;. Note: sed's `STRUCT *` allows zero or +# more spaces after STRUCT, but in practice input always has at least +# one — match either way. +/^STRUCT / { + rest = substr($0, 8) # skip "STRUCT " + sub(/^ +/, "", rest) # collapse extra spaces + if (substr(rest, length(rest)) == ";") { + rest = substr(rest, 1, length(rest) - 1) + # name = first space-delimited token + sp = index(rest, " ") + if (sp > 0) { + sname = substr(rest, 1, sp - 1) + sbody = substr(rest, sp + 1) + printf "#if defined(__NEED_struct_%s) && !defined(__DEFINED_struct_%s)\n", sname, sname + printf "struct %s %s;\n", sname, sbody + printf "#define __DEFINED_struct_%s\n", sname + printf "#endif\n\n" + next + } + } +} + +/^UNION / { + rest = substr($0, 7) # skip "UNION " + sub(/^ +/, "", rest) + if (substr(rest, length(rest)) == ";") { + rest = substr(rest, 1, length(rest) - 1) + sp = index(rest, " ") + if (sp > 0) { + uname = substr(rest, 1, sp - 1) + ubody = substr(rest, sp + 1) + printf "#if defined(__NEED_union_%s) && !defined(__DEFINED_union_%s)\n", uname, uname + printf "union %s %s;\n", uname, ubody + printf "#define __DEFINED_union_%s\n", uname + printf "#endif\n\n" + next + } + } +} + +{ print } diff --git a/scripts/musl-vendor.sh b/scripts/musl-vendor.sh @@ -0,0 +1,116 @@ +#!/bin/sh +## musl-vendor.sh — regenerate vendor/upstream/musl-1.2.5-overrides/ and +## musl-1.2.5-deletes.txt from the upstream tarball + tcc-compat patch. +## +## NOT on the boot.sh path. This is a vendoring helper run on a dev host +## any time vendor/upstream/musl-1.2.5-tcc.patch changes; it requires +## the host's `patch` binary. The output it produces (the overrides +## directory tree + the deletes list) is what boot4.sh consumes — boot4 +## itself never invokes `patch`. +## +## What the script does: +## 1. Extract a pristine copy of musl-1.2.5.tar.gz to a scratch dir. +## 2. Apply musl-1.2.5-tcc.patch. +## 3. For every file the patch touched: +## - if non-empty in the patched tree → vendor it into +## musl-1.2.5-overrides/<path>, mirroring the musl-1.2.5/ +## subtree layout. +## - if 0-byte (the patch's deleted-file marker) → record the +## path in musl-1.2.5-deletes.txt. +## 4. Append the per-arch sweep deletes (aarch64+riscv64 overrides +## arm64-asm.c phase 1+2 / riscv64-asm.c can't yet handle). +## 5. Sort + dedupe the deletes list. +## +## Boot4 then mirrors this state at build time without `patch`: +## cp -R overrides/. musl-1.2.5/ +## while read p; do rm -rf "musl-1.2.5/$p"; done < deletes.txt + +set -eu + +ROOT=$(cd "$(dirname "$0")/.." && pwd) +cd "$ROOT" + +TARBALL=vendor/upstream/musl-1.2.5.tar.gz +PATCH_FILE=vendor/upstream/musl-1.2.5-tcc.patch +OVERRIDES=vendor/upstream/musl-1.2.5-overrides +DELETES=vendor/upstream/musl-1.2.5-deletes.txt + +[ -e "$TARBALL" ] || { echo "missing $TARBALL" >&2; exit 1; } +[ -e "$PATCH_FILE" ] || { echo "missing $PATCH_FILE" >&2; exit 1; } +command -v patch >/dev/null || { echo "host patch not found" >&2; exit 1; } + +WORK=$(mktemp -d) +trap 'rm -rf "$WORK"' EXIT + +# (1) extract +tar xzf "$TARBALL" -C "$WORK" +SRC=$WORK/musl-1.2.5 +[ -d "$SRC" ] || { echo "tarball did not produce musl-1.2.5/"; exit 1; } + +# (2) apply patch (cwd = parent of musl-1.2.5/, -p1 strips the a/ prefix) +( cd "$WORK" && patch -p1 < "$ROOT/$PATCH_FILE" ) >"$WORK/patch.log" 2>&1 \ + || { tail -40 "$WORK/patch.log" >&2; exit 1; } + +# (3) mirror touched files into overrides/, record empty ones as deletes +rm -rf "$OVERRIDES" +mkdir -p "$OVERRIDES" +: > "$DELETES" + +# Each diff in the patch starts with `diff -urN ... patched_musl/musl-1.2.5/<rel>`. +# Strip the "patched_musl/musl-1.2.5/" prefix to get a path under SRC. +awk '/^diff -urN/ { + sub(/^patched_musl\/musl-1.2.5\//, "", $4); print $4 + }' "$PATCH_FILE" | +while read -r rel; do + f=$SRC/$rel + if [ -s "$f" ]; then + mkdir -p "$OVERRIDES/$(dirname "$rel")" + cp "$f" "$OVERRIDES/$rel" + else + echo "$rel" >> "$DELETES" + fi +done + +# (4) per-arch sweep: aarch64 + riscv64 files boot4 can't compile yet. +# Globs are expanded against the upstream tree, so every entry is a +# concrete file path (no glob in the deletes list itself). +for f in "$SRC"/src/math/aarch64/*.c; do + [ -e "$f" ] && echo "${f#$SRC/}" >> "$DELETES" +done +for f in "$SRC"/src/math/riscv64/*.c; do + [ -e "$f" ] && echo "${f#$SRC/}" >> "$DELETES" +done +{ + echo src/string/aarch64/memset.S + echo src/string/aarch64/memcpy.S + echo src/fenv/aarch64/fenv.s + echo src/thread/aarch64/clone.s + echo src/thread/aarch64/syscall_cp.s + echo src/thread/aarch64/__unmapself.s + echo src/setjmp/aarch64/setjmp.s + echo src/setjmp/aarch64/longjmp.s + echo src/signal/aarch64/sigsetjmp.s + echo src/fenv/riscv64/fenv.S + echo src/fenv/riscv64/fenv-sf.c + echo src/setjmp/riscv64/setjmp.S + echo src/setjmp/riscv64/longjmp.S + echo src/signal/riscv64/sigsetjmp.s + echo src/signal/riscv64/restore.s + echo src/thread/riscv64/clone.s + echo src/thread/riscv64/syscall_cp.s + echo src/thread/riscv64/__unmapself.s + echo src/process/riscv64/vfork.s + # src/complex/ is gutted by the patch (every .c file becomes 0-byte + # in the patched tree, so it's already in DELETES). The dir entry + # cleans up the empty directory itself. + echo src/complex +} >> "$DELETES" + +# (5) sort + dedupe +sort -u "$DELETES" -o "$DELETES" + +n_files=$(find "$OVERRIDES" -type f | wc -l) +n_dels=$(wc -l < "$DELETES") +echo "musl-vendor: overrides=$n_files deletes=$n_dels" +echo " $OVERRIDES" +echo " $DELETES" diff --git a/scripts/stage1-flatten.sh b/scripts/stage1-flatten.sh @@ -28,7 +28,7 @@ while [ $# -gt 0 ]; do case "$1" in --arch) ARCH=$2; shift 2 ;; --verify) VERIFY=1; shift ;; - -h|--help) sed -n 's/^## \{0,1\}//p' "$0"; exit 0 ;; + -h|--help) awk '/^##/ { sub(/^## ?/, ""); print }' "$0"; exit 0 ;; *) echo "unknown arg: $1" >&2; exit 2 ;; esac done @@ -254,9 +254,8 @@ FLAT=$WORK/tcc.flat.c -D TCC_TARGET_${TCC_TARGET_DEFINE}=1 \ "$SRC/tcc.c" > "$FLAT" -LINES=$(wc -l < "$FLAT") BYTES=$(wc -c < "$FLAT") -echo "produced $FLAT ($LINES lines, $BYTES bytes)" +echo "produced $FLAT ($BYTES bytes)" # --- (4) optional verify --------------------------------------------- if [ "$VERIFY" -eq 1 ]; then @@ -265,7 +264,6 @@ if [ "$VERIFY" -eq 1 ]; then echo "host cc: tcc.flat.c compiles cleanly to $HOST_OBJ" else echo "host cc: tcc.flat.c FAILED to compile; see $WORK/host-cc.log" >&2 - head -30 "$WORK/host-cc.log" >&2 exit 1 fi fi diff --git a/vendor/upstream/musl-1.2.5-deletes.txt b/vendor/upstream/musl-1.2.5-deletes.txt @@ -0,0 +1,151 @@ +src/complex +src/complex/__cexp.c +src/complex/__cexpf.c +src/complex/cabs.c +src/complex/cabsf.c +src/complex/cabsl.c +src/complex/cacos.c +src/complex/cacosf.c +src/complex/cacosh.c +src/complex/cacoshf.c +src/complex/cacoshl.c +src/complex/cacosl.c +src/complex/carg.c +src/complex/cargf.c +src/complex/cargl.c +src/complex/casin.c +src/complex/casinf.c +src/complex/casinh.c +src/complex/casinhf.c +src/complex/casinhl.c +src/complex/casinl.c +src/complex/catan.c +src/complex/catanf.c +src/complex/catanh.c +src/complex/catanhf.c +src/complex/catanhl.c +src/complex/catanl.c +src/complex/ccos.c +src/complex/ccosf.c +src/complex/ccosh.c +src/complex/ccoshf.c +src/complex/ccoshl.c +src/complex/ccosl.c +src/complex/cexp.c +src/complex/cexpf.c +src/complex/cexpl.c +src/complex/cimag.c +src/complex/cimagf.c +src/complex/cimagl.c +src/complex/clog.c +src/complex/clogf.c +src/complex/clogl.c +src/complex/conj.c +src/complex/conjf.c +src/complex/conjl.c +src/complex/cpow.c +src/complex/cpowf.c +src/complex/cpowl.c +src/complex/cproj.c +src/complex/cprojf.c +src/complex/cprojl.c +src/complex/creal.c +src/complex/crealf.c +src/complex/creall.c +src/complex/csin.c +src/complex/csinf.c +src/complex/csinh.c +src/complex/csinhf.c +src/complex/csinhl.c +src/complex/csinl.c +src/complex/csqrt.c +src/complex/csqrtf.c +src/complex/csqrtl.c +src/complex/ctan.c +src/complex/ctanf.c +src/complex/ctanh.c +src/complex/ctanhf.c +src/complex/ctanhl.c +src/complex/ctanl.c +src/fenv/aarch64/fenv.s +src/fenv/riscv64/fenv-sf.c +src/fenv/riscv64/fenv.S +src/fenv/x86_64/fenv.s +src/math/aarch64/ceil.c +src/math/aarch64/ceilf.c +src/math/aarch64/fabs.c +src/math/aarch64/fabsf.c +src/math/aarch64/floor.c +src/math/aarch64/floorf.c +src/math/aarch64/fma.c +src/math/aarch64/fmaf.c +src/math/aarch64/fmax.c +src/math/aarch64/fmaxf.c +src/math/aarch64/fmin.c +src/math/aarch64/fminf.c +src/math/aarch64/llrint.c +src/math/aarch64/llrintf.c +src/math/aarch64/llround.c +src/math/aarch64/llroundf.c +src/math/aarch64/lrint.c +src/math/aarch64/lrintf.c +src/math/aarch64/lround.c +src/math/aarch64/lroundf.c +src/math/aarch64/nearbyint.c +src/math/aarch64/nearbyintf.c +src/math/aarch64/rint.c +src/math/aarch64/rintf.c +src/math/aarch64/round.c +src/math/aarch64/roundf.c +src/math/aarch64/sqrt.c +src/math/aarch64/sqrtf.c +src/math/aarch64/trunc.c +src/math/aarch64/truncf.c +src/math/riscv64/copysign.c +src/math/riscv64/copysignf.c +src/math/riscv64/fabs.c +src/math/riscv64/fabsf.c +src/math/riscv64/fma.c +src/math/riscv64/fmaf.c +src/math/riscv64/fmax.c +src/math/riscv64/fmaxf.c +src/math/riscv64/fmin.c +src/math/riscv64/fminf.c +src/math/riscv64/sqrt.c +src/math/riscv64/sqrtf.c +src/math/x86_64/expl.s +src/math/x86_64/fabs.c +src/math/x86_64/fabsf.c +src/math/x86_64/fabsl.c +src/math/x86_64/fma.c +src/math/x86_64/fmaf.c +src/math/x86_64/fmodl.c +src/math/x86_64/llrint.c +src/math/x86_64/llrintf.c +src/math/x86_64/llrintl.c +src/math/x86_64/lrint.c +src/math/x86_64/lrintf.c +src/math/x86_64/lrintl.c +src/math/x86_64/remainderl.c +src/math/x86_64/remquol.c +src/math/x86_64/rintl.c +src/math/x86_64/sqrt.c +src/math/x86_64/sqrtf.c +src/math/x86_64/sqrtl.c +src/process/riscv64/vfork.s +src/setjmp/aarch64/longjmp.s +src/setjmp/aarch64/setjmp.s +src/setjmp/riscv64/longjmp.S +src/setjmp/riscv64/setjmp.S +src/signal/aarch64/sigsetjmp.s +src/signal/riscv64/restore.s +src/signal/riscv64/sigsetjmp.s +src/signal/x86_64/sigsetjmp.s +src/string/aarch64/memcpy.S +src/string/aarch64/memset.S +src/thread/aarch64/__unmapself.s +src/thread/aarch64/clone.s +src/thread/aarch64/syscall_cp.s +src/thread/riscv64/__unmapself.s +src/thread/riscv64/clone.s +src/thread/riscv64/syscall_cp.s diff --git a/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/atomic_arch.h b/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/atomic_arch.h @@ -0,0 +1,28 @@ +/* tcc-build aarch64 atomic_arch.h replacement. + * + * Stock musl's atomic primitives are inline asm with output operands + * (LL/SC pairs and the `dmb ish` named option), none of which + * arm64-asm.c phase 1+2 handles. We can't decompose into separate + * extern a_ll / a_sc — function-call boundaries between ldaxr and + * stlxr clear the exclusive monitor on real hardware (and on + * QEMU/Apple Silicon), making the LL/SC retry loop deadloop. + * + * Provide a_cas (32-bit) and a_cas_p (64-bit, since aarch64 pointers + * are 64-bit) as single-function externs implemented in + * src/internal/aarch64/atomic.s; the LL/SC pair lives inside one + * call. musl's src/internal/atomic.h derives a_swap, a_fetch_add, + * a_or, a_and, a_inc, a_dec, a_store and friends from a_cas. + * + * Phase 3 of arm64-asm.c will let us inline these. */ + +extern int a_cas (volatile int *, int, int); +extern void *a_cas_p (volatile void *, void *, void *); +extern void a_barrier(void); +extern int a_ctz_64 (unsigned long long); +extern int a_clz_64 (unsigned long long); + +#define a_cas a_cas +#define a_cas_p a_cas_p +#define a_barrier a_barrier +#define a_ctz_64 a_ctz_64 +#define a_clz_64 a_clz_64 diff --git a/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/crt_arch.h b/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/crt_arch.h @@ -0,0 +1,36 @@ +/* tcc-build aarch64 crt_arch.h replacement. + * + * Three things stock musl does that we can't: + * + * 1. `adrp x1, _DYNAMIC` + `add x1, x1, #:lo12:_DYNAMIC` to pass + * _DYNAMIC's address. arm64-asm.c phase 1+2 has neither the + * `adrp` mnemonic nor the `:lo12:` ELF reloc syntax, and boot4 + * only links static binaries (no _DYNAMIC) anyway. _start_c + * ignores its second argument; just don't pass it. + * + * 2. `and sp, x0, #-16` to align the stack. Phase 2's `bic` rejects + * the bitmask-immediate form ("invert form requires a register"). + * Linux/AAPCS already guarantees a 16-byte-aligned sp at process + * entry, so the realignment is defensive only. + * + * 3. `mov x29, #0` / `mov x30, #0` / `mov x1, #0` — phase 1 emits + * these as the 32-bit MOVZ form (sf=0), leaving the upper 32 + * bits of the X register at their entry value. Subsequent code + * treats x29 as a frame-pointer chain anchor; non-zero high bits + * crash on the first `stp x29, x30, [...]`. The Linux kernel + * zeroes all GPRs except sp at process entry (see + * `start_thread` in arch/arm64/kernel/process.c), so omitting + * the explicit zeroing is safe — when phase 3 lands, restore + * the zeroing for defense-in-depth. + * + * What's left is the minimum kernel-to-userland glue: pass sp to + * _start_c so it can read argc/argv/envp/auxv, then jump. + */ +__asm__( +".text \n" +".global " START "\n" +".type " START ",%function\n" +START ":\n" +" mov x0, sp\n" +" b " START "_c\n" +); diff --git a/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/pthread_arch.h b/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/pthread_arch.h @@ -0,0 +1,14 @@ +/* tcc-build aarch64 pthread_arch.h replacement. + * + * Stock musl emits `mrs %0, tpidr_el0` as inline asm with output + * operand. tcc 0.9.26's arm64-asm.c phase 1+2 has no operand + * constraint plumbing, so route through extern __get_tp implemented + * in src/internal/aarch64/get_tp.s. Single-instruction overhead; + * inlining is recovered by phase 3 once it lands. */ + +extern unsigned long __get_tp(void); + +#define TLS_ABOVE_TP +#define GAP_ABOVE_TP 16 + +#define MC_PC pc diff --git a/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/syscall_arch.h b/vendor/upstream/musl-1.2.5-overrides/arch/aarch64/syscall_arch.h @@ -0,0 +1,55 @@ +/* tcc-build aarch64 syscall_arch.h replacement. + * + * Stock musl uses GCC register-asm-variable inline asm + * (`register long x8 __asm__("x8") = n; ... svc 0`); tcc 0.9.26 lacks + * that GCC extension and arm64-asm.c phase 1+2 has no inline-asm + * operand constraint plumbing. Route every __syscallN through one + * variadic-style trampoline implemented in pure asm + * (src/internal/aarch64/syscall.s); the trampoline shuffles C-ABI + * x0-x6 into kernel-ABI x8 + x0-x5 and issues svc #0. + * + * The wrappers are static __inline functions, not macros — musl's + * src/internal/syscall.h defines `#define __syscall1(n,a) __syscall1(n,__scc(a))` + * which would defeat a macro-form wrapper (CPP self-reference rule + * leaves the call unexpanded, producing an unresolved __syscall1 + * symbol). With static functions, syscall.h's macro applies __scc(), + * then the rescan resolves to the static function. + * + * Mirrors the x86_64 trampoline strategy. */ + +#define __SYSCALL_LL_E(x) (x) +#define __SYSCALL_LL_O(x) (x) + +extern long __syscall(long, ...); + +static __inline long __syscall0(long n) +{ + return __syscall(n); +} +static __inline long __syscall1(long n, long a) +{ + return __syscall(n, a); +} +static __inline long __syscall2(long n, long a, long b) +{ + return __syscall(n, a, b); +} +static __inline long __syscall3(long n, long a, long b, long c) +{ + return __syscall(n, a, b, c); +} +static __inline long __syscall4(long n, long a, long b, long c, long d) +{ + return __syscall(n, a, b, c, d); +} +static __inline long __syscall5(long n, long a, long b, long c, long d, long e) +{ + return __syscall(n, a, b, c, d, e); +} +static __inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) +{ + return __syscall(n, a, b, c, d, e, f); +} + +#define SYSCALL_FADVISE_6_ARG +#define SYSCALL_IPC_BROKEN_MODE diff --git a/vendor/upstream/musl-1.2.5-overrides/arch/x86_64/syscall_arch.h b/vendor/upstream/musl-1.2.5-overrides/arch/x86_64/syscall_arch.h @@ -0,0 +1,50 @@ +#define __SYSCALL_LL_E(x) (x) +#define __SYSCALL_LL_O(x) (x) + +/* tcc-friendly: avoid GCC register-asm-variable extension and + x86 inline-asm constraints by routing every syscall through a + pure-asm trampoline (src/internal/x86_64/syscall.s). */ +extern long __syscall(long, ...); + +static __inline long __syscall0(long n) +{ + return __syscall(n); +} + +static __inline long __syscall1(long n, long a1) +{ + return __syscall(n, a1); +} + +static __inline long __syscall2(long n, long a1, long a2) +{ + return __syscall(n, a1, a2); +} + +static __inline long __syscall3(long n, long a1, long a2, long a3) +{ + return __syscall(n, a1, a2, a3); +} + +static __inline long __syscall4(long n, long a1, long a2, long a3, long a4) +{ + return __syscall(n, a1, a2, a3, a4); +} + +static __inline long __syscall5(long n, long a1, long a2, long a3, long a4, long a5) +{ + return __syscall(n, a1, a2, a3, a4, a5); +} + +static __inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) +{ + return __syscall(n, a1, a2, a3, a4, a5, a6); +} + +#define VDSO_USEFUL +#define VDSO_CGT_SYM "__vdso_clock_gettime" +#define VDSO_CGT_VER "LINUX_2.6" +#define VDSO_GETCPU_SYM "__vdso_getcpu" +#define VDSO_GETCPU_VER "LINUX_2.6" + +#define IPC_64 0 diff --git a/vendor/upstream/musl-1.2.5-overrides/include/complex.h b/vendor/upstream/musl-1.2.5-overrides/include/complex.h @@ -0,0 +1,10 @@ +#ifndef _COMPLEX_H +#define _COMPLEX_H + +/* tcc-build stub: tcc does not implement C99 _Complex. + This libc was built with complex disabled; the header is empty so + non-complex code can still transitively include it (e.g. <tgmath.h>). + Any direct use of complex types or functions will fail at compile or + link time. */ + +#endif diff --git a/vendor/upstream/musl-1.2.5-overrides/src/include/features.h b/vendor/upstream/musl-1.2.5-overrides/src/include/features.h @@ -0,0 +1,15 @@ +#ifndef FEATURES_H +#define FEATURES_H + +#include "../../include/features.h" + +#define weak __attribute__((__weak__)) +#define hidden __attribute__((__visibility__("hidden"))) +/* tcc-build: tcc silently ignores __attribute__((alias(...))), leaving + every weak_alias target undefined. Emit the alias as raw assembly + directives, plus a plain extern decl so callers see a prototype. */ +#define weak_alias(old, new) \ + extern __typeof(old) new; \ + __asm__(".weak " #new "\n.set " #new "," #old) + +#endif diff --git a/vendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/atomic.s b/vendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/atomic.s @@ -0,0 +1,97 @@ +/* tcc-build aarch64 atomic primitives. + * + * Stock musl's atomic primitives are inline asm with output operands + * (LL/SC pairs and `dmb ish` named-option), unsupported by + * arm64-asm.c phase 1+2. We can't decompose into separate extern + * a_ll/a_sc — function-call boundaries between ldaxr and stlxr clear + * the exclusive monitor on real hardware (and on QEMU/Apple Silicon), + * making the LL/SC retry loop deadloop. So provide a_cas / a_cas_p as + * single asm functions whose LL/SC pair lives inside one call. + * + * Two arm64-asm.c phase-2 quirks shape the layout below: + * 1. Forward `b.cond` / `cbz` / `cbnz` to a same-file label emits + * `CONDBR19 reloc (unsupported)`. + * 2. Forward unconditional `b` to a same-file label silently + * assembles as `b +0` (branch-to-self) — no error, but the + * function turns into an infinite loop. + * Backward branches resolve correctly (offset known at emit time); + * branches to external symbols (e.g. `bl __syscall`) go through + * JUMP26/CALL26 relocations which arm64-link.c handles. So the trick + * is: define each function's "exit" block BEFORE the function entry, + * so every conditional branch out of the loop is backward, and the + * tail unconditional `b` is also backward. + * + * Mnemonics ldaxr, stlxr, dmb, rbit, clz are outside arm64-asm.c + * phase 1+2; emit them as raw .long words. Phase 1+2 covers cmp, + * b.cond (backward only), cbnz (backward), mov, ret, b (backward to + * same-file or any-direction to extern). + * + * Encoding cheat sheet: + * 0x885FFC03 ldaxr w3, [x0] + * 0xC85FFC03 ldaxr x3, [x0] + * 0x8804FC02 stlxr w4, w2, [x0] + * 0xC804FC02 stlxr w4, x2, [x0] + * 0xD5033BBF dmb ish + * 0xDAC00000 rbit x0, x0 + * 0xDAC01000 clz x0, x0 + * + * Note: tcc treats `.word` as 2 bytes; use `.long` for 4. */ + +.text + +/* Exit blocks defined first so a_cas / a_cas_p only emit BACKWARD + * branches. Not part of any function — only entered via the backward + * b.ne / b inside their respective functions below. */ +.Lcas_done: + .long 0xD5033BBF /* dmb ish */ + mov w0, w3 /* return old (32-bit) */ + ret + +.Lcasp_done: + .long 0xD5033BBF /* dmb ish */ + mov x0, x3 /* return old (64-bit) */ + ret + +/* int a_cas(volatile int *p, int t, int s) — 32-bit CAS. */ +.global a_cas +.type a_cas,@function +a_cas: + .long 0x885FFC03 /* ldaxr w3, [x0] : old = *p, mark exclusive */ + cmp w3, w1 /* old == t ? */ + b.ne .Lcas_done /* backward — OK */ + .long 0x8804FC02 /* stlxr w4, w2, [x0]: try *p = s, w4 = status */ + cbnz w4, a_cas /* backward — failed, retry from a_cas entry */ + b .Lcas_done /* backward — succeeded */ + +/* void *a_cas_p(volatile void *p, void *t, void *s) — 64-bit CAS. */ +.global a_cas_p +.type a_cas_p,@function +a_cas_p: + .long 0xC85FFC03 /* ldaxr x3, [x0] */ + cmp x3, x1 + b.ne .Lcasp_done + .long 0xC804FC02 /* stlxr w4, x2, [x0] */ + cbnz w4, a_cas_p + b .Lcasp_done + +/* void a_barrier(void) — dmb ish */ +.global a_barrier +.type a_barrier,@function +a_barrier: + .long 0xD5033BBF + ret + +/* int a_ctz_64(uint64_t x) — count trailing zeros: rbit + clz. */ +.global a_ctz_64 +.type a_ctz_64,@function +a_ctz_64: + .long 0xDAC00000 /* rbit x0, x0 */ + .long 0xDAC01000 /* clz x0, x0 */ + ret + +/* int a_clz_64(uint64_t x) */ +.global a_clz_64 +.type a_clz_64,@function +a_clz_64: + .long 0xDAC01000 + ret diff --git a/vendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/get_tp.s b/vendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/get_tp.s @@ -0,0 +1,17 @@ +/* tcc-build aarch64 thread-pointer reader. + * + * Reads tpidr_el0 into x0 and returns. Stock musl's pthread_arch.h + * uses `__asm__ ("mrs %0, tpidr_el0" : "=r"(tp))`; the inline-asm + * operand syntax is unsupported by tcc 0.9.26's arm64-asm.c (phase 3, + * not yet started). The mrs mnemonic itself is also outside phase 1+2, + * so emit raw bytes: + * + * d53bd040 mrs x0, tpidr_el0 (op0=3 op1=3 CRn=13 CRm=0 op2=2 Rt=0) + * d65f03c0 ret (encoded by phase-1 `ret`) + */ + +.global __get_tp +.type __get_tp,@function +__get_tp: + .long 0xd53bd040 + ret diff --git a/vendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/syscall.s b/vendor/upstream/musl-1.2.5-overrides/src/internal/aarch64/syscall.s @@ -0,0 +1,22 @@ +/* tcc-build aarch64 syscall trampoline. + * + * Mirrors src/internal/x86_64/syscall.s. C-ABI passes the syscall + * number in x0 and arguments in x1-x6; Linux aarch64 syscall ABI + * wants the number in x8 and arguments in x0-x5. Shuffle and svc. + * Return value is already in x0 from the kernel side. + * + * Mnemonics here are all in arm64-asm.c phase 1 (mov reg-reg, svc, + * ret). */ + +.global __syscall +.type __syscall,@function +__syscall: + mov x8, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + mov x3, x4 + mov x4, x5 + mov x5, x6 + svc #0 + ret diff --git a/vendor/upstream/musl-1.2.5-overrides/src/internal/syscall.h b/vendor/upstream/musl-1.2.5-overrides/src/internal/syscall.h @@ -0,0 +1,413 @@ +#ifndef _INTERNAL_SYSCALL_H +#define _INTERNAL_SYSCALL_H + +#include <features.h> +#include <errno.h> +#include <sys/syscall.h> +#include "syscall_arch.h" + +#ifndef SYSCALL_RLIM_INFINITY +#define SYSCALL_RLIM_INFINITY (~0ULL) +#endif + +#ifndef SYSCALL_MMAP2_UNIT +#define SYSCALL_MMAP2_UNIT 4096ULL +#endif + +#ifndef __SYSCALL_LL_PRW +#define __SYSCALL_LL_PRW(x) __SYSCALL_LL_O(x) +#endif + +#ifndef __scc +#define __scc(X) ((long) (X)) +typedef long syscall_arg_t; +#endif + +hidden long __syscall_ret(unsigned long), + __syscall_cp(syscall_arg_t, syscall_arg_t, syscall_arg_t, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t); + +#define __syscall1(n,a) __syscall1(n,__scc(a)) +#define __syscall2(n,a,b) __syscall2(n,__scc(a),__scc(b)) +#define __syscall3(n,a,b,c) __syscall3(n,__scc(a),__scc(b),__scc(c)) +#define __syscall4(n,a,b,c,d) __syscall4(n,__scc(a),__scc(b),__scc(c),__scc(d)) +#define __syscall5(n,a,b,c,d,e) __syscall5(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e)) +#define __syscall6(n,a,b,c,d,e,f) __syscall6(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) +#define __syscall7(n,a,b,c,d,e,f,g) __syscall7(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f),__scc(g)) + +#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +#define __SYSCALL_NARGS(...) __SYSCALL_NARGS_X(__VA_ARGS__,7,6,5,4,3,2,1,0,) +#define __SYSCALL_CONCAT_X(a,b) a##b +#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X(a,b) +#define __SYSCALL_DISP(b,...) __SYSCALL_CONCAT(b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define __syscall(...) __SYSCALL_DISP(__syscall,__VA_ARGS__) +#define syscall(...) __syscall_ret(__syscall(__VA_ARGS__)) + +#define socketcall(nm,a,b,c,d,e,f) __syscall_ret(__socketcall(nm,a,b,c,d,e,f)) +#define socketcall_cp(nm,a,b,c,d,e,f) __syscall_ret(__socketcall_cp(nm,a,b,c,d,e,f)) + +#define __syscall_cp0(n) (__syscall_cp)(n,0,0,0,0,0,0) +#define __syscall_cp1(n,a) (__syscall_cp)(n,__scc(a),0,0,0,0,0) +#define __syscall_cp2(n,a,b) (__syscall_cp)(n,__scc(a),__scc(b),0,0,0,0) +#define __syscall_cp3(n,a,b,c) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),0,0,0) +#define __syscall_cp4(n,a,b,c,d) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),0,0) +#define __syscall_cp5(n,a,b,c,d,e) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),0) +#define __syscall_cp6(n,a,b,c,d,e,f) (__syscall_cp)(n,__scc(a),__scc(b),__scc(c),__scc(d),__scc(e),__scc(f)) + +#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__) +#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__)) + +static inline long __alt_socketcall(int sys, int sock, int cp, syscall_arg_t a, syscall_arg_t b, syscall_arg_t c, syscall_arg_t d, syscall_arg_t e, syscall_arg_t f) +{ + long r; + if (cp) r = __syscall_cp(sys, a, b, c, d, e, f); + else r = __syscall(sys, a, b, c, d, e, f); + if (r != -ENOSYS) return r; +#ifdef SYS_socketcall + if (cp) r = __syscall_cp(SYS_socketcall, sock, ((long[6]){a, b, c, d, e, f})); + else r = __syscall(SYS_socketcall, sock, ((long[6]){a, b, c, d, e, f})); +#endif + return r; +} +#define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \ + __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) +#define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \ + __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) + +/* fixup legacy 16-bit junk */ + +#ifdef SYS_getuid32 +#undef SYS_lchown +#undef SYS_getuid +#undef SYS_getgid +#undef SYS_geteuid +#undef SYS_getegid +#undef SYS_setreuid +#undef SYS_setregid +#undef SYS_getgroups +#undef SYS_setgroups +#undef SYS_fchown +#undef SYS_setresuid +#undef SYS_getresuid +#undef SYS_setresgid +#undef SYS_getresgid +#undef SYS_chown +#undef SYS_setuid +#undef SYS_setgid +#undef SYS_setfsuid +#undef SYS_setfsgid +#define SYS_lchown SYS_lchown32 +#define SYS_getuid SYS_getuid32 +#define SYS_getgid SYS_getgid32 +#define SYS_geteuid SYS_geteuid32 +#define SYS_getegid SYS_getegid32 +#define SYS_setreuid SYS_setreuid32 +#define SYS_setregid SYS_setregid32 +#define SYS_getgroups SYS_getgroups32 +#define SYS_setgroups SYS_setgroups32 +#define SYS_fchown SYS_fchown32 +#define SYS_setresuid SYS_setresuid32 +#define SYS_getresuid SYS_getresuid32 +#define SYS_setresgid SYS_setresgid32 +#define SYS_getresgid SYS_getresgid32 +#define SYS_chown SYS_chown32 +#define SYS_setuid SYS_setuid32 +#define SYS_setgid SYS_setgid32 +#define SYS_setfsuid SYS_setfsuid32 +#define SYS_setfsgid SYS_setfsgid32 +#endif + + +/* fixup legacy 32-bit-vs-lfs64 junk */ + +#ifdef SYS_fcntl64 +#undef SYS_fcntl +#define SYS_fcntl SYS_fcntl64 +#endif + +#ifdef SYS_getdents64 +#undef SYS_getdents +#define SYS_getdents SYS_getdents64 +#endif + +#ifdef SYS_ftruncate64 +#undef SYS_ftruncate +#undef SYS_truncate +#define SYS_ftruncate SYS_ftruncate64 +#define SYS_truncate SYS_truncate64 +#endif + +#ifdef SYS_stat64 +#undef SYS_stat +#define SYS_stat SYS_stat64 +#endif + +#ifdef SYS_fstat64 +#undef SYS_fstat +#define SYS_fstat SYS_fstat64 +#endif + +#ifdef SYS_lstat64 +#undef SYS_lstat +#define SYS_lstat SYS_lstat64 +#endif + +#ifdef SYS_statfs64 +#undef SYS_statfs +#define SYS_statfs SYS_statfs64 +#endif + +#ifdef SYS_fstatfs64 +#undef SYS_fstatfs +#define SYS_fstatfs SYS_fstatfs64 +#endif + +#if defined(SYS_newfstatat) +#undef SYS_fstatat +#define SYS_fstatat SYS_newfstatat +#elif defined(SYS_fstatat64) +#undef SYS_fstatat +#define SYS_fstatat SYS_fstatat64 +#endif + +#ifdef SYS_ugetrlimit +#undef SYS_getrlimit +#define SYS_getrlimit SYS_ugetrlimit +#endif + +#ifdef SYS__newselect +#undef SYS_select +#define SYS_select SYS__newselect +#endif + +#ifdef SYS_pread64 +#undef SYS_pread +#undef SYS_pwrite +#define SYS_pread SYS_pread64 +#define SYS_pwrite SYS_pwrite64 +#endif + +#ifdef SYS_fadvise64_64 +#undef SYS_fadvise +#define SYS_fadvise SYS_fadvise64_64 +#elif defined(SYS_fadvise64) +#undef SYS_fadvise +#define SYS_fadvise SYS_fadvise64 +#endif + +#ifdef SYS_sendfile64 +#undef SYS_sendfile +#define SYS_sendfile SYS_sendfile64 +#endif + +#ifdef SYS_timer_settime32 +#define SYS_timer_settime SYS_timer_settime32 +#endif + +#ifdef SYS_timer_gettime32 +#define SYS_timer_gettime SYS_timer_gettime32 +#endif + +#ifdef SYS_timerfd_settime32 +#define SYS_timerfd_settime SYS_timerfd_settime32 +#endif + +#ifdef SYS_timerfd_gettime32 +#define SYS_timerfd_gettime SYS_timerfd_gettime32 +#endif + +#ifdef SYS_clock_settime32 +#define SYS_clock_settime SYS_clock_settime32 +#endif + +#ifdef SYS_clock_gettime32 +#define SYS_clock_gettime SYS_clock_gettime32 +#endif + +#ifdef SYS_clock_getres_time32 +#define SYS_clock_getres SYS_clock_getres_time32 +#endif + +#ifdef SYS_clock_nanosleep_time32 +#define SYS_clock_nanosleep SYS_clock_nanosleep_time32 +#endif + +#ifdef SYS_gettimeofday_time32 +#define SYS_gettimeofday SYS_gettimeofday_time32 +#endif + +#ifdef SYS_settimeofday_time32 +#define SYS_settimeofday SYS_settimeofday_time32 +#endif + +/* Ensure that the plain syscall names are defined even for "time64-only" + * archs. These facilitate callers passing null time arguments, and make + * tests for establishing which to use/fallback-to more consistent when + * they do need to be called with time arguments. */ + +#ifndef SYS_clock_gettime +#define SYS_clock_gettime SYS_clock_gettime64 +#endif + +#ifndef SYS_clock_settime +#define SYS_clock_settime SYS_clock_settime64 +#endif + +#ifndef SYS_clock_adjtime +#define SYS_clock_adjtime SYS_clock_adjtime64 +#endif + +#ifndef SYS_clock_getres +#define SYS_clock_getres SYS_clock_getres_time64 +#endif + +#ifndef SYS_clock_nanosleep +#define SYS_clock_nanosleep SYS_clock_nanosleep_time64 +#endif + +#ifndef SYS_timer_gettime +#define SYS_timer_gettime SYS_timer_gettime64 +#endif + +#ifndef SYS_timer_settime +#define SYS_timer_settime SYS_timer_settime64 +#endif + +#ifndef SYS_timerfd_gettime +#define SYS_timerfd_gettime SYS_timerfd_gettime64 +#endif + +#ifndef SYS_timerfd_settime +#define SYS_timerfd_settime SYS_timerfd_settime64 +#endif + +#ifndef SYS_utimensat +#define SYS_utimensat SYS_utimensat_time64 +#endif + +#ifndef SYS_pselect6 +#define SYS_pselect6 SYS_pselect6_time64 +#endif + +#ifndef SYS_ppoll +#define SYS_ppoll SYS_ppoll_time64 +#endif + +#ifndef SYS_recvmmsg +#define SYS_recvmmsg SYS_recvmmsg_time64 +#endif + +#ifndef SYS_mq_timedsend +#define SYS_mq_timedsend SYS_mq_timedsend_time64 +#endif + +#ifndef SYS_mq_timedreceive +#define SYS_mq_timedreceive SYS_mq_timedreceive_time64 +#endif + +/* SYS_semtimedop omitted because SYS_ipc may provide it */ + +#ifndef SYS_rt_sigtimedwait +#define SYS_rt_sigtimedwait SYS_rt_sigtimedwait_time64 +#endif + +#ifndef SYS_futex +#define SYS_futex SYS_futex_time64 +#endif + +#ifndef SYS_sched_rr_get_interval +#define SYS_sched_rr_get_interval SYS_sched_rr_get_interval_time64 +#endif + + + + +/* socketcall calls */ + +#define __SC_socket 1 +#define __SC_bind 2 +#define __SC_connect 3 +#define __SC_listen 4 +#define __SC_accept 5 +#define __SC_getsockname 6 +#define __SC_getpeername 7 +#define __SC_socketpair 8 +#define __SC_send 9 +#define __SC_recv 10 +#define __SC_sendto 11 +#define __SC_recvfrom 12 +#define __SC_shutdown 13 +#define __SC_setsockopt 14 +#define __SC_getsockopt 15 +#define __SC_sendmsg 16 +#define __SC_recvmsg 17 +#define __SC_accept4 18 +#define __SC_recvmmsg 19 +#define __SC_sendmmsg 20 + +/* This is valid only because all socket syscalls are made via + * socketcall, which always fills unused argument slots with zeros. */ +#ifndef SYS_accept +#define SYS_accept SYS_accept4 +#endif + +#ifndef SO_RCVTIMEO_OLD +#define SO_RCVTIMEO_OLD 20 +#endif +#ifndef SO_SNDTIMEO_OLD +#define SO_SNDTIMEO_OLD 21 +#endif + +#define SO_TIMESTAMP_OLD 29 +#define SO_TIMESTAMPNS_OLD 35 +#define SO_TIMESTAMPING_OLD 37 +#define SCM_TIMESTAMP_OLD SO_TIMESTAMP_OLD +#define SCM_TIMESTAMPNS_OLD SO_TIMESTAMPNS_OLD +#define SCM_TIMESTAMPING_OLD SO_TIMESTAMPING_OLD + +#ifndef SIOCGSTAMP_OLD +#define SIOCGSTAMP_OLD 0x8906 +#endif +#ifndef SIOCGSTAMPNS_OLD +#define SIOCGSTAMPNS_OLD 0x8907 +#endif + +#ifdef SYS_open +#define __sys_open2(x,pn,fl) __syscall2(SYS_open, pn, (fl)|O_LARGEFILE) +#define __sys_open3(x,pn,fl,mo) __syscall3(SYS_open, pn, (fl)|O_LARGEFILE, mo) +#define __sys_open_cp2(x,pn,fl) __syscall_cp2(SYS_open, pn, (fl)|O_LARGEFILE) +#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp3(SYS_open, pn, (fl)|O_LARGEFILE, mo) +#else +#define __sys_open2(x,pn,fl) __syscall3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) +#define __sys_open3(x,pn,fl,mo) __syscall4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) +#define __sys_open_cp2(x,pn,fl) __syscall_cp3(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE) +#define __sys_open_cp3(x,pn,fl,mo) __syscall_cp4(SYS_openat, AT_FDCWD, pn, (fl)|O_LARGEFILE, mo) +#endif + +#define __sys_open(...) __SYSCALL_DISP(__sys_open,,__VA_ARGS__) +#define sys_open(...) __syscall_ret(__sys_open(__VA_ARGS__)) + +#define __sys_open_cp(...) __SYSCALL_DISP(__sys_open_cp,,__VA_ARGS__) +#define sys_open_cp(...) __syscall_ret(__sys_open_cp(__VA_ARGS__)) + +#ifdef SYS_wait4 +#define __sys_wait4(a,b,c,d) __syscall(SYS_wait4,a,b,c,d) +#define __sys_wait4_cp(a,b,c,d) __syscall_cp(SYS_wait4,a,b,c,d) +#else +hidden long __emulate_wait4(int, int *, int, void *, int); +#define __sys_wait4(a,b,c,d) __emulate_wait4(a,b,c,d,0) +#define __sys_wait4_cp(a,b,c,d) __emulate_wait4(a,b,c,d,1) +#endif + +#define sys_wait4(a,b,c,d) __syscall_ret(__sys_wait4(a,b,c,d)) +#define sys_wait4_cp(a,b,c,d) __syscall_ret(__sys_wait4_cp(a,b,c,d)) + +/* tcc-build: stock tcc 0.9.27 does not parse C99 [static N] array + parameter syntax. The static qualifier here is a hint to the compiler + only; dropping it preserves identical semantics. */ +hidden void __procfdname(char __buf[15+3*sizeof(int)], unsigned); + +hidden void *__vdsosym(const char *, const char *); + +#endif diff --git a/vendor/upstream/musl-1.2.5-overrides/src/internal/x86_64/syscall.s b/vendor/upstream/musl-1.2.5-overrides/src/internal/x86_64/syscall.s @@ -0,0 +1,13 @@ +.global __syscall +.hidden __syscall +.type __syscall,@function +__syscall: + movq %rdi, %rax /* syscall number */ + movq %rsi, %rdi /* arg1 (was C arg2) */ + movq %rdx, %rsi /* arg2 (was C arg3) */ + movq %rcx, %rdx /* arg3 (was C arg4) */ + movq %r8, %r10 /* arg4 (kernel uses r10, not rcx) */ + movq %r9, %r8 /* arg5 */ + movq 8(%rsp), %r9 /* arg6 from stack */ + syscall + ret diff --git a/vendor/upstream/musl-1.2.5-overrides/src/network/lookup.h b/vendor/upstream/musl-1.2.5-overrides/src/network/lookup.h @@ -0,0 +1,55 @@ +#ifndef LOOKUP_H +#define LOOKUP_H + +#include <stdint.h> +#include <stddef.h> +#include <features.h> +#include <netinet/in.h> +#include <netdb.h> + +struct aibuf { + struct addrinfo ai; + union sa { + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } sa; + volatile int lock[1]; + short slot, ref; +}; + +struct address { + int family; + unsigned scopeid; + uint8_t addr[16]; + int sortkey; +}; + +struct service { + uint16_t port; + unsigned char proto, socktype; +}; + +#define MAXNS 3 + +struct resolvconf { + struct address ns[MAXNS]; + unsigned nns, attempts, ndots; + unsigned timeout; +}; + +/* The limit of 48 results is a non-sharp bound on the number of addresses + * that can fit in one 512-byte DNS packet full of v4 results and a second + * packet full of v6 results. Due to headers, the actual limit is lower. */ +#define MAXADDRS 48 +#define MAXSERVS 2 + +hidden int __lookup_serv(struct service buf[MAXSERVS], const char *name, int proto, int socktype, int flags); +hidden int __lookup_name(struct address buf[MAXADDRS], char canon[256], const char *name, int family, int flags); +hidden int __lookup_ipliteral(struct address buf[1], const char *name, int family); + +hidden int __get_resolv_conf(struct resolvconf *, char *, size_t); +hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *); + +hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *); + +#endif diff --git a/vendor/upstream/musl-1.2.5-overrides/src/network/lookup_ipliteral.c b/vendor/upstream/musl-1.2.5-overrides/src/network/lookup_ipliteral.c @@ -0,0 +1,55 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "lookup.h" + +int __lookup_ipliteral(struct address buf[1], const char *name, int family) +{ + struct in_addr a4; + struct in6_addr a6; + if (__inet_aton(name, &a4) > 0) { + if (family == AF_INET6) /* wrong family */ + return EAI_NODATA; + memcpy(&buf[0].addr, &a4, sizeof a4); + buf[0].family = AF_INET; + buf[0].scopeid = 0; + return 1; + } + + char tmp[64]; + char *p = strchr(name, '%'), *z; + unsigned long long scopeid = 0; + if (p && p-name < 64) { + memcpy(tmp, name, p-name); + tmp[p-name] = 0; + name = tmp; + } + + if (inet_pton(AF_INET6, name, &a6) <= 0) + return 0; + if (family == AF_INET) /* wrong family */ + return EAI_NODATA; + + memcpy(&buf[0].addr, &a6, sizeof a6); + buf[0].family = AF_INET6; + if (p) { + if (isdigit(*++p)) scopeid = strtoull(p, &z, 10); + else z = p-1; + if (*z) { + if (!IN6_IS_ADDR_LINKLOCAL(&a6) && + !IN6_IS_ADDR_MC_LINKLOCAL(&a6)) + return EAI_NONAME; + scopeid = if_nametoindex(p); + if (!scopeid) return EAI_NONAME; + } + if (scopeid > UINT_MAX) return EAI_NONAME; + } + buf[0].scopeid = scopeid; + return 1; +} diff --git a/vendor/upstream/musl-1.2.5-overrides/src/network/lookup_name.c b/vendor/upstream/musl-1.2.5-overrides/src/network/lookup_name.c @@ -0,0 +1,437 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <pthread.h> +#include <errno.h> +#include <resolv.h> +#include "lookup.h" +#include "stdio_impl.h" +#include "syscall.h" + +static int is_valid_hostname(const char *host) +{ + const unsigned char *s; + if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0; + for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++); + return !*s; +} + +static int name_from_null(struct address buf[2], const char *name, int family, int flags) +{ + int cnt = 0; + if (name) return 0; + if (flags & AI_PASSIVE) { + if (family != AF_INET6) + buf[cnt++] = (struct address){ .family = AF_INET }; + if (family != AF_INET) + buf[cnt++] = (struct address){ .family = AF_INET6 }; + } else { + if (family != AF_INET6) + buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } }; + if (family != AF_INET) + buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } }; + } + return cnt; +} + +static int name_from_numeric(struct address buf[1], const char *name, int family) +{ + return __lookup_ipliteral(buf, name, family); +} + +static int name_from_hosts(struct address buf[MAXADDRS], char canon[256], const char *name, int family) +{ + char line[512]; + size_t l = strlen(name); + int cnt = 0, badfam = 0, have_canon = 0; + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return 0; + default: + return EAI_SYSTEM; + } + while (fgets(line, sizeof line, f) && cnt < MAXADDRS) { + char *p, *z; + + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + for(p=line+1; (p=strstr(p, name)) && + (!isspace(p[-1]) || !isspace(p[l])); p++); + if (!p) continue; + + /* Isolate IP address to parse */ + for (p=line; *p && !isspace(*p); p++); + *p++ = 0; + switch (name_from_numeric(buf+cnt, line, family)) { + case 1: + cnt++; + break; + case 0: + continue; + default: + badfam = EAI_NODATA; + break; + } + + if (have_canon) continue; + + /* Extract first name as canonical name */ + for (; *p && isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + *z = 0; + if (is_valid_hostname(p)) { + have_canon = 1; + memcpy(canon, p, z-p+1); + } + } + __fclose_ca(f); + return cnt ? cnt : badfam; +} + +struct dpc_ctx { + struct address *addrs; + char *canon; + int cnt; + int rrtype; +}; + +#define RR_A 1 +#define RR_CNAME 5 +#define RR_AAAA 28 + +#define ABUF_SIZE 4800 + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen) +{ + char tmp[256]; + int family; + struct dpc_ctx *ctx = c; + if (rr == RR_CNAME) { + if (__dn_expand(packet, (const unsigned char *)packet + plen, + data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) + strcpy(ctx->canon, tmp); + return 0; + } + if (ctx->cnt >= MAXADDRS) return 0; + if (rr != ctx->rrtype) return 0; + switch (rr) { + case RR_A: + if (len != 4) return -1; + family = AF_INET; + break; + case RR_AAAA: + if (len != 16) return -1; + family = AF_INET6; + break; + } + ctx->addrs[ctx->cnt].family = family; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, len); + return 0; +} + +static int name_from_dns(struct address buf[MAXADDRS], char canon[256], const char *name, int family, const struct resolvconf *conf) +{ + unsigned char qbuf[2][280], abuf[2][ABUF_SIZE]; + const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; + unsigned char *ap[2] = { abuf[0], abuf[1] }; + int qlens[2], alens[2], qtypes[2]; + int i, nq = 0; + struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; + static const struct { int af; int rr; } afrr[2] = { + { .af = AF_INET6, .rr = RR_A }, + { .af = AF_INET, .rr = RR_AAAA }, + }; + + for (i=0; i<2; i++) { + if (family != afrr[i].af) { + qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr, + 0, 0, 0, qbuf[nq], sizeof *qbuf); + if (qlens[nq] == -1) + return 0; + qtypes[nq] = afrr[i].rr; + qbuf[nq][3] = 0; /* don't need AD flag */ + /* Ensure query IDs are distinct. */ + if (nq && qbuf[nq][0] == qbuf[0][0]) + qbuf[nq][0]++; + nq++; + } + } + + if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) + return EAI_SYSTEM; + + for (i=0; i<nq; i++) { + if (alens[i] < 4 || (abuf[i][3] & 15) == 2) return EAI_AGAIN; + if ((abuf[i][3] & 15) == 3) return 0; + if ((abuf[i][3] & 15) != 0) return EAI_FAIL; + } + + for (i=nq-1; i>=0; i--) { + ctx.rrtype = qtypes[i]; + if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i]; + __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); + } + + if (ctx.cnt) return ctx.cnt; + return EAI_NODATA; +} + +static int name_from_dns_search(struct address buf[MAXADDRS], char canon[256], const char *name, int family) +{ + char search[256]; + struct resolvconf conf; + size_t l, dots; + char *p, *z; + + if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1; + + /* Count dots, suppress search when >=ndots or name ends in + * a dot, which is an explicit request for global scope. */ + for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++; + if (dots >= conf.ndots || name[l-1]=='.') *search = 0; + + /* Strip final dot for canon, fail if multiple trailing dots. */ + if (name[l-1]=='.') l--; + if (!l || name[l-1]=='.') return EAI_NONAME; + + /* This can never happen; the caller already checked length. */ + if (l >= 256) return EAI_NONAME; + + /* Name with search domain appended is setup in canon[]. This both + * provides the desired default canonical name (if the requested + * name is not a CNAME record) and serves as a buffer for passing + * the full requested name to name_from_dns. */ + memcpy(canon, name, l); + canon[l] = '.'; + + for (p=search; *p; p=z) { + for (; isspace(*p); p++); + for (z=p; *z && !isspace(*z); z++); + if (z==p) break; + if (z-p < 256 - l - 1) { + memcpy(canon+l+1, p, z-p); + canon[z-p+1+l] = 0; + int cnt = name_from_dns(buf, canon, canon, family, &conf); + if (cnt) return cnt; + } + } + + canon[l] = 0; + return name_from_dns(buf, canon, name, family, &conf); +} + +static const struct policy { + unsigned char addr[16]; + unsigned char len, mask; + unsigned char prec, label; +} defpolicy[] = { + { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 }, + { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 }, + { "\x20\2", 1, 0xff, 30, 2 }, + { "\x20\1", 3, 0xff, 5, 5 }, + { "\xfc", 0, 0xfe, 3, 13 }, +#if 0 + /* These are deprecated and/or returned to the address + * pool, so despite the RFC, treating them as special + * is probably wrong. */ + { "", 11, 0xff, 1, 3 }, + { "\xfe\xc0", 1, 0xc0, 1, 11 }, + { "\x3f\xfe", 1, 0xff, 1, 12 }, +#endif + /* Last rule must match all addresses to stop loop. */ + { "", 0, 0, 40, 1 }, +}; + +static const struct policy *policyof(const struct in6_addr *a) +{ + int i; + for (i=0; ; i++) { + if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len)) + continue; + if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask) + != defpolicy[i].addr[defpolicy[i].len]) + continue; + return defpolicy+i; + } +} + +static int labelof(const struct in6_addr *a) +{ + return policyof(a)->label; +} + +static int scopeof(const struct in6_addr *a) +{ + if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15; + if (IN6_IS_ADDR_LINKLOCAL(a)) return 2; + if (IN6_IS_ADDR_LOOPBACK(a)) return 2; + if (IN6_IS_ADDR_SITELOCAL(a)) return 5; + return 14; +} + +static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d) +{ + /* FIXME: The common prefix length should be limited to no greater + * than the nominal length of the prefix portion of the source + * address. However the definition of the source prefix length is + * not clear and thus this limiting is not yet implemented. */ + unsigned i; + for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++); + return i; +} + +#define DAS_USABLE 0x40000000 +#define DAS_MATCHINGSCOPE 0x20000000 +#define DAS_MATCHINGLABEL 0x10000000 +#define DAS_PREC_SHIFT 20 +#define DAS_SCOPE_SHIFT 16 +#define DAS_PREFIX_SHIFT 8 +#define DAS_ORDER_SHIFT 0 + +static int addrcmp(const void *_a, const void *_b) +{ + const struct address *a = _a, *b = _b; + return b->sortkey - a->sortkey; +} + +int __lookup_name(struct address buf[MAXADDRS], char canon[256], const char *name, int family, int flags) +{ + int cnt = 0, i, j; + + *canon = 0; + if (name) { + /* reject empty name and check len so it fits into temp bufs */ + size_t l = strnlen(name, 255); + if (l-1 >= 254) + return EAI_NONAME; + memcpy(canon, name, l+1); + } + + /* Procedurally, a request for v6 addresses with the v4-mapped + * flag set is like a request for unspecified family, followed + * by filtering of the results. */ + if (flags & AI_V4MAPPED) { + if (family == AF_INET6) family = AF_UNSPEC; + else flags -= AI_V4MAPPED; + } + + /* Try each backend until there's at least one result. */ + cnt = name_from_null(buf, name, family, flags); + if (!cnt) cnt = name_from_numeric(buf, name, family); + if (!cnt && !(flags & AI_NUMERICHOST)) { + cnt = name_from_hosts(buf, canon, name, family); + if (!cnt) cnt = name_from_dns_search(buf, canon, name, family); + } + if (cnt<=0) return cnt ? cnt : EAI_NONAME; + + /* Filter/transform results for v4-mapped lookup, if requested. */ + if (flags & AI_V4MAPPED) { + if (!(flags & AI_ALL)) { + /* If any v6 results exist, remove v4 results. */ + for (i=0; i<cnt && buf[i].family != AF_INET6; i++); + if (i<cnt) { + for (j=0; i<cnt; i++) { + if (buf[i].family == AF_INET6) + buf[j++] = buf[i]; + } + cnt = i = j; + } + } + /* Translate any remaining v4 results to v6 */ + for (i=0; i<cnt; i++) { + if (buf[i].family != AF_INET) continue; + memcpy(buf[i].addr+12, buf[i].addr, 4); + memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + buf[i].family = AF_INET6; + } + } + + /* No further processing is needed if there are fewer than 2 + * results or if there are only IPv4 results. */ + if (cnt<2 || family==AF_INET) return cnt; + for (i=0; i<cnt; i++) if (buf[i].family != AF_INET) break; + if (i==cnt) return cnt; + + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + + /* The following implements a subset of RFC 3484/6724 destination + * address selection by generating a single 31-bit sort key for + * each address. Rules 3, 4, and 7 are omitted for having + * excessive runtime and code size cost and dubious benefit. + * So far the label/precedence table cannot be customized. */ + for (i=0; i<cnt; i++) { + int family = buf[i].family; + int key = 0; + struct sockaddr_in6 sa6 = { 0 }, da6 = { + .sin6_family = AF_INET6, + .sin6_scope_id = buf[i].scopeid, + .sin6_port = 65535 + }; + struct sockaddr_in sa4 = { 0 }, da4 = { + .sin_family = AF_INET, + .sin_port = 65535 + }; + void *sa, *da; + socklen_t salen, dalen; + if (family == AF_INET6) { + memcpy(da6.sin6_addr.s6_addr, buf[i].addr, 16); + da = &da6; dalen = sizeof da6; + sa = &sa6; salen = sizeof sa6; + } else { + memcpy(sa6.sin6_addr.s6_addr, + "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4); + memcpy(da6.sin6_addr.s6_addr, + "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12); + memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4); + memcpy(&da4.sin_addr, buf[i].addr, 4); + da = &da4; dalen = sizeof da4; + sa = &sa4; salen = sizeof sa4; + } + const struct policy *dpolicy = policyof(&da6.sin6_addr); + int dscope = scopeof(&da6.sin6_addr); + int dlabel = dpolicy->label; + int dprec = dpolicy->prec; + int prefixlen = 0; + int fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP); + if (fd >= 0) { + if (!connect(fd, da, dalen)) { + key |= DAS_USABLE; + if (!getsockname(fd, sa, &salen)) { + if (family == AF_INET) memcpy( + sa6.sin6_addr.s6_addr+12, + &sa4.sin_addr, 4); + if (dscope == scopeof(&sa6.sin6_addr)) + key |= DAS_MATCHINGSCOPE; + if (dlabel == labelof(&sa6.sin6_addr)) + key |= DAS_MATCHINGLABEL; + prefixlen = prefixmatch(&sa6.sin6_addr, + &da6.sin6_addr); + } + } + close(fd); + } + key |= dprec << DAS_PREC_SHIFT; + key |= (15-dscope) << DAS_SCOPE_SHIFT; + key |= prefixlen << DAS_PREFIX_SHIFT; + key |= (MAXADDRS-i) << DAS_ORDER_SHIFT; + buf[i].sortkey = key; + } + qsort(buf, cnt, sizeof *buf, addrcmp); + + pthread_setcancelstate(cs, 0); + + return cnt; +} diff --git a/vendor/upstream/musl-1.2.5-overrides/src/network/lookup_serv.c b/vendor/upstream/musl-1.2.5-overrides/src/network/lookup_serv.c @@ -0,0 +1,114 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +#include "lookup.h" +#include "stdio_impl.h" + +int __lookup_serv(struct service buf[MAXSERVS], const char *name, int proto, int socktype, int flags) +{ + char line[128]; + int cnt = 0; + char *p, *z = ""; + unsigned long port = 0; + + switch (socktype) { + case SOCK_STREAM: + switch (proto) { + case 0: + proto = IPPROTO_TCP; + case IPPROTO_TCP: + break; + default: + return EAI_SERVICE; + } + break; + case SOCK_DGRAM: + switch (proto) { + case 0: + proto = IPPROTO_UDP; + case IPPROTO_UDP: + break; + default: + return EAI_SERVICE; + } + case 0: + break; + default: + if (name) return EAI_SERVICE; + buf[0].port = 0; + buf[0].proto = proto; + buf[0].socktype = socktype; + return 1; + } + + if (name) { + if (!*name) return EAI_SERVICE; + port = strtoul(name, &z, 10); + } + if (!*z) { + if (port > 65535) return EAI_SERVICE; + if (proto != IPPROTO_UDP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + if (proto != IPPROTO_TCP) { + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + return cnt; + } + + if (flags & AI_NUMERICSERV) return EAI_NONAME; + + size_t l = strlen(name); + + unsigned char _buf[1032]; + FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf); + if (!f) switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + return EAI_SERVICE; + default: + return EAI_SYSTEM; + } + + while (fgets(line, sizeof line, f) && cnt < MAXSERVS) { + if ((p=strchr(line, '#'))) *p++='\n', *p=0; + + /* Find service name */ + for(p=line; (p=strstr(p, name)); p++) { + if (p>line && !isspace(p[-1])) continue; + if (p[l] && !isspace(p[l])) continue; + break; + } + if (!p) continue; + + /* Skip past canonical name at beginning of line */ + for (p=line; *p && !isspace(*p); p++); + + port = strtoul(p, &z, 10); + if (port > 65535 || z==p) continue; + if (!strncmp(z, "/udp", 4)) { + if (proto == IPPROTO_TCP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_DGRAM; + buf[cnt++].proto = IPPROTO_UDP; + } + if (!strncmp(z, "/tcp", 4)) { + if (proto == IPPROTO_UDP) continue; + buf[cnt].port = port; + buf[cnt].socktype = SOCK_STREAM; + buf[cnt++].proto = IPPROTO_TCP; + } + } + __fclose_ca(f); + return cnt > 0 ? cnt : EAI_SERVICE; +} diff --git a/vendor/upstream/musl-1.2.5-overrides/src/thread/aarch64/__set_thread_area.s b/vendor/upstream/musl-1.2.5-overrides/src/thread/aarch64/__set_thread_area.s @@ -0,0 +1,23 @@ +/* tcc-build aarch64 __set_thread_area. + * + * Sets the EL0 thread pointer (TPIDR_EL0) to x0 and returns 0. + * Stock musl writes `msr tpidr_el0, x0` as a plain mnemonic; the + * `msr` system-register move is outside arm64-asm.c phase 1+2, so + * we emit the encoding as a raw word. + * + * d51bd040 msr tpidr_el0, x0 (op0=3 op1=3 CRn=13 CRm=0 op2=2 Rt=0) + * + * Without this, __init_tls's call to __set_thread_area resolves to + * an invalid address (tcc's static linker doesn't fail on undefined + * archive references), and hello segfaults inside __libc_start_main + * before main runs. + * + * Note: tcc treats `.word` as 2 bytes; use `.long` for 4. */ + +.global __set_thread_area +.hidden __set_thread_area +.type __set_thread_area,@function +__set_thread_area: + .long 0xd51bd040 + mov w0, #0 + ret