Memora8 Application Binary Interface

Document version: 1.0 Status: Specification Compiler implementation baseline: SekuraJS 6dd5716

This document describes the function-call and data-layout conventions used by the SekuraJS Memora8 backend. It defines how compatible functions exchange scalar arguments and results, preserve registers, and use the stack. It supplements the Memora8 ISA specification; it does not change instruction behavior.

Data model

Property Convention
General-purpose register width 32 bits
ABI word size 4 bytes
Pointer size 4 bytes
Stack alignment at function boundaries 4 bytes
Stack direction Grows toward lower addresses

The compiler’s integer scalar types are i8, u8, i16, u16, i32, and u32. Their storage sizes and natural alignments are 1, 2, or 4 bytes. Pointers occupy 4 bytes. Structure fields are placed at their natural alignment, and the complete structure size is rounded up to the greatest field alignment. Arrays contain consecutive elements.

Register conventions

Registers ABI role Preservation
r0 Constant zero Always reads as zero; writes have no effect
r1 Function result Caller-saved; also used for return values
r2–r7 First six scalar arguments (a0–a5) Caller-saved
r8–r18 Temporary / scratch registers Caller-saved
r19–r25 Saved registers (s0–s6) Callee-saved
r26 Reserved by the compiler backend Do not use for general values
r27 No general calling-convention role is assigned by this backend Treat as unspecified
r28 Module base in compiler-generated module code Reserved while executing that code
r29 Stack pointer (SP) Callee restores it before returning
r30 Frame pointer (FP) Callee restores the caller’s value
r31 Link register (LR) A function that makes calls saves and restores it

A caller that needs a value in r1–r18 after a function call must save it before the call. A callee must restore any r19–r25 register it uses. r28 is used by module-mode code to address module data and function tables; code in that mode must preserve its module-base role.

Function arguments

The first six scalar arguments are passed in registers, in order:

Argument Register
1 r2
2 r3
3 r4
4 r5
5 r6
6 r7

Additional scalar arguments are passed on the stack. The caller places them in right-to-left order, one 4-byte argument slot per argument. At callee entry, after establishing its frame pointer, the first stack argument is at [FP + 4], the next at [FP + 8], and so on. The caller removes the stack arguments after the call returns.

SekuraJS launchers that enter a module use the same initial argument registers r2–r7. The launch configuration can set those values; its syntax is documented in the mr8sim launch configuration reference.

Return values and calls

A scalar function result is returned in r1. A function call writes its return address to r31, conventionally using JAL r31, target or JALR r31, base, offset. A returning function transfers control to the address in r31, conventionally with JALR r0, r31, 0.

The value in r1 is the result of the most recent call. A caller should copy it to another register or memory before making another call if it must remain live.

Stack frames

The stack grows downward. The compiler-generated function prologue saves the previous frame pointer at [FP + 0] and sets r30 to that location. If the function makes calls, it saves its incoming link register at [FP - 4]; local variables, spills, and saved registers occupy stack storage below the frame pointer. A function that does not make calls can use [FP - 4] for its first local storage.

Before returning, the callee restores any saved registers, restores r31 when it has made calls, restores the previous r30, and releases its frame so the caller’s stack pointer is recovered. The required stack alignment at call boundaries is 4 bytes.

The exact placement of local variables and register spills is compiler-generated and is not a stable interface between independently compiled functions. Functions should exchange values through the argument and return conventions above rather than relying on another function’s local frame layout.

Data layout

Integer objects use their declared widths: 8-bit, 16-bit, or 32-bit. Structure members are aligned to their natural size, with an overall structure alignment equal to the greatest member alignment. The compiler inserts padding as needed between members and at the end of a structure. Pointers are 32-bit values.

This ABI description covers scalar function arguments and scalar return values. Passing or returning structures by value, variadic calls, and interoperability with non-SekuraJS toolchains require a separately specified convention before they can be treated as compatible interfaces.

Versioning

This document describes the calling and data-layout conventions implemented by SekuraJS baseline 6dd5716. Changes to register roles, argument placement, stack layout at call boundaries, return-value placement, or data layout require an ABI version review.