Search code examples
cmakefilelinkerembedded

Creating binary without main() function in embedded environment


I need to create some project for MCU on c language, which does not have main() function. This project should be compiled and linked. Functions from this projects can be called by pointer, which should have fixed address. I'm using Eclipse-based IDE for this and GCC toolchain.

For example:

/* linker script SECTIONS: '.fun1 0x601f1000 : {KEEP(*(.fun1))}' */
int (* fun_ptr)(int) __attribute__((section(".fun1")))  = &fun;
int fun(int a)
{
    return a*2;
}

int res
void main (void)
{
    int (* fun_call_ptr)(int) = (int (*)(int))(*(int*)0x601f1000);
    res = (*fun_call_ptr)(10);
}

The goal is to have function 'fun' in one project and 'main' in another. Then build both projects and load both binary files to flash separately.

I guess it can be done by some linker script or makefile, but have no idea how to do it.


Solution

  • I have not specifically done what you describe, but have done similar things, and the approach I would try would be:

    • Compile the code with -nostartfiles so that no start-up code is linked (which is what causes main() to be called.
    • Set an alternate entry point with the --entry= option so it does not need a main(). Alternatively just provide a dummy main() since with -nostartfiles nothing will call it. The actual entry can be any function or a dummy function. Since there is no start-up code, nothing is going to start it. It is just to satisfy the linker.
    • Specify all functions (and other symbols) that you want to force to be linked even if not referenced by using the --undefined= linker option.
    • Make all functions and symbols you want external linkage (i.e. not static) to prevent the compiler from discarding unused functions.

    You should then get a fully linked binary that is a collection of functions that need not be explicitly internally referenced.

    You could then use the emitted symbol map or nm output to determine the function entry point. However that requires that your image with the main() entry point must be built after the nostartup image, and re-built every time the nostartup image changes, obviating any advantage of having a separate image. Instead I suggest that you create a single array of function pointers to each entry point, in a fixed order and locate that table at a specific location (i.e. a vector table). Then you use that to lookup function entry points by index into the table. That way you may also not need multiple undefined linker options for each separate function, but a single one for the table, and either image can be updated independently, so long as the indexes do not change.

    There may be other considerations, but that is the general approach to take I think.