I'm trying to load a function into a mapped memory buffer and call it later so I've made a test case to try out:
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());
}
Which works fine, but as soon as I try to do something even trivial I get a segfault.
I tried to do a simple variable assignment like this:
int x;
auto func() -> void{
    x = 5;
}
and now my function call segfaults. I have changed the buffer size appropriately and am certain the correct memory is being written into the buffer.
What important piece of information am I missing here? Why can't I do this?
P.S. Please don't lecture me on unsafe code, this is a simple personal learning exercise.
Ignoring the fact that this is blatant undefined behavior, if you do an assignment of a global variable, the generated code is likely to use relative addressing to reference the variable on some architectures.
That is, the function expects itself and x to be at a given address, and if you move it, things break.
This is what my GCC generates for your test function:
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
Note the movl    $5, x(%rip), which means that the code uses its own address (stored in %rip) to compute the position of x and store 5 in it.
So in short, there's no simple way to do what you're trying to do, unless you make sure that your function only has position-independent code. And even then, it's only asking for trouble.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With