如何在运行时在c中定义新函数?

如何在运行时在c中定义新函数?,c,function,C,Function,在c语言中,您可以将代码复制为内存块,因此我想知道是否是由一些开发人员完成的,或者是将函数的代码复制到堆中分配的块中,在堆中更改函数的代码,然后(mprotect…)执行“复制和修改”函数,这是明智和安全的,从安全角度来看,让堆块保持可执行状态可能会产生什么后果。或者有没有一种方法可以运行运行时在c中定义的代码 void* handler(void* arg1, void* arg2, void* arg3) { typedef void* (*function)(void*, void

在c语言中,您可以将代码复制为内存块,因此我想知道是否是由一些开发人员完成的,或者是将函数的代码复制到堆中分配的块中,在堆中更改函数的代码,然后(mprotect…)执行“复制和修改”函数,这是明智和安全的,从安全角度来看,让堆块保持可执行状态可能会产生什么后果。或者有没有一种方法可以运行运行时在c中定义的代码

void* handler(void* arg1, void* arg2, void* arg3) {
    typedef void* (*function)(void*, void*, void*, void*);
    return ((function)FUNCTION_ADDRESS_TO_REPLACE)(SELF_ADDRESS_TO_REPLACE,
                                                   arg1,
                                                   arg2,
                                                   arg3);
}


void* allocate_new_function(void* function, void* self) {
    void* (*fun) () = 0;
    uint64_t size = (uint64_t) &allocate_new_function - (uint64_t) &handler; //48 byte
    fun = malloc(size);
    memcpy(fun, handler, size);
    replace(fun, size, SELF_ADDRESS_TO_REPLACE, self);
    replace(fun, size, FUNCTION_ADDRESS_TO_REPLACE, function);
    char *to_mprotect = (char*) (((uint64_t) fun / PAGE_SIZE) * PAGE_SIZE);
    uint64_t offset = (uint64_t) fun % PAGE_SIZE;
    if (offset + size > PAGE_SIZE) {
        mprotect(to_mprotect,
                 PAGE_SIZE,
                 PROT_READ | PROT_EXEC | PROT_WRITE);
        mprotect(to_mprotect + PAGE_SIZE,
                 PAGE_SIZE,
                 PROT_READ | PROT_EXEC | PROT_WRITE);
    } else {
        mprotect(to_mprotect,
                 PAGE_SIZE,
                 PROT_READ | PROT_EXEC | PROT_WRITE);
    }
    return fun;
}
此处,分配的_函数将使用隐式参数self执行函数“function”。有没有更好的方法来做到这一点,或者这种方法可能是有效的

配置为:--prefix=/Applications/Xcode.app/Contents/Developer/usr--gxx include dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1 Apple clang版本12.0.0(clang-1200.0.32.29) 目标:x86_64-apple-darwin20.2.0 线程模型:posix
InstalledDir:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xToolchain/usr/bin

mprotect
不保证与通过
mmap
获取的内存一起工作。因此,您最好通过
mmap
调用分配内存,而不是
new
。您还依赖于生成的对象文件中函数的特定顺序,但没有任何东西可以保证这一点。函数可以以编译器或链接器选择的任何顺序出现,因此您提取函数大小的方法存在严重缺陷。是的,这是事实,但偏移量必须是页面大小的倍数,因此如果多次调用allocate_new_函数,我将浪费大量内存,如果程序崩溃,页面将保持映射状态是的,我尝试过这样做,但是我可以假设函数的最大大小,而不是精确计算值,因为处理程序非常小,替换函数在找到第一个特殊地址时停止。无论如何,您必须为代码块设置一个专用页面,否则您将更改随机内存的权限。如果您不想浪费页面,您必须实现自己的分配器,它通过mmap请求内存并使用可用页面中的内存,直到用完为止。您正在做的事情是可以做到的——毕竟,这是任何JIT优化器正在做的事情——但它需要谨慎和深思熟虑的方法才能达到生产级。作为概念证明,您的代码很好。