Lam*_*eta 1 c linux assembly function-pointers currying
我正在尝试编写一个复制函数的函数(并最终修改其程序集)并返回它.这适用于一个级别的间接,但在两个我得到段错误.
这是一个最小(非)工作示例:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我可以记忆到一个mmap的区域,创建一个可以被调用的有效函数(g()()
).但是,如果我再次尝试应用它(h()()()
)它会发生段错误.我已经确认它正确创建了复制版本g
,但是当我执行该版本时,我得到了一个段错误.
我有什么理由不能在另一个mmap的区域中的一个mmap的区域中执行代码吗?从带有x/i
检查的探索性gdb-ing 看起来我可以成功调用,但是当我返回我来自的函数时已被删除并替换为0.
我怎样才能使这种行为起作用?它甚至可能吗?
大编辑:
许多人问我的理由,因为我在这里显然是在做XY问题.这是真实而有意的.你看,一个月之前这个问题发布在代码高尔夫堆栈交换上.它也为C/Assembly解决方案带来了不错的赏金.我对这个问题做了一些空洞的思考,并意识到通过复制一个函数体同时删除一个具有一些唯一值的地址,我可以在其内存中搜索该值并将其替换为有效地址,从而允许我有效地创建lambda函数将单个指针作为参数.使用这个我可以得到单一的currying工作,但我需要更一般的currying.因此,我目前的部分解决方案与此相关.这是展示我试图避免的段错误的完整代码.虽然这几乎是一个坏主意的定义,但我觉得它很有趣,并且想知道我的方法是否可行.我唯一缺少的是运行从函数创建的函数的能力,但我无法让它工作.
代码使用相对调用来调用mmap
,memcpy
因此复制的代码最终会调用无效的位置.
您可以通过指针调用它们,例如:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#define BODY_SIZE 100
void* (*mmap_ptr)(void *addr, size_t length, int prot, int flags,
int fd, off_t offset) = mmap;
void* (*memcpy_ptr)(void *dest, const void *src, size_t n) = memcpy;
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_ptr(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy_ptr(r, f, BODY_SIZE);
return r;
}
int (*(*h(void))(void))(void) {
void *r = mmap_ptr(0, BODY_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy_ptr(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;
}
Run Code Online (Sandbox Code Playgroud)