如何从加载动态库执行未知的功能呢?(How to execute unknown functions

2019-10-29 21:54发布

这很容易,当你知道在设计时此功能加载从动态库中的函数。 只是这样做:

   int (*fn)(int);

   l0 = dlopen("./libfoo.so", RTLD_LAZY);
   if (!l0) 
   {
      fprintf(stderr, "l0 %s\n", dlerror());
      return 1;
   }


   fn = (int (*)(int))dlsym(l0, "foo");


   if ((error = dlerror()) != NULL)  
   {
      fprintf(stderr, "fn:%s\n", error);
      return 1;
   }

   x=(*fn)(y);

...

如何当它在设计时未知的执行库函数? 在运行时,你有一个函数名和参数指针和参数大小的数组的数组:

char *之fn_name = “foo” 的; INT foo_argc; 无效* foo_argv []; INT foo_argv_size [];

在脚本语言,它是一块蛋糕的任务,但如何在C很好地实现这个++?

Answer 1:

作为一个静态的语言,C ++实际上取决于知道类型/接口在编译时。 我怀疑有一个很好的低级别的方法来完成你正在寻找解决的任务,但一如既往,如果你增加一个抽象的另一层你大概可以达到的目标。 具体来说,在这种情况下,方法,我已经在过去使用时,不知道到底是什么“论证”需要传递给动态加载的插件传递的一个参数std::map< std::string, std::string > >即一键=值字典)只是需要传递任何信息包,并让插件弄清楚如何处理它。 这有点不方便,你必须编码/解码大部分数据,但它可以用来妥善地处理我已经至少运行大多数情况下。

当然,这是假设你已经通过标准化的插件接口来控制动态加载DLL的API的能力。 如果你不能做到这一点......你可能出于运气。



Answer 2:

随着问题的陈述,你不能在标准C ++做到这一点。 有没有办法来有效地调用一个函数,除非编译器在编译时知道被叫方的参数。 即使在可变参数功能的情况下,调用代码必须编译知道参数传递什么-有没有办法建立一个va_list

如果你控制DLL中的函数,则可能是最好的办法是通过集合boost::any ,或者(如果两者都将使用相同的编译器和库编译) void* (如果你没有那么多兼容性),或者参数(谷歌的协议缓冲,也许)的一些序列化形式。

如果DLL已经存在,你不能改变它的接口,那么你需要要么打不规范的技巧与堆栈根据您的调用约定把参数在正确的地方(这是当他们有什么动态语言做一个C调用机制),否则你需要覆盖所有的函数签名,这可能是一个巨大的switch语句。 显然,后者是唯一可能的,如果你已经有了你正在处理一个好主意,什么DLL(S)。

此外,通常你需要比指针将参数及其大小列表的更多。 调用约定很可能取决于该类型的参数,而不仅仅是规模。 例如,浮点参数可在FPU被传递寄存器,而不是在堆栈上。

您还需要担心返回类型,什么调用代码期待用它做。



Answer 3:

实际上,有在运行时调用的函数,如果你知道它的调用约定和参数接收的方法。 然而,这在于出了标准的C / C ++语言的范围。

对于x86汇编:

假设如下:

  1. 你知道准备的所有参数,固体缓冲你的功能,正是以这样的方式,他们会被包装堆栈中。
  2. 您的函数不接受/按值返回C ++对象。

您可以使用,则以下功能:

int CallAnyFunc(PVOID pfn, PVOID pParams, size_t nSizeParams)
{
    // Reserve the space on the stack
    // This is equivalent (in some sense) to 'push' all the parameters into the stack.
    // NOTE: Don't just subtract the stack pointer, better to call _alloca, because it also takes
    // care of ensuring all the consumed memory pages are accessible
    _alloca(nSizeParams);

    // Obtain the stack top pointer
    char* pStack;
    _asm {
        mov pStack, esp
    };

    // Copy all the parameters into the stack
    // NOTE: Don't use the memcpy function. Because the call to it
    // will overwrite the stack (which we're currently building)
    for (size_t i = 0; i < nSizeParams; i++)
        pStack[i] = ((char*) pParams)[i];

    // Call your function
    int retVal;
    _asm {
        call pfn
        // Most of the calling conventions return the value of the function (if anything is returned)
        // in EAX register
        mov retVal, eax
    };

    return retVal;
}

您可能需要调整这个功能,这取决于所使用的调用约定



Answer 4:

如何当它在设计时未知的执行库函数?

你不能。 有没有在C ++中没有反映。 你必须了解的功能原型,为了能够调用它。 (除非你实现你自己的倒影,反正。)



文章来源: How to execute unknown functions from dynamic load libraries?