嗨,我正在做有关使用Pintos的操作系统的作业。我被要求在一项测试中找到错误的说明。测试框架期望Pintos输出“什么都不做:exit(162)”。这是进程退出时Pintos打印的标准消息。但是,Pintos没有输出此消息。相反,由于内存访问冲突(分段错误),无所事事程序在用户空间中崩溃了。
#include "tests/lib.h"
int
main (int argc UNUSED, char *argv[] UNUSED)
{
return 162;
}
我调查了这个测试的结果,
FAIL
Test output failed to match any acceptable form.
Acceptable output:
do-nothing: exit(162)
Differences in `diff -u' format:
- do-nothing: exit(162)
+ Page fault at 0xc0000008: rights violation error reading page in user context.
+ do-nothing: dying due to interrupt 0x0e (#PF Page-Fault Exception).
+ Interrupt 0x0e (#PF Page-Fault Exception) at eip=0x8048757
+ cr2=c0000008 error=00000005
+ eax=00000000 ebx=00000000 ecx=00000000 edx=00000000
+ esi=00000000 edi=00000000 esp=bfffffe4 ebp=00000000
+ cs=001b ds=0023 es=0023 ss=0023
问题:
我不知道如何找到3.问题的答案,“ objdump -S do-nothing.o”的输出非常简单:
Disassembly of section .text:
00000000 <main>:
int
main (int argc UNUSED, char *argv[] UNUSED)
{
return 162;
}
0: b8 a2 00 00 00 mov $0xa2,%eax
5: c3 ret
A:
void
_start (int argc, char *argv[])
{
8048754: 83 ec 1c sub $0x1c,%esp
exit (main (argc, argv));
8048757: 8b 44 24 24 mov 0x24(%esp),%eax
804875b: 89 44 24 04 mov %eax,0x4(%esp)
804875f: 8b 44 24 20 mov 0x20(%esp),%eax
8048763: 89 04 24 mov %eax,(%esp)
8048766: e8 35 f9 ff ff call 80480a0 <main>
804876b: 89 04 24 mov %eax,(%esp)
804876e: e8 49 1b 00 00 call 804a2bc <exit>
#include <syscall.h>
int main (int, char *[]);
void _start (int argc, char *argv[]);
void
_start (int argc, char *argv[])
{
exit (main (argc, argv));
}
8048757: 8b 44 24 24 mov 0x24(%esp),%eax
**为什么该指令会导致分段错误?**
sub $0x1c,%esp
mov 0x24(%esp),%eax
首先,它分配了一些堆栈空间(0x1c),然后将参数argv移至0x24(%esp)[在更改堆栈指针之前为0x8]到%eax,为什么这个简单的指令会导致分段错误?
我不是PintOS的专家,但是我可以提供一些见解。你正在目标文件(.o
)上使用OBJDUMP 。这些是未链接的ELF对象文件,没有任何VMA(虚拟内存地址)起点(也称为起点),并且在每个PintOS程序中均不包含任何用户模式运行时代码。诸如C启动之类的事情,它会设置用户模式应用程序,并main
使用argc
和argv
参数在处启动代码。
你需要执行的操作是使用常规PintOS构建过程将目标文件构建到用户模式程序中。userland可执行文件的名称.o
与已.o
删除文件的名称相同。do-nothing
是可执行文件的名称,看起来它们可以在目录中找到pintos/src/userprog/build/tests/userprog/
。在此可执行文件上运行OBJDUMP,搜索地址0x8048757。你应该能够轻松地找到函数名称和所有代码。有了这些信息,你应该能够回答第三个问题。你对问题1和2的答案是正确的。
非常感谢您的详细回答。您能看看我更新的问题吗?我发现了错误的指示。它是“ mov 0x24(%esp),%eax”,我不知道为什么会导致故障。
@badtastetea有关页面错误的异常err表示在用户上下文中读取页面时发生权限冲突错误。。这表明用户模式程序试图访问它没有读取权限的页面。可能是因为内核地址从0xc0000000开始(可能是映射的超级用户模式可访问)。为什么这么重要?该指令
mov 0x24(%esp),%eax
具有一个内存操作数,它表示无法访问地址0x24 + ESP。如果您查看ESP失败时的值,则表示添加到0x24时的值为0xbfffffe4,是一个略高于0xc0000008的地址。@badtastetea至于该代码在做什么,取决于进程如何在堆栈上传递argc和argv。看来是从堆栈中复制argc和argv的值,并将它们设置为的第一个参数
main
。可能选择从堆栈中减去值0x1c来构建main
s参数并仍然保持16字节堆栈对齐。这是一种猜测,因为我不知道什么叫公约PintOS规定,虽然i386的System V的ABI需要16个字节alignment.hen claling的ABI兼容的功能(如main
)我假设
start
最初是使用16字节对齐的堆栈调用的。的第一条指令_start
将有一个4字节未对齐的堆栈,因为对的调用将_start
其地址压入了堆栈。因此,像0x1c + 4 = 0x20和0x20这样的值可以被16整除(十六进制0x10)。实际上,所有代码所做的就是使用argc和argv作为参数设置对main的调用,并保持堆栈正确对齐。但是,该错误表明,无论谁调用
_start
,实际上都没有将argc和argv作为参数推入其中,_start
并且_start
试图将它们复制到堆栈以获取功能时main
-它们不存在,并且生成的堆栈指针(ESP)+ 0x24失败。