native: export generated FFI symbols

ober

705393265c765b733ea4c0b04ec29c24195f0bc2

diff --git a/jerboa-native-rs/src/aproc.rs b/jerboa-native-rs/src/aproc.rs
index 8a7a21e..01cd7de 100644
--- a/jerboa-native-rs/src/aproc.rs
+++ b/jerboa-native-rs/src/aproc.rs
@@ -1024,6 +1024,7 @@ pub extern "C" fn jerboa_aproc_spawn_pty(
 }
 
 /// dup(2) — returns the new fd, or -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_aproc_dup(fd: i32) -> i32 {
     ffi_wrap(|| {
         // SAFETY: dup(2) validates the descriptor number; errors are surfaced
@@ -1041,6 +1042,7 @@ pub extern "C" fn jerboa_aproc_dup(fd: i32) -> i32 {
 }
 
 /// close(2) — returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_aproc_close(fd: i32) -> i32 {
     // SAFETY: close(2) validates the descriptor number. Ownership is governed
     // by the Scheme caller; this wrapper forwards the syscall result.
diff --git a/jerboa-native-rs/src/crypto.rs b/jerboa-native-rs/src/crypto.rs
index 0db968b..cef08b3 100644
--- a/jerboa-native-rs/src/crypto.rs
+++ b/jerboa-native-rs/src/crypto.rs
@@ -55,6 +55,7 @@ fn digest_impl(
     })
 }
 
