Call a functionΒΆ

ProblemΒΆ

Factor a piece of code into a reusable routine, like a function call in a normal language.

CodeΒΆ

stl.startup_and_init_all

stl.fcall greet, ret_addr
stl.fcall greet, ret_addr
stl.loop

greet:
    stl.output "hi!\n"
    stl.fret ret_addr

ret_addr: bit.vec w

Output:

hi!
hi!

WalkthroughΒΆ

  • stl.startup_and_init_all β€” stl.fcall/stl.fret use the stack, so we need the full init.

  • stl.fcall target, ret_addr β€” saves the return address into ret_addr, then jumps to target. On return the runtime jumps back to whatever was saved.

  • stl.fret ret_addr β€” jumps to the address stored in ret_addr.

Note: ret_addr is a bit.vec w (one word wide β€” enough to hold a code address). One return slot per call site, NOT a stack of return addresses. For recursive or re-entrant calls you’d need to push/pop the return address onto a real stack.

VariationsΒΆ

Recursive calls require a stack. See stl.stack_init + hex.pointers.push_ret_address β€” the upstream calc.fj example uses this pattern.

Passing arguments β€” FlipJump has no calling convention. The conventional pattern is to declare a parameter variable, write into it before fcall, and have the callee read it:

// caller
bit.mov w, arg_buf, my_value
stl.fcall print_value, ret_addr

// callee
print_value:
    bit.print_dec_uint w, arg_buf
    stl.fret ret_addr

arg_buf:  bit.vec w
ret_addr: bit.vec w

See alsoΒΆ