如何为gcc中的函数创建单独的序言和尾声?

问题描述 投票:0回答:1

我听说过 gcc 中的

__attribute__((naked))
,这是将一些代码放入您不想进行额外调用的部分的常见方法。

例如在 AVR 中,您经常可以找到这样的代码存根:

static void __preinit(void) __attribute__((used, naked, section(".init3")));

void __preinit(void) {
    wdt_disable();
    RESET_Flags = MCUSR;
    MCUSR = 0;
}

此代码将放置在

.init3
部分,这是芯片初始化的部分,甚至在RAM初始化之前(
.bss
.data
)。这是通过 RAM 初始化所必需的,因为否则看门狗将在 RAM 初始化例程中启动并创建引导循环。

基于此我有一个想法。在我的程序中,我有很多模块,它们总是有 3 个功能:

*_init
*_main
*_tick
。在这种情况下,main.c 变得一团糟:

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

如果你忘记调用某个模块,调试就变成无用的浪费时间。 我想为我的项目创建一个平台,您只需在其中插入模块的 c 文件,它们就会被自动调用。就像与汇编相比,您不需要手动分配 RAM 的方式一样。

如果我定义所有模块内函数放置在相应的部分中会怎样:

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")));

我可以将这些函数合并到某种部分中,可以使用链接器将其加入:

.text :
{
    . = ALIGN(4);
    *(.text)
    *(.text*)

    *(.init_epilogue)
    *(.init_epilogue*)
    *(.mod_init)
    *(.mod_init*)
    *(.init_prologue)
    *(.init_prologue*)

    ...
} >ROM

但是我如何进入这些部分呢?我应该自己写序言和尾声吗?我怎么知道应该将哪些寄存器压入堆栈?

目前我使用ARM微控制器,所以这里的AVR只是作为示例。

有没有更自动化的方法来完成我的计划?

c gcc microcontroller ld sections
1个回答
0
投票

我如何进入这些部分?

只需将指针存储在节中即可。

.
开头的部分在技术上是为链接器保留的。无论如何,每个人都使用它们。

仅考虑:

// 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();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.