CandleVM Executable Format
A CandleVM executable contains a header, plugin requirements, module and function metadata, embedded resources, and the bytecode instructions. The loader reads these sections in order. The bytecode starts immediately after the resource table and continues to the end of the file.
Integer encoding
Multi-byte integers are stored little-endian. A u8 occupies one byte; a u16 occupies two bytes; a u32 occupies four bytes. Signed i32 operands use the same byte order. Serialized Value values use their documented type discriminator and payload layout.
File layout
| Section | Encoding | Description |
|---|---|---|
| Magic | 4 bytes | The ASCII bytes CAND. |
| Candle version | u16 | Version of the Candle ecosystem; the supported version is 1. |
| Plugin requirement count | u16 | Number of required plugins that follow. |
| Plugin requirements | Repeated strings | Each entry contains the plugin name followed by its required version. The matching plugins must be available when the executable is loaded. |
| Module count | u16 | Number of modules defined in the executable. |
| Module table | Repeated module records | Each record contains a module name string, a function count (u16), and that many function records. |
| Resource count | u16 | Number of embedded resources that follow. |
| Resource table | Repeated resource records | Each record contains a resource ID string, a data length (u32), and that many data bytes. |
| Bytecode | Remaining bytes | The instruction stream. Its length is determined by the end of the file. |
Module names must be unique. Functions are numbered by their order within each module; function names must be unique within the module. Each function record contains:
| Field | Encoding | Description |
|---|---|---|
| Name | String | Function name. |
| Entry address | u32 | Byte offset into the bytecode instruction stream where the function begins. |
| Parameter count | u8 | Number of regular parameters, up to 8. |
| Capture count | u8 | Number of captured values, up to 8. |
Resource IDs must be unique. Each resource can contain up to 64 MiB of data. The executable can define up to 32,768 modules, with up to 65,535 functions per module.
Strings
Every string in the file uses the same encoding:
- A
u32byte length in little-endian order. - Exactly that many UTF-8 bytes.
The length counts bytes, not Unicode characters. Strings are not null-terminated. Invalid UTF-8 or a string whose bytes run past the end of the file makes the executable invalid. Strings are used for plugin names and versions, module and function names, and resource IDs.
Bytecode instructions
The bytecode section is a sequence of instructions. Each instruction begins with one opcode byte, followed by that opcode's operands in the order listed in the opcode reference. Registers and u8 operands occupy one byte. Multi-byte numeric operands use the little-endian encoding described above. String operands use the string encoding in this section. A tagged value operand uses the encoding described in the Value reference.
For example, a string operand containing the UTF-8 text cat is encoded as a four-byte little-endian length (03 00 00 00), followed by the three bytes 63 61 74.