我试图编写一个函数来复制一个函数(并最终修改其程序集)并返回它。对于一个间接级别来说,这很好用,但在两个级别上,我都遇到了段错误。
这是一个最小的(不)工作示例:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#define BODY_SIZE 100
int f(void) { return 42; }
int (*G(void))(void) { return f; }
int (*(*H(void))(void))(void) { return G; }
int (*g(void))(void) {
void *r = mmap(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy(r, f, BODY_SIZE);
return r;
}
int (*(*h(void))(void))(void) {
void *r = mmap(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy(r, g, BODY_SIZE);
return r;
}
int main() {
printf("%d\n", f());
printf("%d\n", G()());
printf("%d\n", g()());
printf("%d\n", H()()());
printf("%d\n", h()()()); // This one fails - why?
return 0;
}
我可以一次将内存转移到mmap'ed区域中,以创建一个可以称为(g()())的有效函数。但是,如果我尝试再次应用(h()()()),则会出现段错误。我已经确认它可以正确创建的复制版本g,但是当我执行该版本时,就会出现段错误。
我为什么不能在一个mmap'ed区域中执行代码而又不能在另一个mmap'ed区域中执行代码呢?从带有x/i检查的探索性gdb-ing看来,我可以成功调用,但是当我返回该函数时,我所来自的函数已被擦除并替换为0。
如何使这种行为起作用?可能吗?