2016-11-02 9 views
1

システムコール "clone()"を使用してxv6でスレッドを作成したいが、スレッドを作成したい場合はスタックの作成について混乱している。 ebp、esp、eipなどの対応するレジスタポインタを作成します。しかし、私はこれらのレジスタポインタの値を設定する方法を知らない。ここでxv6でスレッドを作成する際にポインタを登録する

は(クローンのコードです)私たちは、このようなレジスタポインタの値を設定する必要がある理由xv6で、私にはわからない.......

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; 

} 
+0

'クローンを()は必要ありません' Linux-(と明らかにxv6-)固有のものです。 xv6にpthreadがある場合は、代わりにそのインターフェイスを使用することを強くお勧めします。 –

答えて

1

あなたは「ドンこれらのレジスタを設定する - クローンがそれらを設定します。あなたは関数(クローンがIPを初期化するために使用する)とスタック(クローンがspを初期化するために使用する)を提供する必要があります。

関数ポインタはかなり単純です(そのC関数ポインタだけですが)、スタックはトリッキーです。 cloneの実装では、いくつかのメモリを割り当てて、そのブロックのの末尾にPGSIZEのポインタを指定する必要があります。 Linuxのクローンコールは似ていますが、少し異なります(ブロックの最後にポインタを置く必要があります)。スタックオーバーフローをキャッチしたい場合は、もっと多くの作業が必要になります(スタックの下に読み書き可能な保護ガードページを割り当てている可能性があります)。あなたが設定されたすべてのレジスタの値の

+0

私はこのシステムコールclone()の使用方法を知っていますが、この関数のレジスタポインタについて混乱しています。なぜこのように設定できるのかを知りたいのですが – zyz

+0

私はあなたの質問を理解できません。あなたが与えた引数に基づいて新しいスレッドのスレッドが登録されます。スケジューラが新しいスレッドに切り替わったときに関数が呼び出されるように、スレッドのレジスタを設定する必要があります。 –

+0

たとえば、np-> tf-> eaxが0に等しい理由はわかりませんが、それはebb – zyz

1

、のみ有用なものは以下のとおりです。

EIP - それはESP

をユーザ空間に戻ってから実行を開始するスレッドを伝えます - これがポイントですスタックの上部に移動します。これは、あなたがこの権利をした場合、スタックの最上位に保存された4つのバイトがあなたのリターンアドレス


EAXを含まなければならないことを意味し、スレッドが新しいコンテキストにジャンプしないよう見て、ここでは本当に便利ではありませんそれが作成された場所です。それ以外の場合は、eaxには最後のシステムコールの戻り値が格納されます。これについてまだ混乱している場合は、forkの実装を参照してください。

EBPはあなたによってではなく、x86の関数呼び出し規約によって操作されておらず、通常は関数が呼び出されたESPの値に設定されています。そのように、あなたは通常、ほとんどの機能の解体にこの種のものを見ることができます EBP

push ebp  ; Preserve current frame pointer 
mov ebp, esp ; Create new frame pointer pointing to current stack top 

を呼び出し、それがその後のポイントに変更される前に、それは前の関数のスタックの先頭を格納するため、また、スタックトレースするのに便利です現在のスタックトップ


にあなたがこの*(ustack - 2) = 0xffffffff;

関連する問題