💾 Archived View for danielc.dev › tiny-embedded-module-system-spec.gmi captured on 2023-04-27 at 07:30:17. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
Tiny Embedded Module System Spec
Feb 4 2022
The Idea: Create a memory efficient alternative to ELF that
is less powerful, but good enough for a plugin/module system.
---
The Solution: TEMS (Tiny Embedded Module System)
Modules are loaded via file on SD card/storage device.
Module file is compiled machine code, with the first bytes being
the `_start` function.
`_start` recieves an address to this function:
struct ModuleInfo { // Version of the module API - default is 0 uint32_t version; // Length of symbols uint32_t length; // Variable length struct struct Symbol { char *name; uintptr_t addr; }sym[]; };
`_start` parses this structure. It should only
load in addresses for symbols that have been compiled
into the module. Excess symbols are ignored. Error is reported
when symbols aren't found.
`_start` should have the following header:
int _start(struct ModuleInfo *info, int action);
If `action` is `0x0`:
Load symbols, run a "startup" code if needed.
Return `0x0` on success. Return `0x1` on symbol error.
Return `0x3` on startup error.
If `action` is `0x1`:
Run the main module code. Returns `0x0` on success.
Returns `0x1` on error.
How this is done isn't crucial, here are some of the top of my head:
- The module file has a local copy of `struct ModuleInfo`.
- It includes the required functions, and `addr` stores an address to
an assembly variable.
- `version` is checked between both structs, to ensure compatibility.
Basic trampoline:
Here, `ModuleInfo.sym[x].addr` would refer to the address of `sprintf_addr`.
.global sprintf .global sprintf_addr sprintf: adr r9, sprintf_addr ldr r9, [r9] bx r9 sprintf_addr: .long 0
Here is a generic lazy way:
if (!strcmp(info.funcs[0].type, "sprintf") { sprintf_addr = info.funcs[0].addr; } ...
Generating the structures and code could be done in the following ways:
- Write a linker script
- Write a python script
- Write a C "script"
(Writing a Python script is the most readable choice.)
With this spec, writing cross platform modules could be
possible, assuming the device provides POSIX functions.