Linuxの備忘録とか・・・(目次へ)Linuxの備忘録とか・・・(目次へ)forkの返り値forkは、copy_processで親プロセスディスクリプタを雛形にして、clone_flagsのオプションに応じた子プロセスのプロセスディスクリプタが作成し、その子プロセスIDを返り値としている。従って返り値が0でない親プロセス処理と、0である子プロセス処理として記述していくことができる。ユーザプロセスからforkを呼び出すと、glibがユーザスタックに詰まれた引数をレジスターに設定しなおす。カーネルへ処理がわたると、カーネルスタックとしてプロセス毎のthread_structにスタックが切り替わるからである。80hでカーネルプロセスに切り替わり、systm_callがコールされる。この時点からカーネルスタックとなる。80を呼び出す前に、ユーザプロセスから渡された引数はレジスターに設定しているわけで、これ等のレジスタを含めて他のレジスターをこのカーネルスタックに積みなおすことで、カーネル側でもC呼び出しによるスタック参照で値の受け渡しができるようになっている。systm_callではAXレジスタに設定されたファンクションコードをインデックスとして、該当する処理をコールする。その処理からリターンすると、返り値はAXレジスターに入っている。Cで記述されているわけで、カーネルモードといえども同じことだ。80hにリターンすることでAXレジスターをシステムコールの返り値として、ユーザプロセスへと渡っていくようになっている。カーネルスタックは、それぞれのプロセスディスクリプタのthread_structに設定している。従って子プロセスのプロセスディスクリプタのthread_struct内のスタック領域のAXがpushされる箇所に、子プロセスの返り値である0を設定すればいいわけだ。子プロセスもforkの後から走り出す。そのためには、子プロセスのカーネルスタックは親のカーネルスタックと同じにする必要がある。task_struct->thread.ipにはタスクスイッチ直後の実行アドレスを設定するようになっており、通常はスイッチされた直後から走り出すようになっているのだが、fork直後の子プロセスはret_from_forkから走りだすようになっている。systm_callは該当システムコールからリターンして後、カーネルスタックからpopして、レジスター群を復帰している。80Hをコールする前のユーザプロセスでのレジスタ値である。従ってiretでユーザプロセス(glib内)にリターンすることで、AXをforkの返り値として処理することが可能である。80hのところ、すなわちユーザプロセスの呼び出し元forkにリターンすることができる。err;子プロセスのthread_struct内のレジスター群をpopしている位置を求める。task_pt_regs(p);親プロセスのスタック内のレジスター群regsを子プロセスのスタックに設定する。*regs;なお返り値に子プロセスとして0を設定する。(childregs+1);スイッチングで子プロセスにスイッチングされるとret_from_forkから走り出す。ノースAdsense広告情報が設定されていません。