Skip to content
kamaboko edited this page Mar 18, 2024 · 2 revisions

まだ実装してないとかアイデア程度のメモです

プロセスへの可変長引数の渡し方?

プロセス側の関数シグネチャは一般的にコマンドライン引数を受け取るようにint main(uint8_t argc, char *argv[])とする。
最終的にプロセスのメイン関数(上記のシグネチャの関数)をスタートするときのスタックの状態を、以下みたいになるように初期化をすれば良い。

|  eip(exit handler) | <- ESP
|  argc              | この場合はargcは4
|  argv[3]           |
|  argv[2]           |
|  argv[1]           |
|  argv[0]           |
(実際にはこの下にもっと続く場合もある)

例えば、プロセス初期化を行うカーネルの関数で、こんな感じで引数を受け付けてみる。

// pはプロセス管理用の構造体である
init_proc(Process *p, *int (*func)(int, char *[]), uint8_t argc, char *argv, ...){
    // プロセスの初期化処理いろいろ

    //引数のデータを格納する領域を確保(固定長にして足りない場合はエラーとかでもいいかも)
    va_list _args;
    va_start(_args, argv);
    uint32_t size = 0;
    for(int i = 0; i < argc; i++){
        size += strlen(va_arg(args, char *));
    }
    va_end(_args);
    
    //実際にはページングもあるのでプロセスのメモリ空間におけるアドレスに変換したり、もうひと手間必要
    void mem_args = (void *)vmalloc(size);

    //上記で確保した領域に入れられる引数のそれぞれのアドレスを入れておく(プロセス初期化時にカーネルが使うだけ)
    char *_args_ptr[] = (char *)kvmalloc(sizeof(char *) * argc);

    //確保した領域にコピーしていく
    va_start(_args, argv);
    for(int i = 0; i < argc; i++){
        _args_ptr[i] = mem_args;
        size = strcpy(mem_args, va_arg(args, char *));
        mem_args += size;
    }
    va_end(_args);

    //スタック領域確保
    //stackはスタック領域のアドレス計算にも使う
    void *stack = (void *)vmalloc(PROCESS_STACK_SIZE);
    stack = (void *)((uint32_t)stack + PROCESS_STACK_SIZE) + 1;
    for(int i = 0; i < argc; i++){
        stack--;
        //可変長引数で受け取った引数へのポインタをスタックに積んでいく
        *stack = _args_ptr(i);
    }
    stack--;
    //stackはvoid *だけど、ここではポインタではなく引数の数を入れる
    *stack = (void *)argc;
    
    // プロセスの初期化処理いろいろ
    //スタックの初期化
    p->context->esp = stack;
}

引数渡すだけなのにこんなにめんどくさいのか?
xv6とかの実装も読んでみたほうが良さそう。
そもそもこれで行けるかもわからない。

Clone this wiki locally