代码之家  ›  专栏  ›  技术社区  ›  Nick Strupat

是否可以将函数加载到分配的内存中并从那里运行它?

  •  4
  • Nick Strupat  · 技术社区  · 15 年前

    我正在处理一些进程间通信的东西,我很好奇是否有可能将一个函数复制到某个共享内存中,然后从其中任何一个进程运行它。

    memcpy(shared_memory_address, &func, &func + sizeof(func));
    

    我知道你不能接受函数的大小,但这就是我突然想到的。

    7 回复  |  直到 15 年前
        1
  •  4
  •   phadej    15 年前

    理论上,由于函数只是内存中某个位置的字节码序列,因此可以复制函数的内存块并调用(跳入)它。尽管c++抽象了这种可能性,但正如您所注意到的,我们实际上无法知道函数的大小(尽管我们可以得到指向它的指针)。

    不过,还有图书馆。例如,您可以告诉远程可执行文件从动态库加载特定函数并执行它。检查 wikipedia-article

        2
  •  4
  •   Loki Astari    15 年前

    那很有趣。
    请执行以下操作:

    编译日期联想:T61p运行Windows7:使用g++4.3.4

    还要注意的是,函数的类型非常有限:

    在这个例子中,func()做的很少,因此可以工作。
    但是,如果您执行以下任一操作,它将无法移植到其他进程:

    • 调用函数或方法。
    • 传递指针(或引用)
    • 使用globals。
      • 但它所使用的对象必须按值传递。

    以上这些都不起作用,因为一个进程的地址空间与另一个进程的地址空间不相似(因为它在硬件级别映射到物理内存)。

    #include <vector>
    #include <iostream>
    #include <string.h>
    
    int func(int x)
    {
        return x+1;
    }
    
    typedef int (*FUNC)(int);
    
    
    int main()
    {
        std::vector<char>   buffer(5000);
    
        ::memcpy(&buffer[0],reinterpret_cast<char*>(&func),5000);
    
        FUNC func   = reinterpret_cast<FUNC>(&buffer[0]);
    
        int result  = (*func)(5);
    
        std::cout << result << std::endl;
    
    }
    
        3
  •  2
  •   Thomas Matthews    15 年前

    上次我尝试这个方法时,遇到了一个障碍:确定函数中的字节数。任务是使用函数的地址,将字节复制到内存中(前提是代码被编译为位置无关代码PIC)。

    一种更独立于平台的方法是查看编译器文档,看看是否有 #pragma ,编译器选项或关键字,允许您指定函数的地址或段以在加载时加载。

    另外,搜索嵌入式系统组,因为这是一种流行的技术:将编程闪存的代码加载到RAM中,在RAM中执行功能,然后重置系统。

    希望有帮助。


    还可以查看DLL或共享库,它们可以在操作系统的帮助下在运行时加载。

        5
  •  1
  •   karunski    15 年前

    对。类似的技术也被实时代码生成器(如javavm)使用。实际上,您几乎可以说操作系统的运行时加载程序和链接器在将动态库加载到您的进程中时为您这样做。

    不过,您必须从操作系统请求可执行内存。你要跳入的代码必须以允许它位于内存中任何位置的方式编写(位置无关)。

        6
  •  0
  •   rubber boots    15 年前

    如果生成代码字节并将其注入进程,则称为 运行时代码生成(RTCG) look up some examples .

    现代的内核会从一个非特权的层面上阻止它工作, 所以你必须进入正确的模式或者 第一。为了 函数的代码段,直到最后返回代码。

    对于动态光栅操作(取决于问题)。

        7
  •  -1
  •   Paul Nathan    15 年前

    您可以合理地假设这在Linux、Windows或更复杂的嵌入式操作系统上是完全不可能的。

    讨厌的 限制,您可以在程序集中修补一些表示函数开始/结束的保护字节,并使用这些字节帮助您将内容复制到共享内存(当然使用程序集),然后将过程地址列表发布到任何感兴趣的进程(也可以使用程序集访问/运行)。

    当然,动态库系统Linux和Windows提供了一种定义良好的机制,可以为多个进程提供代码库。可能没有你想的那么灵活。:-)

    推荐文章