How to create separate prologue and epilogue for functions in gcc?

74 Views Asked by At

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?

2

There are 2 best solutions below

4
KamilCuk On

how do i enter those sections?

You iterate over addresses of variables named __start_<section> and __stop_<section>. Like extern <type> __start_mod_init; and extern <type> __stop_mod_init. And then all data are between &__start_mod_init and &__stop_mod_init.

The problem with storing functions in a section, you do not know the size of the function, unless they are like all the same.

Is there and more-automated way of doing what i had planned?

Just store pointers in sections.

Sections starting with . are technically reserved for linker. Everyone uses them anyway.

Consider just:

// module.h
struct module {
   void (*init)();
   void (*main)();
};
#define CONCAT(a, b)  a##b
#define XCONCAT(a, b) CONCAT(a, b)
#define MODULE_REGISTER(init, main) \
   __attribute__((__section__("modules"))) \
   static const struct module XCONCAT(_module_, __LINE__) = \
       { init, main }
extern struct module __start_modules;
extern struct module __stop_modules;
#define MODULE_FOREACH(VAR) \
   for (const struct module *VAR = &__start_modules; \
        VAR != &__stop_modules; \
        ++VAR)

// module1
MODULE_REGISTER(mod1_init, mod1_main);

// main
void init() {
    MODULE_FOREACH(i) {
       i->init();
    }
}

void loop() {
    MODULE_FOREACH() {
       i->main();
    }
}
0
emacs drives me nuts On

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

Using attribute __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.

Using attribute __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));
}

Avoiding attribute __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).