Feeding the Snake
string-data-sections

Emit string data sections at the start of c_program(). After all function definitions and before the main function, emit:

(memory (export "memory") 1)
(data (i32.const 60000) "hello")
(data (i32.const 60005) "world")

Each string gets a (data ...) section that writes its bytes into linear memory at the right address.

fn emit_string_table() void {
    emit_str("(memory (export \"memory\") 1)\n");
    for (0..str_count) |i| {
        emit_str("(data (i32.const ");
        emit_num(@intCast(str_addrs[i]));
        emit_str(") \"");
        // emit bytes, escaping non-printable chars
        for (str_table[i]) |c| {
            if (c >= 32 and c < 127 and c != '"' and c != '\\') {
                emit_byte(c);
            } else {
                emit_byte('\\');
                emit_byte("0123456789abcdef"[c >> 4]);
                emit_byte("0123456789abcdef"[c & 0xf]);
            }
        }
        emit_str("\")\n");
    }
}

Call emit_string_table() from c_program() after emitting function definitions.