SBBE has no string type. Strings are byte sequences in linear memory, managed entirely by the frontend. This guide shows common patterns for C-style null-terminated strings and length-prefixed strings.

C-style null-terminated strings

A C string is a pointer to a sequence of bytes ending with a zero byte. The frontend stores the string data in linear memory and passes the address around as a ptr.

String length (strlen)

func $strlen(ptr) -> i32 {
    var $len i32

entry:
    ldi 0
    str $len
    jmp check

check:
    ldl 0              // current ptr position
    ld $len
    add.s i64          // ptr + len
    ldm.u8             // load byte
    eqz i32            // is it zero?
    jmp.if done
    jmp next

next:
    ld $len
    ldi 1
    add.s i32
    str $len
    jmp check

done:
    ld $len
    ret
}

Comparing bytes

To compare two memory regions byte by byte:

func $memcmp(ptr, ptr, i32) -> i32 {
    var $i i32

entry:
    ldi 0
    str $i
    jmp check

check:
    ld $i
    ldl 2              // length
    ge.u i32           // i >= length?
    jmp.if equal
    jmp compare

compare:
    // Load byte from first buffer
    ldl 0
    ld $i
    add.s i64
    ldm.u8

    // Load byte from second buffer
    ldl 1
    ld $i
    add.s i64
    ldm.u8

    // Compare
    sub.s i32          // a - b
    dup
    eqz i32
    jmp.if advance
    ret                // return nonzero difference

advance:
    drop               // discard the zero difference
    ld $i
    ldi 1
    add.s i32
    str $i
    jmp check

equal:
    ldi 0
    ret
}

Length-prefixed strings

Many languages (Pascal, Rust, Go) use a (pointer, length) pair instead of null termination. This is typically represented as a struct:

// StringView layout:
//   offset 0: ptr data
//   offset 8: i32 length
// Get the length of a string view
func $string_len(ptr) -> i32 {
entry:
    ldl 0
    ldi 8
    add.s i64
    ldm i32            // load length field
    ret
}

// Get a byte at index i
func $string_at(ptr, i32) -> i32 {
entry:
    ldl 0
    ldm ptr            // load data pointer
    ldl 1              // index
    add.s i64          // data + index
    ldm.u8             // load byte
    ret
}

Copying memory (memcpy)

A byte-by-byte copy loop. In practice, backends would recognize this pattern and emit optimized block copy instructions.

func $memcpy(ptr, ptr, i32) {
    // params: dst=0, src=1, len=2
    var $i i32

entry:
    ldi 0
    str $i
    jmp check

check:
    ld $i
    ldl 2
    ge.u i32
    jmp.if done
    jmp copy

copy:
    // dst[i] = src[i]
    ldl 0
    ld $i
    add.s i64          // dst + i

    ldl 1
    ld $i
    add.s i64          // src + i
    ldm.u8             // load byte from src

    stm8               // store byte to dst

    ld $i
    ldi 1
    add.s i32
    str $i
    jmp check

done:
    ret
}

Key takeaways