2

我需要向匿名管道写入类似的东西double (*fun)(double),但以下WriteFile(pipe, fun, 4, written_bytes, 0)导致管道接收器出现错误 while ReadFile(read_pipe, fun, 4, written_bytes, 0)。有什么方法可以做到这一点吗?

我有个主意。我可以创建一个具有相同类型字段的结构:

struct Foo
{
    double (*f)(double);
};

然后我写它WriteFile(hWritePipe_StdIN, &to_process, sizeof(Foo), &bytes, 0); 但我有问题,管道接收器永远不会结束读取数据: ReadFile(hReadPipe, &to_process, sizeof(Foo), &bytes, 0);

4

5 回答 5

2

它存在一些问题:

首先,你应该知道函数的大小。如果你这样做,你只需打电话WriteFile(pipe, funcPtr, funcSize, ...)转移它。

其次,该函数应该只包含与位置无关的代码,并且不处理任何数据。例如,这样的功能将不起作用:

double fun(double x)
{
    int arr[10000]; // implicit function call (alloca or something like this)
    printf("some");
    static int some = 1;
    return globalVal + (++some);
}

因为函数printf将具有不同的地址,并且在另一个进程中不会有静态变量和字符串。
(好吧,也许您也可以传输数据,但您无法生成 PI 代码。)

因此,有了所有这些限制,您可以发送一个函数:

__declspec(naked) double fun(double x) { __asm ret }

const auto funcSize = 1;
WriteFile(pipe, &fun, funcSize, ...);
于 2012-12-14T12:20:05.083 回答
2

在本机代码中,您不能将函数(代码)本身发送到相同的进程或不同的进程。(您可以尝试像@Abyx 建议的那样进行低级黑客攻击,但它严重限制了代码可以执行的功能,并且可能会让您不得不在汇编程序中手动编写所有代码。)

您也不能将函数的地址发送给另一个进程,因为每个进程都有自己独立的地址空间;在另一个进程中,该地址将包含不同的数据。

解决方案是创建一个共享库(最好是动态的),其中包含所有可能以这种方式发送的函数。为每个函数分配一些标记(例如编号或名称),让 DLL 维护标记和地址之间的映射。然后改为发送标签。

于 2012-12-14T12:35:56.353 回答
1

你在这里想要达到什么目的?您真的要编写函数本身吗?为什么?这不是您在 C++ 中可以轻松完成的事情,例如,因为函数的大小没有明确定义。

您可能应该编写data,即返回的数字fun()

const double value = fun(input);
DWORD numberOfBytesWritten;
WriteFile(pipe, &value, sizeof value, &numberOfBytesWritten, NULL);

您当然应该添加代码来检查输出。请注意,像这样编写二进制数据可能很脆弱。

于 2012-12-14T11:56:59.750 回答
1

由于您使用的是 WinAPI,因此发送函数的本机方式是通过 COM。特别是,将函数公开为 COM 对象上的方法,获取 COM 名字对象,然后发送该名字对象。名字对象可以被序列化并通过管道发送。另一方可以反​​序列化名字对象并访问您的对象。

在水下,这通过在 COM运行对象表中查找对象来工作

于 2012-12-14T12:35:36.720 回答
0

看到这在 C++ 中是多么复杂且容易出错(并且只适用于非常有限的一组函数),我建议您为此使用脚本语言。除了已经提到的之外,指令缓存和 DEP 是您必须考虑的另外两件事。

真的。将函数作为脚本传输,然后在另一端运行。拯救自己的痛苦。

Angelscript 的外观和感觉几乎与 C++ 相似,因此它可能是一个可能的候选者。

现在,如果你反对这一点,因为你需要一些脚本无法做到的事情,请知道:在这种情况下,C++ 也无法做到。

除了上面提到的 PIC 代码问题 (@Abyx) 以及您无法安全或可移植地知道函数大小的事实之外,您可以想象通过管道发送并以有意义的方式执行的唯一 C++ 函数是严格的 const 函数。在这里, const 是 GCC 的意思__attribute__((const)),而不是 C++const关键字。

也就是说,任何这样的函数都不能检查除了它的参数之外的任何值,并且除了返回值之外没有任何影响。原因很明显:不同的进程存在于不同的地址空间中,因此您引用的任何内容都是没有意义的。你改变的任何东西都是没有意义的。
现在,这正是脚本可以以安全、直接且可靠的方式执行的操作。考虑到您已经通过管道发送代码,开销可以忽略不计。

于 2012-12-14T12:30:49.477 回答