将现有函数复制到内存缓冲区

5

我正在尝试将一个函数加载到映射的内存缓冲区中,并稍后调用它,因此我制作了一个测试用例来尝试:

auto func() -> void{
    asm(
        "nop;"
        "nop;"
        "nop;"
        "nop;"
    );
}

auto main(int argc, char *argv[]) -> int{
    void *exec_mem = mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    // check errors here

    memcpy(exec_mem, reinterpret_cast<const void*>(func), 5); // size is known
    (reinterpret_cast<void(*)()>(exec_mem))(); // function call

    munmap(exec_mem, getpagesize());
}

这个很正常,但只要我尝试去做一些简单的事情,就会出现段错误。

我试图执行一个简单的变量赋值,像这样:

int x;
auto func() -> void{
    x = 5;
}

现在我的函数调用导致了段错误。我已经适当地更改了缓冲区大小,并确信正确的内存被写入了缓冲区。
我缺少什么重要的信息?为什么我不能这样做?
附言:请不要对我进行不安全代码的演讲,这是一个简单的个人学习练习。

@EdHeal 是的,我不是以编程为职业。 - RamblingMad
1
只是好奇,这个语法是什么意思:`auto / ->'?以前从未见过。 - Eugene Sh.
@EugeneSh。C++11的尾随返回类型语法。在这种情况下使用它非常简单;我只是随意决定使用它哈哈。 - RamblingMad
这些东西是在嵌入式系统上完成的吗?感觉像是操作系统访问违规类型问题 - 你知道你不被允许修改代码或运行数据类型。我曾经在非常小的系统中看到并编写过像你的代码一样自修改的代码,但在有实际操作系统支持的系统上没有。 - Michael Dorgan
@EugeneSh。啊,相对内存位置!你应该把它写成一个答案,我会接受的。 - RamblingMad
显示剩余8条评论
1个回答

4
忽略这是明显的未定义行为,如果你对全局变量进行赋值,生成的代码可能会在某些架构上使用相对寻址来引用该变量。
也就是说,函数期望自身和x位于给定地址,如果移动它,事情就会出错。
这是我的GCC为你的测试函数生成的代码:
x:
        .zero   4
        .text
        .globl  _Z4funcv
        .type   _Z4funcv, @function
_Z4funcv:
.LFB2:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $5, x(%rip)
        nop
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc

请注意movl $5, x(%rip),这意味着代码使用自己的地址(存储在%rip中)来计算x的位置并将5存储在其中。因此,简而言之,除非确保函数仅具有位置无关代码,否则没有简单的方法可以实现您要尝试的操作。即使如此,也只会引起麻烦。

你知道如何让GCC为单个函数生成位置无关代码吗? - RamblingMad
1
@CoffeeandCode 你可以将该函数放在自己的文件中,并使用 -fPIC 编译该文件。 - tux3
看起来有点麻烦,如果找不到其他方法,我会采取这种方式。谢谢你的回答 :) 我明白其中涉及的风险,但我需要期望的行为,并且不会在任何其他项目中使用类似的东西。 - RamblingMad
@CoffeeandCode 你应该看看JIT库,也许更适合你想做的事情? - tux3
1
我基本上正在制作一个JIT编译器,所以你说得很对。但是我将把它移植到嵌入式系统中,并且需要非常少的依赖关系。 - RamblingMad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接