[英]Register pointer in creating threads in xv6
我想使用系统调用“ clone()”在xv6中创建线程,但是我对堆栈的创建感到困惑,因为如果我要创建线程,则需要创建相应的寄存器指针,例如ebp,esp ,eip。 但是我不知道如何设置这些寄存器指针的值。
这是xv6中的clone()代码,我不知道为什么我们需要像这样设置寄存器指针的值。
int clone(void(*fcn)(void*), void *arg, void*stack){
int i, pid;
struct proc *np;
int *ustack = stack + PGSIZE - sizeof(void*);
//allocate process.
if((np=allocproc()) == 0)
return -1;
//copy process state from p
np->pgdir = proc->pgdir;
np->sz = proc->sz;
np->parent = 0;
np->pthread = proc;
*np->tf = *proc->tf;
np->ustack = stack;
//initialize stack variables
//void *stackArg, *stackRet;
//stackRet = stack + PGSIZE -2*sizeof(void*);
//*(uint *)stackRet = 0xffffffff;
//stackArg = stack + PGSIZE -sizeof(void*);
//*(uint *)stackArg = (uint)arg;
*ustack = (int) arg;
*(ustack - 1) = 0xffffffff;
*(ustack - 2) = 0xffffffff;
//Set stack pinter register
np->tf->eax = 0;
np->tf->esp = (int) ustack - sizeof(void*);
np->tf->ebp = np->tf->esp;
np->tf->eip = (int)fcn;
for(i = 0; i < NOFILE; i++) {
if(proc->ofile[i])
np->ofile[i] = filedup(proc->ofile[i]);
}
np->cwd = idup(proc->cwd);
np->state = RUNNABLE;
safestrcpy(np->name, proc->name, sizeof(proc->name));
pid = np->pid;
return pid;
}
您无需设置这些寄存器-克隆将为您设置它们。 您需要提供一个函数(该克隆用于初始化ip)和一个堆栈(该克隆用于初始化sp)。
函数指针很简单(它只是一个C函数指针),但是堆栈比较棘手。 对于clone
告诉你执行,你需要分配一些内存,并提供一个指针PGSIZE
该块的端部下方。 Linux的克隆调用类似,但略有不同(您需要提供一个指向块末尾的指针)。 如果要捕获堆栈溢出,则需要做更多的工作(可能在堆栈下方分配一个受读/写保护的保护页)。
在您设置的所有寄存器值中,唯一有用的是:
eip-告诉线程从返回用户空间时开始在哪里执行
esp-这指向堆栈的顶部。 这意味着,如果您正确执行此操作,则存储在堆栈顶部的4个字节应包含您的返回地址
当线程跳转到一个新的上下文而不是创建它的地方时, eax在这里并不是真正有用的。 否则, eax将存储上一个系统调用的返回值。 如果您仍然对此感到困惑,请参阅fork
的实现。
ebp不是由您操纵的,而是由x86函数调用约定来操纵的,通常在调用函数时将其设置为esp的值。 这样,您通常会在大多数函数调用的反汇编中看到这种情况
push ebp ; Preserve current frame pointer
mov ebp, esp ; Create new frame pointer pointing to current stack top
ebp对于堆栈跟踪也很有用,因为它存储前一个函数堆栈的顶部,然后再将其更改为指向当前堆栈顶部
您不需要这个*(ustack - 2) = 0xffffffff;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.