I have heard of __attribute__((naked))
in gcc, which is common way place some code into sections, where you don't want to place additional call.
For example in AVR you can frequently find such code stub:
static void __preinit(void) __attribute__((used, naked, section(".init3")));
void __preinit(void) {
wdt_disable();
RESET_Flags = MCUSR;
MCUSR = 0;
}
This code will be placed in section .init3
, which is the part of chip initialization, even before RAM initialization (.bss
and .data
). This is required to pass ram initialization, because otherwise watchdog will fire-up in RAM initialization routine and create a boot-loop.
Based on this i have an idea. In my programs i have a lot of modules, which always have 3 functions: *_init
, *_main
and *_tick
. In this case main.c becomes a mess:
int main() {
init();
while(1) {
loop();
}
}
void init() {
mod1_init();
mod2_init();
...
modN_init();
}
void loop() {
mod1_main();
mod2_main();
...
modN_main();
}
// Same goes for systick handler
If you forget to call some module, debug becomes a useless waste of time. I would like to create a platform for my projects, where you just drop-in c-files for modules and they are called automatically. Just like the way you are not requred to allocate RAM manually, compared to assembly.
What if i define all in-module functions to be placed in corresponding sections:
static void modX_init() __attribute__((used, naked, section(".mod_init")));
static void modX_main() __attribute__((used, naked, section(".mod_main")));
static void modX_tick() __attribute__((used, naked, section(".mod_tick")));
I would be able to merge those functions into some kind of sections, which can be jouned using linker:
.text :
{
. = ALIGN(4);
*(.text)
*(.text*)
*(.init_epilogue)
*(.init_epilogue*)
*(.mod_init)
*(.mod_init*)
*(.init_prologue)
*(.init_prologue*)
...
} >ROM
But how do i enter those sections? Should i write myself prologue and epilogue? And how do i know which registers should i push onto stack?
Currently i use ARM microcontrollers, so AVR here is just for an example.
Is there and more-automated way of doing what i had planned?
In order to be able to be explicit, the following code is for avr-gcc. For other targets, the code will be different (alignments, opcode for ret
, inline asm modifiers, etc.).
__constructor__
The easy part is for the mod_init
functions for which we can use a static constructor:
__attribute__((__constructor__))
static void mod_init (void)
{
// ...
}
This code will run in .init6
and hence prior to main
(.init9
) but after the initialization of .bss
and .data
in .init4
.
So no special hacks needed here.
__naked__
For simplicity, the remainder shows how the mod_main functions can be handled; the mod_tick functions will work exactly the same.
According to GCC documentation, the only supported code in naked functions is inline asm. This can be achieved by making some naked stub which then calls the very mod function. In order to call the naked functions and to add a trailing ret
, use the following linker script augmentation which will be provided as -T naked.ld
to the link:
SECTIONS
{
.my_main :
{
. = ALIGN(2);
call_mod_main = .;
*(.mod_main)
*(.mod_main.*)
SHORT (0x9508) /* RET */
} > text
}
INSERT AFTER .text
This defines a symbol call_mod_main
that will be used to run the stub functions. After all functions have been executed, there is a final ret
which has 16-bit opcode 0x9508.
The minimal code to call these is then:
extern void call_mod_main (void);
int main (void)
{
call_mod_main ();
return 0;
}
The code for one module would be something like:
// The worker function for mod_main with all code.
__attribute__((__noinline__,__noclone__))
static void mod_main (void)
{
__asm ("nop");
}
// A stub calling the function above to meet (or come close to) the
// requirement that GCC only supports inline assembly in naked funcs.
__attribute__((__used__, __unused__, __no_instrument_function__))
__attribute__((__naked__, __section__(".mod_main")))
static void stub_mod_main (void)
{
// Using vanilla C/C++:
mod_main ();
// or using inline assembly:
__asm volatile ("%~call %x0" :: "i" (mod_main));
}
__naked__
While the code with naked functions from above solves the problem, sometimes it's bit of annoying to have to provide an extra linker script augmentation.
The following solution is still "self-registering" like the code above as all initializations are performed by a static constructor.
The functions for mod_main and mod_tick are maintained in a list that's set up at static construction time and traversed as needed. The registration uses a function register_module
which takes a list element for mod_main resp. mod_tick:
// In some module
static void mod1_init (void) { /* ... */ }
static void mod1_tick (void) { /* ... */ }
__attribute__((__constructor__))
static void register_mod1 (void)
{
mod1_init ();
static flist_t elm_tick = { mod1_tick, NULL };
register_module (NULL /* no mod1_main */, & elm_tick);
}
The main module provides the lists and methods to register modules, and functions to traverse the lists:
// In main.h
typedef void (*func_t)(void);
typedef struct flist
{
func_t func;
struct flist *next;
} flist_t;
extern void register_module (flist_t *lmain, flist_t *ltick);
// In main.c
static flist_t *list_main;
static flist_t *list_tick;
void register_module (flist_t *lmain, flist_t *ltick)
{
if (lmain)
{
lmain->next = list_main;
list_main = lmain;
}
if (ltick)
{
ltick->next = list_tick;
list_tick = ltick;
}
}
static void run_ticks (void)
{
for (const flist_t *elm = list_tick; elm; elm = elm->next)
elm->func ();
}
Disadvantage is that this occupies 8 bytes of SRAM for each module (for avr-gcc), and that it uses more code because it has to register and traverse all modules by hand (as opposed to previous solution that registered and traversed / called by naked magic).