我有一个接口,我想能够静态链接模块例如,我希望能够调用所有名为FOO或与某个原型匹配的函数(尽管是在单独的文件中),最终调用文件中的某个函数而不调用其他文件中的头不要说这是不可能的,因为我发现了一个黑客可以做到这一点,但我想要一个非黑客的方法(技巧是使用nm获取函数及其原型,然后我可以动态调用该函数)另外,我知道你可以通过动态链接来实现,但是,我想静态链接文件。有什么想法吗?

最佳答案

这在编写测试代码时有点常见。例如,您想调用所有以test开头的函数。所以有一个shell脚本,grep会遍历所有的.C文件,并提取与test.*匹配的函数名。然后该脚本生成一个test.c文件,该文件包含一个调用所有测试函数的函数。
例如,生成的程序如下所示:

int main() {
   initTestCode();
   testA();
   testB();
   testC();
}

另一种方法是使用一些链接器技巧这就是Linux内核初始化时所做的事情初始化代码的函数用限定符init标记这在linux/init.h中定义如下:
#define __init          __section(.init.text) __cold notrace

这会导致链接器将该函数放在.init.text节中系统启动后,内核将从该部分回收内存。
为了调用这些函数,每个模块将使用其他宏core_initcall(func)、arch_initcall(func)等(也在linux/init.h中定义)声明一个initcall函数这些宏将指向函数的指针放入名为.initcall的链接器部分。
在启动时,内核将“遍历”调用所有指针的.initcall部分遍历的代码如下所示:
extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];

static void __init do_initcalls(void)
{
        initcall_t *fn;

        for (fn = __early_initcall_end; fn < __initcall_end; fn++)
                do_one_initcall(*fn);

        /* Make sure there is no pending stuff from the initcall sequence */
        flush_scheduled_work();
}

符号初始化调用开始、初始化调用结束等在链接器脚本中定义。
一般来说,Linux内核使用GCC预处理器、编译器和链接器做一些最聪明的技巧是可能的它一直是C技巧的一个很好的参考。

关于c - 如何在C中创建模块,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4494569/

10-09 13:43