build: static main.c (JERBOA_STATIC) + per-platform FFI symbol generation
ober
c4caee7a283bef3779a572b555fd4f0fd11001f7
--- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ secmon-agent.sha256 secmon-program.c secmon-agent.boot jerboa-stage/ + +# generated FFI symbol list (build artifact) +support/ffi-symbols.gen --- a/.jerbuild +++ b/.jerbuild @@ -3,10 +3,12 @@ (entry "bin/agent.ss") (output "secmon-agent") (libdirs "lib") -;; Statically register the linked-in jerboa-native symbols via Sforeign_symbol -;; so the (std crypto native-rust) + (std db sqlite-native) FFI calls resolve -;; in this static binary (dlsym(RTLD_DEFAULT) can't see dead-stripped archive -;; symbols). The list also forces those archive members to be linked in. -(ffi-symbols "support/ffi-symbols.list") +;; Static binary: a custom main.c sets JERBOA_STATIC=1 so the bundled std +;; modules use the linked-in jerboa-native symbols (registered below via +;; Sforeign_symbol) instead of dlopen of libjerboa_native.{so,dylib}, which +;; does not exist in a static build. The list is regenerated per-platform by +;; the Makefile (support/gen-ffi-symbols.sh) before the final link. +(main-c "support/static-main.c") +(ffi-symbols "support/ffi-symbols.gen") (rust-crates ("@bundle/jerboa-native-rs/Cargo.toml" features: "crypto,sqlite")) --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ endif LIBDIRS := --libdirs lib:$(JH)/lib JEXEC := $(JERBUILD) exec $(LIBDIRS) +NATIVE_A := $(JH)/jerboa-native-rs/target/release/libjerboa_native.a BIN := secmon-agent BIN_DIR := $(HOME)/.local/bin @@ -32,9 +33,14 @@ help: @echo " make test Run the test suite" # Standalone native binary via .jerbuild (entry bin/agent.ss -> secmon-agent). -# Cargo-builds jerboa-native (crypto+sqlite) from jerbuild's bundled crate and -# registers its FFI symbols (support/ffi-symbols.list) into the static binary. +# Two passes: the first cargo-builds jerboa-native (crypto,sqlite) into +# jerbuild's cache; we then regenerate the FFI symbol list from that archive +# (platform-correct) and relink. A static main.c sets JERBOA_STATIC=1 so the +# std modules use the registered symbols instead of dlopen. binary: + @touch support/ffi-symbols.gen + $(JERBUILD) build + sh support/gen-ffi-symbols.sh $(JERBUILD) build build: binary deleted file mode 100644 --- a/support/ffi-symbols.list +++ /dev/null @@ -1,97 +0,0 @@ -# FFI symbols statically registered via Sforeign_symbol() in the secmon-agent binary. -# One symbol per line. Consumed by .jerbuild (ffi-symbols); jerbuild registers them -# so the (std crypto native-rust) + (std db sqlite-native) FFI calls resolve in the -# static binary (dlsym(RTLD_DEFAULT) can't see dead-stripped archive symbols). -# Generated from libjerboa_native.a (features: crypto,sqlite). - -jerboa_aead_open -jerboa_aead_seal -jerboa_antidebug_check_all -jerboa_antidebug_check_breakpoint -jerboa_antidebug_check_ld_preload -jerboa_antidebug_check_tracer -jerboa_antidebug_ptrace -jerboa_antidebug_timing_check -jerboa_aproc_close -jerboa_aproc_dup -jerboa_aproc_killpg -jerboa_aproc_set_nonblock -jerboa_aproc_spawn -jerboa_aproc_spawn_pty -jerboa_aproc_wait4 -jerboa_argon2id_hash -jerboa_argon2id_verify -jerboa_chacha20_open -jerboa_chacha20_seal -jerboa_deflate -jerboa_freebsd_is_traced -jerboa_freebsd_process_count -jerboa_gunzip -jerboa_gzip -jerboa_hkdf_sha256 -jerboa_hmac_sha256 -jerboa_hmac_sha256_verify -jerboa_inflate -jerboa_integrity_hash_file -jerboa_integrity_hash_region -jerboa_integrity_hash_self -jerboa_integrity_sign_verify -jerboa_integrity_verify_hash -jerboa_kill_probe -jerboa_last_error -jerboa_md5 -jerboa_mlockall -jerboa_pbkdf2_derive -jerboa_pbkdf2_verify -jerboa_prctl_set_name -jerboa_proc_self_exe -jerboa_random_bytes -jerboa_regex_captures -jerboa_regex_compile -jerboa_regex_compile_ex -jerboa_regex_find -jerboa_regex_find_at -jerboa_regex_free -jerboa_regex_group_count -jerboa_regex_is_match -jerboa_regex_replace_all -jerboa_scrypt -jerboa_secure_alloc -jerboa_secure_free -jerboa_secure_random_fill -jerboa_secure_wipe -jerboa_setproctitle -jerboa_sha1 -jerboa_sha256 -jerboa_sha384 -jerboa_sha512 -jerboa_socks5_server_port -jerboa_socks5_server_start -jerboa_socks5_server_stats -jerboa_socks5_server_stop -jerboa_sqlite_bind_blob -jerboa_sqlite_bind_double -jerboa_sqlite_bind_int -jerboa_sqlite_bind_null -jerboa_sqlite_bind_text -jerboa_sqlite_changes -jerboa_sqlite_close -jerboa_sqlite_column_blob -jerboa_sqlite_column_count -jerboa_sqlite_column_double -jerboa_sqlite_column_int -jerboa_sqlite_column_name -jerboa_sqlite_column_text -jerboa_sqlite_column_type -jerboa_sqlite_errmsg -jerboa_sqlite_exec -jerboa_sqlite_finalize -jerboa_sqlite_last_insert_rowid -jerboa_sqlite_open -jerboa_sqlite_prepare -jerboa_sqlite_reset -jerboa_sqlite_step -jerboa_timing_safe_equal -jerboa_x25519_diffie_hellman -jerboa_x25519_generate_keypair -jerboa_x25519_public_from_private new file mode 100755 --- /dev/null +++ b/support/gen-ffi-symbols.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# Regenerate support/ffi-symbols.gen from the jerboa-native archive that +# jerbuild cargo-builds into its bundle cache. Run between the two `jerbuild +# build` passes so the static binary registers exactly the jerboa_* symbols +# present for THIS platform + feature set (e.g. epoll on Linux, kqueue on +# macOS). The output is .gitignored — it is a build artifact, not source. +set -e +JH="$(jerbuild --jerboa-home 2>/dev/null)" +A="$JH/jerboa-native-rs/target/release/libjerboa_native.a" +OUT="$(dirname "$0")/ffi-symbols.gen" +if [ ! -f "$A" ]; then + echo "gen-ffi-symbols: $A not found (run 'jerbuild build' once first)" >&2 + : > "$OUT" + exit 0 +fi +{ + echo "# AUTOGENERATED by support/gen-ffi-symbols.sh from libjerboa_native.a." + echo "# jerboa-native FFI symbols registered via Sforeign_symbol() (see .jerbuild)." + echo "" + nm -gjU "$A" 2>/dev/null | sed 's/^_//' | grep -E '^jerboa_[A-Za-z0-9_]+$' | sort -u +} > "$OUT" +echo "gen-ffi-symbols: wrote $(grep -c '^jerboa_' "$OUT") symbols to $OUT"