2010-12-20 73 views
1

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

+0

如果您想通过名称在C中调用函数,您必须将该名称声明为某个函数。这是头文件的用途。你为什么不要他们? – TToni 2010-12-20 22:28:34

+0

我看不出如何用'nm'推导出C函数的原型。为了让原型破碎,在那里,你必须将文件编译为C++而不是C,否? – 2010-12-20 22:46:21

+0

您通过为函数名称刷头文件获得原型(hacks,同意) – chacham15 2010-12-21 08:27:17

回答

2

这在编写测试代码时有点常见。例如,您想调用以test_开头的所有函数。因此,您有一个shell脚本,可以通过所有.C文件对grep进行操作,并提取与test _。*匹配的函数名称。然后该脚本生成一个包含调用所有测试函数的函数的test.c文件。

例如,生成的程序看起来像:

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

另一种方式来做到这一点是使用一些技巧链接。这是Linux内核为其初始化做的。作为init代码的函数用限定符__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(); 
} 

符号__initcall_start,__initcall_end等得到链接脚本定义。

一般来说,Linux内核对GCC预处理器,编译器和链接器都有一些最聪明的技巧。它一直是C技巧的一个很好的参考。

0

你真的需要静态链接,并且同时在运行时选择所有匹配的函数,对吧?因为后者是动态链接的典型例子,我会说。

您确实需要一些机制来注册可用的功能。动态链接将提供这一点。

4

把所有功能的表到每个翻译单元:

struct functions MOD1FUNCS[]={ 
    {"FOO", foo}, 
    {"BAR", bar}, 
    {0, 0} 
}; 

然后把一张桌子到主程序中列出所有这些表:

struct functions* ALLFUNCS[]={ 
    MOD1FUNCS, 
    MOD2FUNCS, 
    0 
}; 

然后,在运行时,通过搜索表,并查找相应的函数指针。

0

我真的不认为你可以做到这一点。 C并不完全具备后期约束力或者你似乎需要的那种内省。

虽然我不太了解你的问题。你想静态链接时动态链接库的功能吗?因为这对静态链接没有任何意义,所以您需要手头已经有了二进制文件,这会使动态加载函数浪费时间,即使您可以轻松完成。