pintos - Pintos - 系统调用项目 2
问题描述
我正在做 Pintos 项目,以了解有关操作系统的更多信息。我完成了项目 1 并开始了第二个项目。我已经验证了设置堆栈并且可以正常工作(通过 hex_dump)。现在我在获取正确的系统调用参数时遇到问题。
在 user/syscall.c 中有 4 个程序集存根(0 - 4 个存根)由用户系统调用包装。
#define syscall3(NUMBER, ARG0, ARG1, ARG2) \
({ \
int retval; \
asm volatile \
("pushl %[arg2]; pushl %[arg1]; pushl %[arg0]; " \
"pushl %[number]; int $0x30; addl $16, %%esp" \
: "=a" (retval) \
: [number] "i" (NUMBER), \
[arg0] "g" (ARG0), \
[arg1] "g" (ARG1), \
[arg2] "g" (ARG2) \
: "memory"); \
retval; \
}) (this code is given to us)
我的 syscall_handler 中有一些代码在内核中调用正确的函数。
static void syscall_handler (struct intr_frame *f) {
uint32_t *args = f->esp;
if (args[0] == SYS_WRITE) {
f->eax = write(args);
}
在我的 write 函数中,我打印出 FD 和 Size
int sysCallNumber = (int) args[0];
int fd = (int) args[1];
const char *buffer = (char *) args[2];
unsigned size = (unsigned) args[3];
printf("FD is %d\n", fd);
printf("Size is %d\n", size);
运行“echo hello stack overflow 1 22 333”将产生以下结果。注意我在括号中添加了注释。() <- 有些事情搞砸了,FD 被大小覆盖(包括空终止符)
FD is 6 (hello)
Size is 6
FD is 6 (stack)
Size is 6
FD is 9 (overflow)
Size is 9
FD is 2 (1)
Size is 2
FD is 3 (22)
Size is 3
FD is 4 (333)
Size is 4
FD is 1 (this is from the printf("\n") in echo.c)
Size is 1
我已经用 GDB 设置断点和转储帧来运行它,但无法弄清楚。有没有人遇到过类似的事情?如果是这样,您是如何解决的?
谢谢!
解决方案
我最近发现了一个user/syscall.c
可能会影响您的错误。尝试将此补丁应用于user/syscall.c
:
diff --git a/src/lib/user/syscall.c b/src/lib/user/syscall.c
index a9c5bc8..efeb38c 100644
--- a/src/lib/user/syscall.c
+++ b/src/lib/user/syscall.c
@@ -10,7 +10,7 @@
("pushl %[number]; int $0x30; addl $4, %%esp" \
: "=a" (retval) \
: [number] "i" (NUMBER) \
- : "memory"); \
+ : "memory", "esp"); \
retval; \
})
@@ -24,7 +24,7 @@
: "=a" (retval) \
: [number] "i" (NUMBER), \
[arg0] "g" (ARG0) \
- : "memory"); \
+ : "memory", "esp"); \
retval; \
})
@@ -40,7 +40,7 @@
: [number] "i" (NUMBER), \
[arg0] "g" (ARG0), \
[arg1] "g" (ARG1) \
- : "memory"); \
+ : "memory", "esp"); \
retval; \
})
@@ -57,7 +57,7 @@
[arg0] "g" (ARG0), \
[arg1] "g" (ARG1), \
[arg2] "g" (ARG2) \
- : "memory"); \
+ : "memory", "esp" ); \
retval; \
})
这是长篇大论...
例如,在宏syscall3
中,要生成的预期汇编代码看起来像这样
pushl ARG2
pushl ARG1
pushl ARG0
pushl NUMBER
int $0x30
addl $16, %esp
只要堆栈看起来完全符合预期,这应该可以工作,只需推送中断指令。以下是反汇编write
函数在测试程序中的样子(由 生成objdump -d pintos/src/userprog/build/tests/userprog/args-many
):
0804a1a5 <write>:
804a1a5: ff 74 24 0c pushl 0xc(%esp)
804a1a9: ff 74 24 08 pushl 0x8(%esp)
804a1ad: ff 74 24 04 pushl 0x4(%esp)
804a1b1: 6a 09 push $0x9
804a1b3: cd 30 int $0x30
804a1b5: 83 c4 10 add $0x10,%esp
804a1b8: c3 ret
这些说明存在很大的问题。因为参数相对于堆栈指针被压入堆栈%esp
,所以错误的参数被压入堆栈!这是因为%esp
在每条pushl
指令之后都会发生变化。
在对 gcc 的扩展 asm 语法进行了一些挖掘之后,我想我找到了正确的解决方法。需要将%esp
寄存器添加到扩展 asm 指令中的 Clobbers 列表中syscall*
。这是因为每条pushl
指令都是%esp
间接修改的,所以我们需要通知 gcc 那个修改,这样它就不会%esp
在生成的指令中使用不当。
推荐阅读
- ajax - 我对使用 laravel 的 AJAX 帖子有问题
- javascript - JSON.parse() 字符串,在值中包含换行符
- jquery - JS 按钮,Jquery 选择器
- office-js - Office.js 提取 openXml 时缺少分页符(LastRenderedPageBreak)
- android - WebView 音频播放器在一段时间后自动停止
- apache-spark - Spark 流不从云存储源中选择新文件
- php - 如何在 wocommerce wordpress 网站中仅更改“结帐”的标题
- php - Laravel 权限被拒绝错误
- c# - 获取打开 c# 应用程序的文件位置
- python - Python3:计算嵌套字典中字符的出现次数