signal trampoline

またBSD本ネタですが、BSDの実装ではsignalが呼ばれた際にsignal contextとsignal handlerをスタック上に確保し、sigreturnで返ってくるという実装が用いられています。これをsignal trampoline codeと呼ぶそうです。

しかしgniibe先生のcodeblogを見るとどうも最近のlinuxではstruct sigactionのsa_restorerを使用するというような記述が有りますね。

restorer = &__kernel_sigreturn;
if (ka->sa.sa_flags & SA_RESTORER)
  restorer = ka->sa.sa_restorer;

/* Set up to return from userspace.  */
err |= __put_user(restorer, &frame->pretcode);

...

/* Set up registers for signal handler */
regs->esp = (unsigned long) frame;

こんな所も結構時代に沿って変わっているんですね。おもろい。これ使えばsignalが"返る"時をキャッチ出来るかなと思って、こんな感じのコードを書いてみた。

#include <stdio.h>
#include <signal.h>

/* from asm/i386.h */
#define SA_RESTORER     0x04000000

void sig_start(int signum)
{
    printf("sig start\n");
}
void sig_return(void)
{
    printf("sig return\n");
    sigreturn(1); /* 駄目 */
}
int main(void)
{
    struct sigaction act, old;
    act.sa_handler  = sig_start;
    act.sa_restorer = sig_return;
    act.sa_flags    = SA_RESTORER;

    sigaction(SIGINT, &act, &old);

    kill(getpid(), SIGINT);
}

しかしsigreturnはuser spaceからは呼べないようになっているのか、link時にエラーが。うーん、単純にC言語の関数を指定するだけじゃ駄目なんだろうな。関数から戻る時にsigreturnを使用しないといけないのだから。Cからはこういうの指定出来なさそうだ。

飛行機の中で思い付いたネタが2本とも没...。