我有这个代码,给我一个分割错误。我对克隆函数的理解是,父进程必须为子进程分配空间,克隆调用在该堆栈空间中运行的函数。是我误解了什么,还是我的代码没有意义?
char *stack;
char *stackTop;
stack = malloc(STACK_SIZE);
if (stack == NULL)
fprintf(stderr, "malloc");
stackTop = stack + STACK_SIZE;
myClone(childFunc, stackTop, CLONE_FILES, NULL);
int myClone(int (*fn)(void *), void *child_stack,int flags, void *arg){
int* space = memcpy(child_stack, fn, sizeof(fn));
typedef int func(void);
func* f = (func*)&space;
f();
}
这不起作用有两个主要原因。
-
内存保护:相关内存页必须是可执行的。数据页,你从
malloc
得到的不是。"正常的"内存管理函数不能这样做。另一方面,现有的代码页是不可写的,因此您不能将一段代码移动到另一段代码上。这是一种基本的内存保护机制。你要么回到DOS,要么使用一些高级的"调试"界面。 -
位置无关代码:代码中的所有内存地址必须是相对的,或者手动修复。在c中这样做可能太棘手了。
clone()
函数是系统调用。它不能被运行在进程中的C代码复制。
这里有一个基本的误解。所以你得到一个分段错误,这告诉我你试图在用户空间(在操作系统创建的进程中)运行这段代码。
地址空间是操作系统可用的抽象。它通常使用硬件支持(MMU[内存管理单元]),它提供了使用虚拟地址的方法。这些地址在被访问时,会根据一些只有操作系统才能管理的数据结构自动转换为真实的物理地址。
我认为在这里讲太多细节没有多大意义,你有足够的关键词可以谷歌搜索。本质是:没有办法从用户空间代码创建地址空间。这个功能是保留给操作系统的,为了做到这一点,linux上的clone()
发出一个系统调用,调用操作系统。
edit:关于堆栈,提供堆栈意味着为它保留空间(通过将适当数量的页面映射到地址空间)和设置必要的处理器寄存器,当上下文切换到进程时(例如i386
上的esp
/ebp
)。这也是只有操作系统才能做到的。