Ashet Executable Format (.ashex)
.ashex is the native executable container used by Ashet OS. It is designed for direct, low-overhead loading in the kernel.
§1 Overview
-
Little-endian 32-bit format (current file type: machine32_le).
-
Fixed 512-byte header with CRC32 checksum.
-
Offset/count pairs for syscall table, load sections, zeroed sections, and relocations.
-
Optional embedded icon payload (commonly an ABM bitmap).
§2 Header Block
The file starts with a 512-byte header. Bytes 0..507 are checksummed with CRC32 (ISO HDLC), and the checksum is written at 508..511.
const Platform = enum(u8) {
riscv32 = 0,
arm32 = 1,
x86 = 2,
};
const FileType = enum(u8) {
machine32_le = 0,
};
const HeaderV0 = struct {
magic: [4]u8 = .{ 'A', 'S', 'H', 'X' },
version: u8 = 0,
file_type: FileType, // currently always machine32_le
platform: Platform,
_padding0: u8 = 0,
icon_size: u32,
icon_offset: u32, // absolute file offset, 0 if icon_size == 0
vmem_size: u32, // total virtual memory to allocate for the process image
entry_point: u32, // offset within process virtual memory
syscall_offset: u32, syscall_count: u32,
load_header_offset: u32, load_header_count: u32,
bss_header_offset: u32, bss_header_count: u32,
relocation_offset: u32, relocation_count: u32,
_reserved: [452]u8, // currently filled with 0xFF
checksum_crc32: u32, // CRC32 over bytes 0..507
};
§3 File Layout
Payload sections are written in this order, each aligned to a 512-byte boundary: icon, load headers, BSS headers, syscalls, relocations. Alignment padding bytes are currently 0xFF.
+------------------------------+
| 512-byte header |
+------------------------------+
| icon bytes (optional) |
+------------------------------+
| load headers + load data |
+------------------------------+
| bss headers |
+------------------------------+
| syscall table |
+------------------------------+
| relocations |
+------------------------------+
§4 Record Encodings
const LoadRecord = struct {
vmem_offset: u32,
size: u32,
data: [size]u8,
};
const BssRecord = struct {
vmem_offset: u32,
size: u32,
};
const SyscallRecord = struct {
name_len: u16,
name: [name_len]u8, // syscall name bytes
};
const RelocationSize = enum(u2) {
word8 = 0,
word16 = 1,
word32 = 2,
word64 = 3,
};
const RelocationField = enum(u2) {
unused = 0b00,
add = 0b10,
subtract = 0b11,
};
const RelocationType = packed struct(u16) {
size: RelocationSize,
self: RelocationField,
addend: RelocationField,
base: RelocationField,
offset: RelocationField,
syscall: RelocationField,
_padding: u4 = 0,
};
const RelocationRecord = struct {
offset: u32, // process-memory offset to patch
typ: RelocationType,
syscall_index: if (typ.syscall != .unused) u16 else void,
addend: if (typ.addend != .unused) i32 else void,
};
§5 Relocation Semantics
A relocation computes a new value by conditionally adding or subtracting fields selected by RelocationType: current value at patch site (self), encoded addend, process base address (base), relocation offset, and resolved syscall address (syscall).
The current kernel loader supports word32 relocations.
§6 Notes
-
All numeric fields are little-endian.
-
Offsets in header fields are absolute file offsets.
-
The kernel validates magic, version, platform, file type, and header checksum before loading.