2013-02-27 64 views
3

我不知道linux进程是否可以调用位于另一个进程的内存中的代码?Linux:是否可以在进程之间共享代码?

假设我们在进程A中有一个函数f(),并且我们希望进程B调用它。我想过的是,使用带MAP_SHARED和PROT_EXEC标志的mmap映射包含函数代码的内存,并将指针传递给B,假设f()不会从A二进制文件调用任何其他函数。它会工作吗?如果是,那么我如何确定内存中f()的大小?

===编辑===

我知道,共享库将做到这些,但我不知道是否有可能在进程之间动态共享代码。

+5

不是直接。请使用动态库或[RPC](http://en.wikipedia.org/wiki/Remote_procedure_call)。 – 2013-02-27 14:13:07

+0

这正是库的用途。根据你将要完成的任务,[IPC](http://www.tldp.org/LDP/lpg/node7.html)也可能会这样做。 – KBart 2013-02-27 14:16:55

+0

您想共享的代码是由编译器生成的,还是由您的程序生成的? – ams 2013-02-27 14:22:16

回答

5

是的,您可以这样做,但第一个进程必须首先通过mmap和内存映射文件或使用shm_open创建的共享区域创建共享内存。

如果您正在共享编译代码,那么这就是共享库创建。您可以通过普通的方式与他们进行链接,共享将自动发生,或者您可以使用dlopen(例如,用于插件)手动加载它们。


更新:

由于代码已经由编译器产生的,那么你将有搬迁担心。编译器不会生成任何可以正常工作的代码。它预计.data部分位于某个位置,并且.bss部分已归零。 GOT将需要填充。任何静态构造函数都必须被调用。

总之,你想要的可能是dlopen。这个系统允许你像打开一个文件一样打开共享库,然后按名称提取函数指针。程序库中的每个程序都将共享代码段,从而节省内存,但每个程序都将拥有自己的数据段副本,因此它们不会相互干扰。

请注意,您需要使用-fPIC来编译您的库代码,否则您将无法获得任何代码共享(实际上,许多架构的链接器和动态加载器可能不支持不是PIC的库) 。

+0

我其实从来没有尝试从mmaped内存运行代码..它真的有效吗?如何权限? – KBart 2013-02-27 14:18:52

+0

@KBart:只要设置了PROT_EXEC权限,就应该工作。当然,并非所有的体系结构都支持该标志,但在大多数情况下,您无法停止它的工作。 – ams 2013-02-27 14:20:42

+0

很好。也许你可以举个小例子吗?我相信这正是这个问题无论如何。 – KBart 2013-02-27 14:22:06

4

标准方法是将代码f()置于共享库libfoo.so中。然后,你既可以链接到该库(例如,通过建立程序gcc -Wall a.c -lfoo -o a.bin),或动态地加载(例如,在程序)使用dlopen(3)然后检索的f使用dlsym地址。

当你编译一个共享库要:

  • gcc -Wall -fPIC -c foo1.c -o foo1.pic.o每个源文件foo1.c编译成position independent code,同样为foo2.cfoo2.pic.o
  • 链接所有的人都为libfoo.sogcc -Wall -shared foo*.pic.o -o libfoo.so;注意到可以链接附加共享库lbfoo.so(例如通过附加-lm到连接命令)

又见Program Library Howto

你可以通过mmap来玩疯狂的技巧 - 其他一些/proc/1234/mem但这是不合理的。使用共享库。

PS。你可以dlopen大量(数十万)共享对象lib*.so文件;你可能想要dlclose他们(但实际上你不必)。

2

这是可能的,但这正是共享库的用途。

另外,请注意您需要检查两个进程的共享内存地址是否相同,否则任何引用都是“绝对”(即指向共享代码中的某个指针)。和共享库一样,代码的位必须是相同的,并且与所有共享内存一样,如果修改任何共享内存,则需要确保不会“混淆”其他进程记忆。

根据生成的实际代码以及可用信息的级别,确定函数的大小范围从“硬”到“几乎不可能”。调试符号将具有函数的大小,但要注意,我已经看到编译器会生成代码,其中两个函数共享相同的“返回”代码片段(也就是说,编译器会生成跳转到具有相同代码位的另一个函数返回结果,因为它节省了几个字节的代码,并且无论如何已经有一个跳转[例如编译器必须跳转的if/else])。

相关问题