Pintos中exec系统调用参数未出现在用户栈的问题排查
Pintos系统调用exec参数获取异常问题
场景复现
我正在测试一个经过小幅修改的Pintos项目,用户程序通过以下代码创建子进程:
void test_main (void) { msg ("wait(exec()) = %d", wait (exec ("child-simple"))); }
其中wait()和exec()是在userprog/syscall.c中实现的系统调用。根据Pintos的lib/user/syscall.h定义,调用系统调用时会先将参数压入用户栈,再压入系统调用号,相关宏定义如下:
#define syscall1(NUMBER, ARG0) ({ int retval; asm volatile ("pushl %[arg0]; pushl %[number]; int $0x30; addl $8, %%esp" : "=a" (retval) : [number] "i" (NUMBER), [arg0] "g" (ARG0) : "memory"); retval; })
按宏逻辑,调用exec("child-simple")时,应先压入文件名的地址,再压入SYS_EXEC对应的系统调用号2,之后触发int $0x30进入系统调用处理。
当前问题
在syscall_handler()中能正常提取到系统调用号2,但在处理分支中尝试从f->esp +4获取文件名地址时,并未找到预期值:
case SYS_EXEC:{ // f-> esp + 4 doesn't have file address??? is_valid_vaddr(f->esp + 4); f->eax = exec((char*)(f->esp+4)); break; }
通过hex_dump()查看内存的结果如下:
esp position : 0xbfffff74 syscall number : 2 bfffff70 02 00 00 00-79 b2 04 08 01 81 04 08 | ....y.......| bfffff80 79 b2 04 08 a7 88 04 08-b8 ff ff 0e c8 c6 04 08 |y...............| bfffff90 00 00 00 00 |.... |
系统调用号02 00 00 00位于地址0xbfffff74,但后续位置未出现文件名地址,导致exec()无法创建子进程。
问题分析与解决
参数位置判断错误
宏定义中是先pushl %[arg0](参数),再pushl %[number](系统调用号),因此用户栈在触发中断前的布局是:地址: 0xbfffff70 → 参数(文件名地址:0x0804b279,对应dump中的`79 b2 04 08`) 地址: 0xbfffff74 → 系统调用号2(`02 00 00 00`)你当前用
f->esp +4查找参数,但实际f->esp指向的是系统调用号的位置0xbfffff74,参数应该在f->esp -4的位置,也就是0xbfffff70处的地址。修正方案
将处理代码中的参数获取位置改为f->esp -4,修改后的代码如下:case SYS_EXEC:{ is_valid_vaddr(f->esp - 4); f->eax = exec((char*)(f->esp - 4)); break; }同时可以验证
0x0804b279地址是否确实指向用户空间中的"child-simple"字符串,确认参数的正确性。额外检查点
- 确认
is_valid_vaddr函数能正确验证用户空间地址,避免因地址校验失败导致后续操作异常; - 检查
syscall_handler()中f->esp的来源,确保它是用户态触发中断时的原始栈指针,未被内核代码意外修改。
- 确认
内容的提问来源于stack exchange,提问作者Jason Kim
相关产品推荐
相关产品推荐

