継続ライブラリ libcont を書いたよ

libcont という継続ライブラリを書いてみました。

何ができるの?

ある場所で状態を保存し、その後その場所から実行を再開できます。
setjmp/longjmp では実現できない深い方向へのジャンプ可能なのが特徴です。

動作環境

Linux (IA32) で動くと思われます。
ビルドには nasm が必要です。( gas で書き換えたい)
動作確認ができているのは以下の自分の環境のみです。

nobita% uname -a
Linux nobita 2.6.17-10-generic #2 SMP Tue Dec 5 22:28:26 UTC 2006 i686 GNU/Linux

サンプルコード

cont_save で状態を保存し、cont_restore でジャンプします。( setjmp / longjmp と使いかたは同じです )

int cont_save(Cont* c);
void cont_restore(Cont* c, int return_value);


このように深い方向へのジャンプが可能です。
stack_destroy はあえて不定なスタックを演出しています。

#include "cont.h"

static int func1(int counter);
static void stack_destroy(int counter);

static Cont c;

void jmp_inside_test()
{
    int ret = func1(0);
    if (ret != 0)
    {
        printf("jmp inside OK\n");
        return;
    }
    stack_destroy(0);
    cont_restore(&c, 1);
}

int func1(int counter)
{
    if (counter == 5)
    {
        int ret = cont_save(&c);
        if (ret == 0)
        {
            return ret;
        }
        else
        {
            printf("jmp inside OK [%d]\n", counter);
            return ret;
        }
    }
    printf("func1 : %x\n", counter);
    int ret = func1(counter + 1);
    printf("func1 : %x\n", counter);
    return ret;
}

void stack_destroy(int counter)
{
    if (counter == 500)
    {
        return;
    }
    stack_destroy(counter + 1);
}

仕組みとか

cont_save 呼出し時にスタックベースから現在のスタックまでをまるごとヒープに保存しています。
cont_restore 時にヒープからスタックに戻しています。
その際に、復帰先のスタックアドレスにあわせて、ヒープに保存されたスタックの中身やレジスタを書き換えています。

現在抱えている問題

  • スタック開始アドレスの取得がいいかげんです。
    • Binary Hacksの Hack #75 を試してみたのですが、libcont 側の問題でうまくうごかず。
  • 復帰先のスタックのアドレスがいいかげんです。
  • nasm が必要
    • gas 形式で書いた方が良いね

移植とか

以下のような問題を考慮すればたぶん簡単に移植できると思います。

  • スタックの成長方向の検知
  • スタックの開始位置

謝辞

id:shotaro_tsuji さんが monalibc に提供してくださっている独自の setjmp/longjmp を内部で使用しています。
ありがとうございます。


id:shinichiro_h さんが紹介してくれた libpcl などを参考にしています。
ありがとうございます。


shiro さんにコメントいただいた点に注意して作りました.ありがとうございます。

最後に

ツッコミ/パッチ等、大歓迎です。