Daniel's Stuff


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.

*This specification is a draft, completed version will be published one day.*

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;

_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
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.