OSを書き込もうとすると、タスク切り替えのために現在の関数の終了アドレス(エピローグの直前)を取得する必要があります。
具体的には、私の問題は、コピーされたスタック内に新しく作成されたタスク(プロセス)に割り当てるEIPを取得することです。私は既にプロセスのレジスタを保存/復元することができましたが、子プロセスがEIPにどのような価値があるのかを知る必要があります。 GCC - ラベルアドレスは実際のラベルアドレスではなく現行のEIPを返します
をドキュメントから: あなたは単項演算子「& &」で現在の関数で定義されたラベルのアドレス(または含む関数)を取得することができます。値の型はvoid *です。
および: GCCでは、ネストされたブロックスコープ内のローカルラベルを宣言できます。ローカルラベルは通常のラベルと同じですが、宣言されているブロック内でのみ参照することができます(gotoステートメントで、またはそのアドレスを取ることによって)。
pid_t fork(void)
{
__label__ fork_end;
...
task->regs.eip = (uintptr_t)&&fork_end;
...
return task->pid;
fork_end:;
}
GCCは、非標準のコードについてだけ警告して、それをコンパイルしません。解体時に
はしかし、GDBは示しています
task->regs.eip = (uintptr_t)&&fork_end;
0x00105008 <+87>: mov $0x105008,%edx
0x0010500d <+92>: mov -0xc(%ebp),%eax
0x00105010 <+95>: mov %edx,0x40(%eax)
...
fork_end:;
}
0x00105096 <+229>: leave
0x00105097 <+230>: ret
私はtask->regs.eip = (uintptr_t)&&fork_endl
が0x00105096
ではなく0x00105008
を救うことを期待しています。
CFLAGS
は-O0 -std=gnu99 -fgnu89-inline -DDEBUG -ggdb3 -ffreestanding -fbuiltin
です(警告関連のオプションはここには表示されません)。
コメント__label__ fork_end;
は何も変更されません。
'&&'についてのgccのドキュメントへの参照を提供してください。拡張機能を使用するときは警告しません。 [ask]を参照し、必要な情報をすべて入力してください。 – Olaf
編集され、@Olaf、gccは '-Wpedantic'オプションで非標準コードについて警告します。あなたのアドバイスをありがとう。 – Aerath
ああ、そうです。拡張子付きの '-Wpedantic'を使うのは悪い考えです。とにかく、あなたのキャストは実装定義であり、 'uint32_t'はポインタを保持するためには求められず、1:1割り当てもありません。 64ビットシステムでは、すでに破棄されています。少なくとも、正しいタイプを使用してください。ポインタとして 'void * 'を使わず、整数を使う理由は何ですか? – Olaf