オペレーティング システムのクラス用に xv6 カーネルの拡張機能を作成しようとしていますが、奇妙なバグに遭遇し、5 時間も費やしてしまいました。シグナル処理関数と引数を手動で命令ポインターに挿入するシグナル処理システムを実装しました。現在、揮発性レジスターの値をユーザースタックにプッシュして保存し、シグナルハンドラーの後に元のレジスターにポップして保存しようとしています。戻り値。
スタック フレームの設定方法は次のとおりです。
void handle_signal(int signo, struct trapframe *tf){
*((uint*)(tf->esp-4)) = tf->eip;
*((uint*)(tf->esp-8)) = proc->tf->eax;
*((uint*)(tf->esp-12)) = proc->tf->ecx;
*((uint*)(tf->esp-16)) = proc->tf->edx;
*((uint*)(tf->esp-20)) = signo;
*((uint*)(tf->esp-24)) =(uint)proc->pop;
tf->esp = tf->esp-24;
tf->eip = (uint)(proc->sigHandlers[signo]);
}
そのため、スタックの一番下を古い命令ポインターに設定し、揮発性レジスターをプッシュし、シグナル ハンドラー引数をプッシュし、レジスターをポップする関数をプッシュし、最後に eip (命令ポインター) をシグナルハンドラのアドレス。
void
popregs(void){
sleep(5);
__asm__ (
"add $16, %esp;"
"pop %edx;"
"pop %ecx;"
"pop %eax;"
"ret");
}
レジスタをポップするために使用している関数は次のとおりです。本当に奇妙なのは、インライン アセンブリの直前に sleep(5) または printf() ステートメントがある場合、プログラムが正しいことを行う (レジスタの値を正しく保存する) ことですが、それを削除すると、私が想定している「範囲外コード」ステートメントは、セグメンテーション違反に相当する xv6 です。レジスタの値が正しく保存されたとしても、ハンドラーが後のシグナル処理呼び出しで失敗するため、スタックがめちゃくちゃになっていることがわかります。
アセンブリをうまくデバッグする方法がよくわからないので、これに対処するのに苦労しています-何が起こっているのか誰にもわかりませんか?