C/C++动态加载原型未知的函数

发布于 2024-09-08 15:35:16 字数 699 浏览 9 评论 0 原文

我正在编写一种运行时系统/解释器,我需要做的一件事是调用位于外部库中的 c/c++ 函数。

在 Linux 上,我使用 dlfcn.h 函数来打开库,并调用位于其中的函数。问题是,当使用 dlsysm() 时,返回的函数指针需要在调用之前转换为适当的类型,以便知道函数参数和返回类型,但是如果我调用一些库中的任意函数,那么显然我在编译时不会知道这个原型。

所以我要问的是,有没有一种方法可以调用动态加载的函数并传递它的参数,并在不知道它的原型的情况下检索它的返回值?

到目前为止,我得出的结论是,没有简单的方法可以做到这一点,但我发现的一些解决方法是:

  • 确保我想要加载的所有函数都具有相同的原型,并提供某种排序机制这些函数用于检索参数和返回值。这就是我目前正在做的事情。

  • 使用内联asm将参数压入堆栈,并读取返回值。如果可能的话,我真的想避免这样做!

如果有人有任何想法,我们将不胜感激。

编辑:

我现在已经找到了我正在寻找的内容:

http://sourceware.org /libffi/

“可移植的外部函数接口库”

(尽管我承认我在原来的问题中可以更清楚!)

I'm in the process of writing a kind of runtime system/interpreter, and one of things that I need to be able to do is call c/c++ functions located in external libraries.

On linux I'm using the dlfcn.h functions to open a library, and call a function located within. The problem is that, when using dlsysm() the function pointer returned need to be cast to an appropriate type before being called so that the function arguments and return type are know, however if I’m calling some arbitrary function in a library then obviously I will not know this prototype at compile time.

So what I’m asking is, is there a way to call a dynamically loaded function and pass it arguments, and retrieve it’s return value without knowing it’s prototype?

So far I’ve come to the conclusion there is not easy way to do this, but some workarounds that I’ve found are:

  • Ensure all the functions I want to load have the same prototype, and provide some sort mechanism for these functions to retrieve parameters and return values. This is what I am doing currently.

  • Use inline asm to push the parameters onto the stack, and to read the return value. I really want to steer clear of doing this if possible!

If anyone has any ideas then it would be much appreciated.

Edit:

I have now found exactly what I was looking for:

http://sourceware.org/libffi/

"A Portable Foreign Function Interface Library"

(Although I’ll admit I could have been clearer in the original question!)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

浪菊怪哟 2024-09-15 15:35:16

您要求的是 C/C++ 是否支持函数反射(即在运行时获取有关其类型的信息)。遗憾的是答案是否定的。

您必须使函数符合标准契约(正如您所说的那样),或者开始实现尝试在运行时调用函数而不知道其参数的机制。

由于不了解函数,因此无法调用它,我假设您的解释器/“运行时系统”至少有一些用户输入或类似的内容,它可以用来推断它正在尝试调用一个看起来像是采用这些函数的函数争论并返回一些并非完全出乎意料的东西。即使使用反射和合适的运行时类型系统,该查找本身也很难实现。混合调用约定、链接样式和平台,事情很快就会变得非常糟糕。

坚持你的计划,为你动态加载的函数执行一个明确定义的契约,并希望能够做到这一点。

What you are asking for is if C/C++ supports reflection for functions (i.e. getting information about their type at runtime). Sadly the answer is no.

You will have to make the functions conform to a standard contract (as you said you were doing), or start implementing mechanics for trying to call functions at runtime without knowing their arguments.

Since having no knowledge of a function makes it impossible to call it, I assume your interpreter/"runtime system" at least has some user input or similar it can use to deduce that it's trying to call a function that will look like something taking those arguments and returning something not entirely unexpected. That lookup is hard to implement in itself, even with reflection and a decent runtime type system to work with. Mix in calling conventions, linkage styles, and platforms, and things get nasty real soon.

Stick to your plan, enforce a well-defined contract for the functions you load dynamically, and hopefully make due with that.

如此安好 2024-09-15 15:35:16

您能否向外部库添加一个调度函数,例如,该函数采用函数名称和某种变体类型的 N 个(可选)参数并返回一个变体?这样调度函数原型就已知了。然后,调度函数对函数名称进行查找(或切换)并调用相应的函数。

显然,如果功能很多,维护就会成为问题。

Can you add a dispatch function to the external libraries, e.g. one that takes a function name and N (optional) parameters of some sort of variant type and returns a variant? That way the dispatch function prototype is known. The dispatch function then does a lookup (or a switch) on the function name and calls the corresponding function.

Obviously it becomes a maintenance problem if there are a lot of functions.

夕嗳→ 2024-09-15 15:35:16

我相信 ruby​​ FFI 库可以实现您的要求。它可以调用函数
在外部动态链接库中,无需专门链接它们。

http://wiki.github.com/ffi/ ffi/

