@earthen94

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

自作OS ユーザプログラム内でargc取得不可

解決したいこと

OSを開発しているのですが、カーネルからユーザプログラムを呼んだ際に、argcをうまく渡すことができません。
kernel.c(入力受付)→command.c(実行ファイル検索)→user_exec.c(ユーザプログラムへ移行)→start.S(ユーザプログラム入口)→test3.binの順番で読み込みます。

投稿時点 : https://github.com/ooe1220/KansoOS/tree/da6871ebefe0d68a60231c7c39affea619485ada
最新 : https://github.com/ooe1220/KansoOS

自分では全体を理解しており、どうしても背景の説明が雑になってしまいますが、できるだけ詳しく書いたつもりです。
OS開発の経験がある方、組み込みをしておられる方等、どなたかお力をお貸し頂ければ幸いです。

Linuxの場合はKansoOS/直下で./build.shを実行すると動きます。
Windowsはddが初めから入っておらず使い辛いため、試しておりません。

以下、初めは自分向けに書いていたので敬語ではありません。

問題

test3.cの中でargcを取得できない。
表示すると正常でない値になる。

整理

user_exec.c中のkprintfでは正しく表示される
start.Sからcall mainをしているため、スタックに積み直さないといけないが、積み直すとCPUがエラーを投げる。

test3.c内にて以下のコードで確認してもスタックの上の方にそれらしい値が無い。

    int dummy = 0x12345678;
    int *p = &dummy;

    printf_d("argc (param) = %d\n", argc);

    for (int i = -1; i >= -10; i--) {
        printf_d("%d\n",p[i]);
    }

カーネルの実行ファイル呼び出し部分

user_exec.c
#include "user_exec.h"
#include "x86/console.h"

// argc: 引数個数, argv: 引数配列
// 引数を指定しない場合、argc=1, argv[0]=ファイル名
int user_exec(void* entry, int argc, char **argv)
{
    int ret;
    
    kprintf("user_exec.c argc: %d\n", argc); // test:引数の数

    asm volatile (
        "push %[argv]\n"   // argv のアドレスを push
        "push %[argc]\n"   // argc を push
        "call *%[entry]\n" // エントリポイントを呼び出す
        : "=a"(ret)        // EAX に返り値を受け取る
        : [entry]"r"(entry),
          [argc]"r"(argc),
          [argv]"r"(argv)
        : "memory"
    );

    return ret;
}

ユーザプログラム

start.S
.intel_syntax noprefix
.global _start
.extern main

_start:
    call main
1:
    ret
test3.c
#include "lib/mystdio.h"

int main(int argc, char **argv){   
    printf_d("argc = %d\n", argc);    
    return 0;
}
objdump -d -M intel kernel.elf

...(省略)...

000096bb <user_exec>:
    96bb:	55                   	push   ebp
    96bc:	89 e5                	mov    ebp,esp
    96be:	53                   	push   ebx
    96bf:	83 ec 14             	sub    esp,0x14
    96c2:	e8 a4 f2 ff ff       	call   896b <__x86.get_pc_thunk.ax>
    96c7:	05 4d 13 00 00       	add    eax,0x134d
    96cc:	83 ec 08             	sub    esp,0x8
    96cf:	ff 75 0c             	push   DWORD PTR [ebp+0xc]
    96d2:	8d 90 4c f6 ff ff    	lea    edx,[eax-0x9b4]
    96d8:	52                   	push   edx
    96d9:	89 c3                	mov    ebx,eax
    96db:	e8 40 f8 ff ff       	call   8f20 <kprintf>
    96e0:	83 c4 10             	add    esp,0x10
    96e3:	8b 45 08             	mov    eax,DWORD PTR [ebp+0x8]
    96e6:	8b 55 0c             	mov    edx,DWORD PTR [ebp+0xc]
    96e9:	8b 4d 10             	mov    ecx,DWORD PTR [ebp+0x10]
    96ec:	51                   	push   ecx
    96ed:	52                   	push   edx
    96ee:	ff d0                	call   eax
    96f0:	89 45 f4             	mov    DWORD PTR [ebp-0xc],eax
    96f3:	8b 45 f4             	mov    eax,DWORD PTR [ebp-0xc]
    96f6:	8b 5d fc             	mov    ebx,DWORD PTR [ebp-0x4]
    96f9:	c9                   	leave  
    96fa:	c3                   	ret    
    
...(省略)...

objdump -b binary -m i386 -D test3.bin

...(省略)...

; ここは入り口
   0:	e8 e2 01 00 00       	call   0x1e7
   5:	c3                   	ret    

...(省略)...

; ここはmain
 1e7:	55                   	push   %ebp
 1e8:	89 e5                	mov    %esp,%ebp
 1ea:	ff 75 08             	push   0x8(%ebp)
 1ed:	68 01 02 01 00       	push   $0x10201
 1f2:	e8 f8 fe ff ff       	call   0xef
 1f7:	83 c4 08             	add    $0x8,%esp
 1fa:	b8 00 00 00 00       	mov    $0x0,%eax
 1ff:	c9                   	leave  
 200:	c3                   	ret    

...(省略)...
Image

スタックを積み直す

start.Sの中で積み直すとCPUがエラーを投げる。

start.S
.intel_syntax noprefix
.global _start
.extern main

_start:
    ; カーネルから渡された引数をmainに渡す
    push ebp
    mov ebp, esp
    
    ; argv (3番目の引数) をスタックに積む
    push DWORD PTR [ebp+16]   ; argv
    ; argc (2番目の引数) をスタックに積む
    push DWORD PTR [ebp+12]   ; argc
    
    call main
    
    add esp, 8  ; 引数を捨てる
    
    pop ebp
    ret
Image
0 likes

1Answer

38640 はHEXで 0x96F0、これって call eax の次のアドレス、つまりcallでスタックに積まれた命令ポインタの値(=戻りアドレス)のようですね。
call eax の前に push edx していて、それが argc の値なのですよね。
main では 0x8(%ebp)argc として参照しているようですが、 0xc(%ebp) じゃないといけないのでは?
ユーザープログラムのコンパイラも自作ですか?

0Like

Your answer might help someone💌