自作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]);
}
カーネルの実行ファイル呼び出し部分
#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;
}
ユーザプログラム
.intel_syntax noprefix
.global _start
.extern main
_start:
call main
1:
ret
#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
...(省略)...
スタックを積み直す
start.Sの中で積み直すとCPUがエラーを投げる。
.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