当我在完成带参数的用户程序后,运行出现了bug。在完成加载磁盘上的文件执行时,首先你需要编译源程序,然后根据源程序的大小,将其写到磁盘中,同时需要修改kernel/main.c,因为我们编译后的程序大小和书中给的程序大小不一样
nasm -f elf ./start.S -o ./start.o -g
ar rcs simple_crt.a ../build/string.o ../build/syscall.o \
../build/stdio.o ../build/assert.o ./start.o
gcc -Wall -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes \
-Wsystem-headers -m32 -I ../lib/ -I ../lib/user -I ../fs prog_arg.c -o prog_arg.o
ld prog_arg.o simple_crt.a -o prog_arg -melf_i386
dd if=command/prog_arg of=/home/cccmmf/mycode/os.img bs=512 count=100 seek=300 conv=notrunc
uint32_t file_size = 22668;
uint32_t sec_cnt = DIV_ROUND_UP(file_size, 512);
struct disk* sda = &channels[0].devices[0];
void* prog_buf = sys_malloc(sec_cnt * SECTOR_SIZE);
ide_read(sda, 300, prog_buf, sec_cnt);
int32_t fd = sys_open("/prog_arg", O_CREAT|O_RDWR);
if (fd != -1) {
if(sys_write(fd, prog_buf, file_size) == -1) {
printk("file write error!\n");
while(1);
}
}
sys_close(fd);
当我运行prog_arg后出现了GP异常,如下所示
我们接下来使用gdb进行debug,首先我们需要去判断,我们是否执行到了prog_arg(判断GP发生在内核还是prog_arg中),我们是通过shell.c中的myshell函数调用execv,execv最终转变为sys_execv去执行磁盘上的可执行文件,所以我们可以直接在sys_execv上打断点。
当我们执行到下图186行时,我们开始使用s进入intr_exit如下第二个图所示,然后我们继续s,当我们执行到iretd时,开始使用si,单步汇编调试
使用si单步调试之后,我们发现我们有一条使用了gs寄存器,按道理来说用户程序肯定是不能操作gs寄存器的,就是该条指令导致了gp异常
接下来我们使用objdump反汇编prog_arg文件
最终发现在main函数里就是有一条指令使用了gs寄存器,接下来我们重新编译prog_arg,重新写入磁盘,使用gcc编译时多加一个参数-fno-stack-protector
nasm -f elf ./start.S -o ./start.o -g
ar rcs simple_crt.a ../build/string.o ../build/syscall.o \
../build/stdio.o ../build/assert.o ./start.o
gcc -Wall -c -fno-builtin -W -Wstrict-prototypes -Wmissing-prototypes \
-Wsystem-headers -m32 -I ../lib/ -I ../lib/user -I ../fs prog_arg.c -o prog_arg.o -fno-stack-protector
ld prog_arg.o simple_crt.a -o prog_arg -melf_i386
dd if=command/prog_arg of=/home/cccmmf/mycode/os.img bs=512 count=100 seek=300 conv=notrunc
然后使用objdump反汇编prog_arg,最终发现使用gs的那条汇编指令没有了
接下来重新启动我们的操作系统,将prog_arg读入文件系统,然后运行,最终运行成功