您可能无法直接在脚本语言中使用它,但也许这些想法是可移植的。

--
布拉德·费兰
http://xtargets.heroku.com

I believe the ruby FFI library achieves what you are asking. It can call functions
in external dynamically linked libraries without specifically linking them in.

http://wiki.github.com/ffi/ffi/

You probably can't use it directly in your scripting language but perhapps the ideas are portable.

--
Brad Phelan
http://xtargets.heroku.com

旧情勿念 2024-09-15 15:35:16

我正在编写一种运行时系统/解释器,我需要做的一件事就是调用位于外部库中的 c/c++ 函数。

您可以查看 TclPython 可以做到这一点。如果您熟悉 Perl,还可以查看 Perl XS

一般方法是在解释器和目标 C 库之间需要额外的网关库。根据我使用 Perl XS 的经验,主要原因是内存管理/垃圾收集和 C 数据类型,它们很难/不可能直接映射到解释器的语言。

所以我要问的是,有没有一种方法可以调用动态加载的函数并传递参数,并在不知道其原型的情况下检索它的返回值?

我不知道。

确保我要加载的所有函数都具有相同的原型,并为这些函数提供某种排序机制来检索参数和返回值。这就是我目前正在做的事情。

这也是我的项目中其他团队正在做的事情。他们为外部插件提供了标准化 API,类似于:

typedef std::list< std::string > string_list_t;
string_list_t func1(string_list_t stdin, string_list_t &stderr);

插件的常见任务是执行输入的转换、映射或扩展,通常使用 RDBMS。

以前版本的界面随着时间的推移而变得无法维护,给客户、产品开发人员和第 3 方插件开发人员带来了问题。由于插件的调用相对较少(而且与到处使用的 SQL 相比,开销仍然微不足道),因此可以随意使用 std::string。参数 stdin 根据插件类型填充输入。如果输出参数 stderr 内有任何以“E:”开头的字符串,则插件调用被视为失败(“W:”用于警告,其余部分将被静默忽略,因此可用于插件开发/调试)。

dlsym 仅在具有预定义名称的函数上使用一次,以通过函数表(函数公共名称、类型、指针等)从共享库数组中获取数据。

I'm in the process of writing a kind of runtime system/interpreter, and one of things that I need to be able to do is call c/c++ functions located in external libraries.

You can probably check for examples how Tcl and Python do that. If you are familiar with Perl, you can also check the Perl XS.

General approach is to require extra gateway library sitting between your interpreter and the target C library. From my experience with Perl XS main reasons are the memory management/garbage collection and the C data types which are hard/impossible to map directly on to the interpreter's language.

So what I’m asking is, is there a way to call a dynamically loaded function and pass it arguments, and retrieve it’s return value without knowing it’s prototype?

No known to me.

Ensure all the functions I want to load have the same prototype, and provide some sort mechanism for these functions to retrieve parameters and return values. This is what I am doing currently.

This is what in my project other team is doing too. They have standardized API for external plug-ins on something like that:

typedef std::list< std::string > string_list_t;
string_list_t func1(string_list_t stdin, string_list_t &stderr);

Common tasks for the plug-ins is to perform transformation or mapping or expansion of the input, often using RDBMS.

Previous versions of the interface grew over time unmaintainable causing problems to both customers, products developers and 3rd party plug-in developers. Frivolous use of the std::string is allowed by the fact that the plug-ins are called relatively seldom (and still the overhead is peanuts compared to the SQL used all over the place). The argument stdin is populated with input depending on the plug-in type. Plug-in call considered failed if inside output parameter stderr any string starts with 'E:' ('W:' is for warnings, rest is silently ignored thus can be used for plug-in development/debugging).

The dlsym is used only once on function with predefined name to fetch from the shared library array with the function table (function public name, type, pointer, etc).

聆听风音 2024-09-15 15:35:16

我的解决方案是,您可以定义一个通用代理函数,它将动态函数转换为统一原型,如下所示:

#include <string>
#include <functional>

using result = std::function<std::string(std::string)>;

template <class F>
result proxy(F func) {
  // some type-traits technologies based on func type
}

在用户定义的文件中,您必须添加定义来进行转换:

double foo(double a) { /*...*/ }
auto local_foo = proxy(foo);

在您的运行时系统/解释器,您可以使用 dlsym 定义 foo-function 。用户定义函数foo负责进行计算。

My solution is that you can define a generic proxy function which will convert the dynamic function to a uniform prototype, something like this:

#include <string>
#include <functional>

using result = std::function<std::string(std::string)>;

template <class F>
result proxy(F func) {
  // some type-traits technologies based on func type
}

In user-defined file, you must add define to do the convert:

double foo(double a) { /*...*/ }
auto local_foo = proxy(foo);

In your runtime system/interpreter, you can use dlsym to define a foo-function. It is the user-defined function foo's responsibility to do calculation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文