cload: Initial import.
This allows running binary code on Bangle.js2.
It's great that you got this working, but I feel like surely this should just be added as _example_compiled_c or something? It's not just an app that someone can install from the app loader and magically have C.
There's also all the code for relocation you're doing, but I think if you use -fpic to ask for position independent code, the code will 'just work' when running from RAM without having to have a relocation step? The compiler we use for Inline C uses a bunch of flags to create its code that might help: https://github.com/gfwilliams/EspruinoCompiler/blob/master/src/compile.js#L457-L469
It might also be worth mentioning https://www.espruino.com/InlineC in the README. That's built in and while it's just for code defined inline, it 'just works' in the IDE and app loader I believe, so you don't have to worry about hard-coding addresses or anything.
gfw: I experimented a bit some time ago, and could not find reliable way to get code that did not need relocations.
I know about InlineC, but it relies on server magic somewhere, and is not really meant for, say, 2000 lines of C being imported that way. I'll add pointer to documentation.
This is the code I've used quite recently to compile C code to something that can be embedded. It worked great for me, and the code mostly comes from EspriunoCompiler. Hopefully it will help? Hopefully with it, we can do the without hard-coded addresses in the JS.
This is for one function, but I believe you should be able to handle others in a similar way - we already do return E.nativeCall(new DataView(E.toArrayBuffer(bin)).getUint32(0,1),... which uses the pointer in the first word as the function pointer, so you just need to ensure the second function pointer goes in 2nd word and so on
Example c file:
int main(uint32_t a) {
}
void *entryPoint[] __attribute__ ((section (".entrypoint"))) = {(void*)main};
linker.ld:
ENTRY(entryPoint)
MEMORY
{
RAM (xrw) : ORIGIN = 0, LENGTH = 100K
}
SECTIONS
{
.entrypoint :
{
. = ALIGN(4);
*(.entryPoint)
}
/* We put everything in .text section as we load everything into RAM as one binary string */
.text :
{
. = ALIGN(4);
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
. = ALIGN(4);
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
} >RAM
/* Remove stuff we don't want */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
*(.ARM.*)
*(.comment)
}
}
Commands to create base64 code that can be run as-is:
INCLUDES="-I... "
CFLAGS="-mlittle-endian -mthumb -mthumb-interwork -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -std=gnu11 -nostdlib -fno-common -fno-exceptions -fdata-sections -ffunction-sections -flto -fno-fat-lto-objects -Wl,--allow-multiple-definition -fpic -fpie -fpermissive -Os -Tlinker.ld "
arm-none-eabi-gcc $INCLUDES $CFLAGS compiledcode.c -o compiledcode.elf || exit 1
# arm-none-eabi-objdump -x -S compiledcode.elf # debug print
arm-none-eabi-objcopy -O binary compiledcode.elf compiledcode.bin || exit 1
echo "(function(){var bin=E.toFlatString(atob(\"`base64 compiledcode.bin | tr -d '\n\r'`\"));return E.nativeCall(new DataView(E.toArrayBuffer(bin)).getUint32(0,1),'int(int)', bin);})"