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:
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