3

オペレーティング システムのクラス用に 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 です。レジスタの値が正しく保存されたとしても、ハンドラーが後のシグナル処理呼び出しで失敗するため、スタックがめちゃくちゃになっていることがわかります。

アセンブリをうまくデバッグする方法がよくわからないので、これに対処するのに苦労しています-何が起こっているのか誰にもわかりませんか?

4

1 に答える 1