的dlsym /与运行参数

问题描述:

我试图做类似下面的dlsym /与运行参数

enum types {None, Bool, Short, Char, Integer, Double, Long, Ptr}; 
    int main(int argc, char ** args) { 
    enum types params[10] = {0}; 
    void* triangle = dlopen("./foo.so", RTLD_LAZY); 
    void * fun = dlsym(triangle, ars[1]); 

    <<pseudo code>> 
    } 

哪里伪代码是一样的东西

fun = {} 
for param in params: 
     if param == None: 
     fun += void 
     if param == Bool: 
      fun += Boolean 
     if param == Integer: 
      fun += int 
     ... 
returnVal = fun.pop() 
funSignature = returnval + " " + funName + "(" + Riffle(fun, ",") + ")" 
exec funSignature 

谢谢

+0

>我想要做下面的事情 那么当你尝试这个时会发生什么? – a2800276 2009-08-30 18:32:24

+0

@ a2800276:编译器抱怨许多语法问题。更深层的问题是误解'dlopen()'和'dlsym()'等提供的服务。 – 2009-08-30 19:01:05

其实,你几乎可以做所有你想要的。在C语言中(例如与C++不同),共享对象中的函数仅由它们的名称引用。因此,要找到- 最重要的,请致电 - 正确的功能,您不需要其完整的签名。你只需要它的名字!这既是优势也是劣势 - 但这就是你选择的语言的本质。

让我来演示一下它是如何工作的。

#include <dlfcn.h> 

typedef void* (*arbitrary)(); 
// do not mix this with typedef void* (*arbitrary)(void); !!! 

int main() 
{ 
    arbitrary my_function; 
    // Introduce already loaded functions to runtime linker's space 
    void* handle = dlopen(0,RTLD_NOW|RTLD_GLOBAL); 
    // Load the function to our pointer, which doesn't know how many arguments there sould be 
    *(void**)(&my_function) = dlsym(handle,"something"); 
    // Call something via my_function 
    (void) my_function("I accept a string and an integer!\n",(int)(2*2)); 
    return 0; 
} 

事实上,你可以用这种方式调用任何函数。但是,有一个缺点。你实际上需要在编译时间中知道你函数的返回类型。默认情况下,如果您在该typedef中省略void *,则将int假定为返回类型 - 是的,它是正确的C代码。问题是编译器需要知道返回类型的大小才能正确操作堆栈。

您可以通过招数变通办法,例如,通过声明前几个函数类型与预先大小不同的返回类型,然后选择你真正要调用哪一个。但更简单的解决方案是要求插件中的函数始终返回void *或int;实际结果是通过作为参数给出的指针返回的。

您必须确保的是您始终使用它应该接受的参数的确切数量和类型来调用函数。密切关注不同整数类型之间的区别(你最好的选择是将参数明确地赋予它们)。

几位评论者报告称上面的代码不保证可用于可变参数函数(如printf)。

+1

@pavel:我能做点像 工会类型{ int i; double d; float f; }类型; (type)my_printf(...)? – adk 2009-08-30 20:26:56

+0

@adk:我没有看到工会有什么问题。事实上,我完全忘了他们,所以谢谢你提高我的答案! :) – 2009-08-30 20:42:37

+0

Pavel:'printf'是一个不好的例子,因为空参数列表声明与可变参数函数不兼容。 (顺便说一句,'printf'的返回类型是'int',而不是'void *')。 – caf 2009-08-31 00:41:35

什么dlsym()回报dlopen的通常是一个函数指针 - 伪装成void *。 (如果你问一个全局变量的名称,它会返回一个指向你到全局变量,太)

你然后调用,就像你可能会使用任何其他指针函数功能:

int (*fun)(int, char *) = (int (*)(int, char *))dlsym(triangle, "function"); 

(*fun)(1, "abc"); # Old school - pre-C89 standard, but explicit 
fun(1, "abc");  # New school - C89/C99 standard, but implicit 

我是老派;我更喜欢显式表示法,以便读者知道“f​​un”是指向函数的指针,而不需要查看它的声明。使用新的学校符号,您必须记住在尝试查找名为'fun()'的函数之前先查找变量'fun'。

请注意,你不能动态地构建函数调用,你正在做的 - 或者,不一般。要做到这一点需要更多的工作。你必须事先知道函数指针在参数方面的期望以及它返回的结果以及如何解释它。

系统,其管理更加动态的函数调用,如Perl,有关于函数的调用方式和参数传递和不调用(可以说是无法调用)函数任意签名的特殊规则。他们只能用事先知道的签名来调用函数。一种机制(Perl不使用)是将参数压入堆栈,然后调用一个知道如何从堆栈中收集值的函数。但即使被调用函数操纵这些值然后调用任意其他函数,该函数也会为任意其他函数提供正确的调用顺序。

C中的反射很难 - 非常困难。这是不可撤消 - 但它需要的基础设施,以支持它和纪律来使用它,它只能调用支持基础设施的规则功能

+0

我知道提前的参数是什么,返回类型是什么,我的问题是我是否可以动态创建转换。 谢谢 – adk 2009-08-30 18:48:09

+1

不;您无法动态创建演员表。 C是一种编译语言;你想要做的是解释C代码,这不是一个微不足道的命题! – 2009-08-30 18:51:31

+0

谢谢。这是我想知道的 – adk 2009-08-30 19:04:45