【问题标题】:Can I pass char* array instead of several arguments to a function?我可以将 char* 数组而不是几个参数传递给函数吗?
【发布时间】:2020-08-06 02:32:16
【问题描述】:

我正在尝试编写一个程序,该程序将运行动态库中的函数,其名称、参数及其类型由用户输入。我可以使用dlsym(func_name) 获得指向此函数的 void* 指针,但是我事先不知道参数的类型及其数量,因此我无法以正常方式取消引用此指针。

如果我将所有参数的字节表示复制到char * 数组中,我可以调用一个以该数组作为参数的函数吗?例如,在汇编中调用 printf 时,我可以将参数和格式字符串推送到堆栈并调用 printf。也许我可以在 C 中做类似的事情,或者使用程序集插入?

例如,假设函数是void func(int, double);,我得到了参数int adouble b。然后我会创建一个数组:

char buf[sizeof(int) + sizeof(double)]
memcpy(buf, &a, sizeof(int))
memcpy(buf + sizeof(int), &b, sizeof(double))

并将其用作压入堆栈的参数。

用户输入函数的名称、描述其类型的字符串以及参数本身。例如:

func_name
viid
5
6
2.34

func_name 是将在 dlsym 中使用的函数的名称。 viid 表示该函数具有 void func_name(int, int, double) 类型(第一个 char 是返回类型,其余是参数。v = void,i = int,d = double)。其余的都是参数。

【问题讨论】:

  • 我相信它可以通过铸造以某种方式完成。尝试将参数作为 char 数组发送,并通过转换为实际类型来读取它。这东西需要一些试验才能成功。但是如果在你得到参数之后你仍然不知道类型,这可能是一个问题,因为你不知道如何阅读参数。也许您应该发送更多参数来解释其他参数的类型。
  • 不一定只有大小,还有类型。像 FP 这样的不同类型可能使用不同的堆栈。
  • 我不认为你真的能做到这一点。有些变量在寄存器中传递,有些在堆栈中传递,这取决于数据类型。
  • 您可能想阅读以下内容:x86 calling conventions
  • @OP 试试 libffi sourceware.org/libffi

标签: c dynamic-linking


【解决方案1】:

不,除非可能在 ABI 中纯粹在堆栈上传递参数。任何计算环境都有参数如何传递的规范。 (此规范是平台的应用程序二进制接口 [ABI] 规范的一部分。)参数类型和大小会影响它们是否在通用寄存器、浮点寄存器或其他位置传递,以及它们的对齐方式。很少有这样的规范(如果有的话)将参数作为原始字节转储传递给堆栈。

可以编写代码来解码参数的描述并构造调用函数所需的状态。这样的代码需要至少部分地用汇编或各种语言扩展来编写。 (我希望有些人可能已经编写了这样的代码并提供了它,但没有这样的参考。)在大多数情况下,这可能是实施成本过高的解决方案;您应该寻找其他方法来实现您的基本目标。

如果 ABI 确实指定所有参数都放在堆栈上,那么可以在包含 unsigned char 数组的结构中传递任意参数:

  • 必须确定最大大小,例如 struct { unsigned char bytes[128]; },因为标准 C 不支持可变大小的结构。
  • 对于任何具有最严格对齐的参数,结构必须按照要求对齐。
  • 所有参数的字节必须在结构中正确对齐。
  • 将通过将结构本身作为参数传递来调用该函数。注意 ABI 必须说即使是大型结构也直接在堆栈上传递。有人可能会说传递了一个指向结构(副本)的指针。

请注意,ABI 可能包含影响函数调用的其他细节,例如说某个寄存器必须包含参数的数量或以某种方式设置,即使它本身不包含参数。

【讨论】:

  • 如果我将问题限制在 i386 Linux 上怎么办?根据这个stackoverflow.com/questions/2535989/…,函数调用约定是所有参数都以相反的顺序在堆栈上传递
  • @Binabil:也许吧。如果所有参数都在堆栈上传递,则传递char 的数组会有所不同——C 将数组转换为指针并传递它。如果参数正确定位在包含unsigned char 数组的结构中(具有正确的对齐方式),那么这样的组合可能会起作用。但标准 C 没有可变长度结构,因此您需要设置最大大小。
  • 假设所有参数一起可以占用的最大字节数。我如何将这样的结构传递给函数?只是一个指向结构的指针就可以了吗?如果 struct Mystr x 是我的结构,我应该使用 ((void()(struct Mystr))sym)(&x) 调用该函数? (假设函数返回类型为 void)?
猜你喜欢
  • 2017-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多