+#[no_mangle]
 pub extern "C" fn jerboa_md5(
     _input: *const u8,
     _input_len: usize,
@@ -113,6 +114,7 @@ fn next_sha256_context() -> u64 {
 }
 
 /// Allocate an opaque incremental SHA-256 context handle.
+#[no_mangle]
 pub extern "C" fn jerboa_sha256_ctx_new() -> u64 {
     match std::panic::catch_unwind(|| {
         let handle = next_sha256_context();
@@ -128,6 +130,7 @@ pub extern "C" fn jerboa_sha256_ctx_new() -> u64 {
 }
 
 /// Add one chunk to an incremental SHA-256 context.
+#[no_mangle]
 pub extern "C" fn jerboa_sha256_ctx_update(handle: u64, input: *const u8, input_len: usize) -> i32 {
     ffi_wrap(|| {
         if input.is_null() && input_len > 0 {
@@ -152,6 +155,7 @@ pub extern "C" fn jerboa_sha256_ctx_update(handle: u64, input: *const u8, input_
 }
 
 /// Finalize and consume an incremental SHA-256 context.
+#[no_mangle]
 pub extern "C" fn jerboa_sha256_ctx_final(handle: u64, output: *mut u8, output_len: usize) -> i32 {
     ffi_wrap(|| {
         if output.is_null() || output_len < digest::SHA256_OUTPUT_LEN {
@@ -176,6 +180,7 @@ pub extern "C" fn jerboa_sha256_ctx_final(handle: u64, output: *mut u8, output_l
 }
 
 /// Drop an unfinished incremental SHA-256 context. Idempotent for cleanup.
+#[no_mangle]
 pub extern "C" fn jerboa_sha256_ctx_free(handle: u64) {
     let _ = std::panic::catch_unwind(|| lock_sha256_contexts().remove(&handle));
 }
diff --git a/jerboa-native-rs/src/process_ctl.rs b/jerboa-native-rs/src/process_ctl.rs
index 012af6a..658fe58 100644
--- a/jerboa-native-rs/src/process_ctl.rs
+++ b/jerboa-native-rs/src/process_ctl.rs
@@ -2,6 +2,7 @@ use crate::panic::{ffi_wrap, set_last_error};
 
 /// Set the process name via prctl(PR_SET_NAME) on Linux.
 /// name: UTF-8 bytes, max 15 bytes (will be truncated).
+#[no_mangle]
 pub extern "C" fn jerboa_prctl_set_name(name: *const u8, name_len: usize) -> i32 {
     ffi_wrap(|| {
         if name.is_null() {
@@ -36,6 +37,7 @@ pub extern "C" fn jerboa_prctl_set_name(name: *const u8, name_len: usize) -> i32
 }
 
 /// Lock all current and future memory pages (prevent swapping).
+#[no_mangle]
 pub extern "C" fn jerboa_mlockall() -> i32 {
     ffi_wrap(|| {
         #[cfg(any(target_os = "linux", target_os = "freebsd"))]
@@ -59,6 +61,7 @@ pub extern "C" fn jerboa_mlockall() -> i32 {
 
 /// Probe whether a process exists using kill(pid, 0).
 /// Returns: 1 = exists, 0 = does not exist, -1 = error.
+#[no_mangle]
 pub extern "C" fn jerboa_kill_probe(pid: u32) -> i32 {
     ffi_wrap(|| {
         // SAFETY: kill(pid, 0) performs permission/existence probing without
@@ -103,6 +106,7 @@ fn errno() -> i32 {
 /// Check if the current process is being traced (debugged) on FreeBSD.
 /// Uses sysctl kern.proc.pid to read kinfo_proc and check ki_flag for P_TRACED.
 /// Returns: 1 = traced, 0 = not traced, -1 = error.
+#[no_mangle]
 pub extern "C" fn jerboa_freebsd_is_traced() -> i32 {
     ffi_wrap(|| {
         #[cfg(target_os = "freebsd")]
@@ -150,6 +154,7 @@ pub extern "C" fn jerboa_freebsd_is_traced() -> i32 {
 
 /// Count total number of processes on FreeBSD via sysctl kern.proc.all.
 /// Returns the count, or -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_freebsd_process_count() -> i32 {
     ffi_wrap(|| {
         #[cfg(target_os = "freebsd")]
@@ -191,6 +196,7 @@ pub extern "C" fn jerboa_freebsd_process_count() -> i32 {
 /// Takes a plain string (not a format string) — we call setproctitle("%s", name).
 /// name: UTF-8 bytes, name_len: length.
 /// Returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_setproctitle(name: *const u8, name_len: usize) -> i32 {
     ffi_wrap(|| {
         if name.is_null() {
@@ -241,6 +247,7 @@ pub extern "C" fn jerboa_setproctitle(name: *const u8, name_len: usize) -> i32 {
 /// Read the path of the current executable.
 /// On Linux: /proc/self/exe
 /// On FreeBSD: sysctl KERN_PROC_PATHNAME
+#[no_mangle]
 pub extern "C" fn jerboa_proc_self_exe(
     output: *mut u8,
     output_len: usize,
diff --git a/jerboa-native-rs/src/regex_native.rs b/jerboa-native-rs/src/regex_native.rs
index bcd3a4e..dce3361 100644
--- a/jerboa-native-rs/src/regex_native.rs
+++ b/jerboa-native-rs/src/regex_native.rs
@@ -295,6 +295,7 @@ pub extern "C" fn jerboa_regex_free(handle: u64) -> i32 {
 /// Compile with PCRE2-compatible flags bitmask.
 /// Flags: 0x8=CASELESS, 0x20=DOTALL, 0x400=MULTILINE, 0x80000=UTF (ignored, always UTF-8)
 /// Returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_regex_compile_ex(
     pattern: *const u8,
     pattern_len: usize,
diff --git a/jerboa-native-rs/src/socks5_server.rs b/jerboa-native-rs/src/socks5_server.rs
index 600f3a1..468765b 100644
--- a/jerboa-native-rs/src/socks5_server.rs
+++ b/jerboa-native-rs/src/socks5_server.rs
@@ -118,6 +118,7 @@ struct ServerConfig {
 /// Returns handle (>0) on success, 0 on error.
 ///
 /// `username`/`password` pointers may be null for no-auth mode.
+#[no_mangle]
 pub extern "C" fn jerboa_socks5_server_start(
     bind_addr: *const u8,
     bind_addr_len: usize,
@@ -260,6 +261,7 @@ pub extern "C" fn jerboa_socks5_server_start(
 
 /// Stop a running SOCKS5 proxy server.
 /// Returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_socks5_server_stop(handle: u64) -> i32 {
     match std::panic::catch_unwind(|| {
         let Some(mut map) = lock_servers() else {
@@ -288,6 +290,7 @@ pub extern "C" fn jerboa_socks5_server_stop(handle: u64) -> i32 {
 
 /// Get the actual bound port of a SOCKS5 server.
 /// Returns port (>0) on success, 0 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_socks5_server_port(handle: u64) -> u16 {
     match std::panic::catch_unwind(|| {
         let Some(map) = lock_servers() else {
@@ -309,6 +312,7 @@ pub extern "C" fn jerboa_socks5_server_port(handle: u64) -> u16 {
 /// Get stats: active connections and total connections.
 /// Writes "active:N total:N" to buf.
 /// Returns bytes written (>0) or -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_socks5_server_stats(handle: u64, buf: *mut u8, buf_len: usize) -> i32 {
     match std::panic::catch_unwind(|| {
         if buf.is_null() || buf_len == 0 {
diff --git a/jerboa-native-rs/src/tls.rs b/jerboa-native-rs/src/tls.rs
index 9c381b1..fc7b267 100644
--- a/jerboa-native-rs/src/tls.rs
+++ b/jerboa-native-rs/src/tls.rs
@@ -737,6 +737,7 @@ pub extern "C" fn jerboa_tls_server_new(
 /// Create a TLS server context from in-memory PEM cert and key data.
 /// Same as jerboa_tls_server_new but reads from byte buffers instead of files.
 /// Returns context handle (>0) on success, 0 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_tls_server_new_pem(
     cert_pem: *const u8,
     cert_pem_len: usize,
@@ -869,6 +870,7 @@ pub extern "C" fn jerboa_tls_accept(server_ctx: u64, fd: i32) -> u64 {
 /// client_ca_pem: CA cert PEM bytes used to verify client certificates.
 /// Clients without a valid cert signed by this CA are rejected at the TLS handshake.
 /// Returns context handle (>0) on success, 0 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_tls_server_new_mtls_pem(
     cert_pem: *const u8,
     cert_pem_len: usize,
@@ -1285,6 +1287,7 @@ pub extern "C" fn jerboa_tls_connect_mtls(
 /// The server's cert is chain-verified against ca_pem. The client
 /// presents cert_pem/key_pem as its identity. Returns handle ID (>0) on
 /// success, 0 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_tls_connect_mtls_pem_ca(
     host: *const u8,
     host_len: usize,
@@ -1417,6 +1420,7 @@ pub extern "C" fn jerboa_tls_connect_mtls_pem_ca(
 /// mTLS connect using in-memory cert/key data (no file paths).
 /// Avoids /proc/self/fd/ which Android SELinux may block.
 /// Returns handle ID (>0) on success, 0 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_tls_connect_mtls_mem(
     host: *const u8,
     host_len: usize,
diff --git a/jerboa-native-rs/src/wasm.rs b/jerboa-native-rs/src/wasm.rs
index 44ceabe..1fd7dfb 100644
--- a/jerboa-native-rs/src/wasm.rs
+++ b/jerboa-native-rs/src/wasm.rs
@@ -306,6 +306,7 @@ pub extern "C" fn jerboa_wasm_instance_free(handle: u64) {
 ///
 /// SAFETY: `fd` must be a valid, owned UDP socket file descriptor.
 /// Returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_wasm_set_socket(instance_handle: u64, fd: i32) -> i32 {
     ffi_wrap(|| {
         let mut instances = match lock_instances() {
@@ -347,6 +348,7 @@ pub extern "C" fn jerboa_wasm_set_socket(instance_handle: u64, fd: i32) -> i32 {
 /// The WASM guest can only open CDB files under these directories.
 /// path_ptr/path_len: UTF-8 directory path.
 /// Returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_wasm_allow_cdb_dir(
     instance_handle: u64,
     path_ptr: *const u8,
diff --git a/jerboa-native-rs/src/wasm_sm.rs b/jerboa-native-rs/src/wasm_sm.rs
index 3145a42..dcf9f3c 100644
--- a/jerboa-native-rs/src/wasm_sm.rs
+++ b/jerboa-native-rs/src/wasm_sm.rs
@@ -1122,6 +1122,7 @@ pub extern "C" fn jerboa_sm_call(
 // FFI: Memory access (stubs — full impl requires persistent instance)
 // ============================================================
 
+#[no_mangle]
 pub extern "C" fn jerboa_sm_memory_read(
     _handle: u64,
     _offset: u32,
@@ -1131,6 +1132,7 @@ pub extern "C" fn jerboa_sm_memory_read(
     -1
 }
 
+#[no_mangle]
 pub extern "C" fn jerboa_sm_memory_write(
     _handle: u64,
     _offset: u32,
@@ -1140,6 +1142,7 @@ pub extern "C" fn jerboa_sm_memory_write(
     -1
 }
 
+#[no_mangle]
 pub extern "C" fn jerboa_sm_memory_size(_handle: u64) -> i64 {
     -1
 }
@@ -1153,6 +1156,7 @@ pub extern "C" fn jerboa_sm_add_fuel(_handle: u64, _fuel: u64) -> i32 {
     0
 }
 
+#[no_mangle]
 pub extern "C" fn jerboa_sm_fuel_remaining(_handle: u64) -> i64 {
     0
 }
diff --git a/jerboa-native-rs/src/x25519.rs b/jerboa-native-rs/src/x25519.rs
index f0ae1b2..d407a7f 100644
--- a/jerboa-native-rs/src/x25519.rs
+++ b/jerboa-native-rs/src/x25519.rs
@@ -6,6 +6,7 @@ use x25519_dalek::{PublicKey, StaticSecret};
 /// Generate an X25519 keypair using ring's CSPRNG.
 /// private_out: 32-byte buffer for the private key
 /// public_out: 32-byte buffer for the public key
+#[no_mangle]
 pub extern "C" fn jerboa_x25519_generate_keypair(private_out: *mut u8, public_out: *mut u8) -> i32 {
     ffi_wrap(|| {
         if private_out.is_null() || public_out.is_null() {
@@ -33,6 +34,7 @@ pub extern "C" fn jerboa_x25519_generate_keypair(private_out: *mut u8, public_ou
 /// Compute public key from a private key.
 /// private_key: 32-byte private key
 /// public_out: 32-byte buffer for the public key
+#[no_mangle]
 pub extern "C" fn jerboa_x25519_public_from_private(
     private_key: *const u8,
     private_len: usize,
@@ -62,6 +64,7 @@ pub extern "C" fn jerboa_x25519_public_from_private(
 /// our_private: 32-byte private key
 /// their_public: 32-byte public key
 /// shared_out: 32-byte buffer for the shared secret
+#[no_mangle]
 pub extern "C" fn jerboa_x25519_diffie_hellman(
     our_private: *const u8,
     priv_len: usize,
@@ -104,6 +107,7 @@ pub extern "C" fn jerboa_x25519_diffie_hellman(
 /// salt: salt bytes (can be NULL with salt_len=0 for no salt)
 /// info: context/application info
 /// output: buffer for derived key material
+#[no_mangle]
 pub extern "C" fn jerboa_hkdf_sha256(
     ikm: *const u8,
     ikm_len: usize,
diff --git a/jerboa-native-rs/src/x509.rs b/jerboa-native-rs/src/x509.rs
index 26e812a..de28fd7 100644
--- a/jerboa-native-rs/src/x509.rs
+++ b/jerboa-native-rs/src/x509.rs
@@ -350,6 +350,7 @@ pub extern "C" fn jerboa_x509_generate_self_signed(
 /// caller-provided buffers instead of files.
 ///
 /// Returns 0 on success, -1 on error.
+#[no_mangle]
 pub extern "C" fn jerboa_x509_generate_self_signed_mem(
     ip_addrs_csv: *const u8,
     ip_addrs_len: usize,
@@ -457,6 +458,7 @@ pub extern "C" fn jerboa_x509_generate_self_signed_mem(
 /// here. The lengths actually written are stored in cert_out_len / key_out_len.
 ///
 /// Returns 0 on success, -1 on error (call jerboa_last_error for details).
+#[no_mangle]
 pub extern "C" fn jerboa_x509_generate_signed_by_ca_mem(
     ca_cert_pem: *const u8,
     ca_cert_pem_len: usize,