Files
sx/examples/1655-platform-asm-callback-into-sx.sx
agra 1346a2d020 test(asm): round-trip example — asm calls back into an sx function
Adds examples/1655-platform-asm-callback-into-sx.sx: a global-asm
trampoline (_caller) that `bl _cb` back into an `export`ed sx function.
Demonstrates the sx → asm → sx round trip and that `export` (external
linkage + stable C symbol + C ABI) is what makes the callback symbol
resolvable — `callconv(.c)` alone leaves it internal and it DCE's away.
Runs under the JIT on aarch64-macos (→ 42); ir-only elsewhere. Locks
current behavior; no compiler change.
2026-06-16 07:55:05 +03:00

36 lines
1.4 KiB
Plaintext

// ASM stream — the round trip: sx → asm → sx. A global-asm routine (`_caller`)
// CALLS BACK into an sx function (`cb`) by its symbol, then returns. For the asm
// `bl _cb` to resolve, the sx callback needs EXTERNAL LINKAGE and a stable C
// symbol — that is exactly what `export` provides (it also implies the C ABI, so
// no hidden context parameter). `callconv(.c)` alone is NOT enough: it sets the
// ABI but leaves the function `internal`, so it is dead-code-eliminated (nothing
// in the IR references it — the `bl` is opaque to the optimizer) and `_cb` is
// undefined at link. macOS gives `export "cb"` the symbol `_cb` (leading
// underscore), which the template references. aarch64-macos-pinned; runs under
// the JIT here (sx run), ir-only elsewhere.
// The sx callback — `export` gives it external linkage + the `_cb` symbol + C ABI.
cb :: (n: i64) -> i64 export "cb" {
return n + 1;
}
// A global-asm trampoline that calls back into `cb`. It saves/restores the link
// register (x30) around the `bl` — it was itself reached via `bl`, so the return
// address must survive the nested call.
asm {
#string ASM
.global _caller
_caller:
stp x29, x30, [sp, #-16]!
bl _cb // x0 = cb(x0) — back into sx
ldp x29, x30, [sp], #16
ret
ASM,
};
caller :: (n: i64) -> i64 extern;
main :: () -> i64 {
return caller(41); // sx main → asm caller → bl _cb → sx cb → 42
}