Hi I'm doing homework about operating system using Pintos. I was asked to find the faulting instruction in one test. The testing framework expected Pintos to output “do-nothing: exit(162)”. This is the standard message that Pintos prints when a process exits. However, Pintos did not output this message; instead, the do-nothing program crashed in userspace due to a memory access violation (a segmentation fault).
#include "tests/lib.h"
int
main (int argc UNUSED, char *argv[] UNUSED)
{
return 162;
}
I looked into the result of this test,
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
The questions :
I have no idea about how to find the answer of 3. question, the output with "objdump -S do-nothing.o" is really simple :
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
**why would this instruction lead to segmentation fault? **
sub $0x1c,%esp
mov 0x24(%esp),%eax
Firstly it allocated some stack space (0x1c), then move the argument argv at 0x24(%esp) [which was 0x8 before stack pointer changed] to %eax, why would this simple instruction lead to segmentation fault?
I am not an expert in PintOS, but I can offer some insight. You are using OBJDUMP on an object file (.o
). These are unlinked ELF object files without any VMA (Virtual Memory Address) starting point (aka Origin Point) and doesn't include any of the user mode runtime code in each PintOS program. Things like a C startup that sets up the user mode application and starts the code at main
with the argc
and argv
parameters.
What you need to do is build the object file into a user mode program with the normal PintOS build processes. The userland executables have the same name as the .o
file with the .o
removed. do-nothing
is the name of the executable and it appears these can be found in the directory pintos/src/userprog/build/tests/userprog/
. Run OBJDUMP on this executable, search for address 0x8048757. You should be able to readily find the function name and all the code for it easily. With that information you should be able to answer the 3rd question. The answer you have for question 1 and 2 is correct.
thanks a lot for your detailed answer. Could you please have a look at my updated question? I found the faulting instruction. It's "mov 0x24(%esp),%eax", I don't know why it would lead to a fault.
@badtastetea The exception err about the page fault says rights violation error reading page in user context. . This suggests that a user mode program attempted to access a page it didn't have privileges to read. Likely because the kernel addresses start at 0xc0000000 (which as probably mapped supervisor mode accessible). Why does that matter? The instruction
mov 0x24(%esp),%eax
has a memory operand and it is saying that the address 0x24+ESP is not accessible. If you look at the value in ESP when it failed it says it is 0xbfffffe4 when added to 0x24 is an address slightly above 0xc0000008.@badtastetea As for what that code is doing, it depends on how the process is passed the argc and argv on the stack. It seems to be copying the value of argc and argv from the stack and setting them up as the first parameters to
main
. The value 0x1c was probably chosen to be subtracted from the stack to buildmain
s arguments and still maintain a 16 byte stack alignment. This is a guess since I don't know what the PintOS calling conventions stipulate, although the i386 System V ABI requires 16 byte alignment.hen claling an ABI compliant function (likemain
)I assume that
start
was called originally with a 16 byte aligned stack. The first instruction of_start
would have a stack that is 4 bytes misaligned because the call to_start
had its address pushed on the stack. So a value like 0x1c+4 =0x20 and 0x20 is evenly divisible by 16 (hex 0x10). Effectively all the code is doing is setting up the call to main with argc and argv as parameters and keeping the stack properly aligned.The fault though suggests that whoever called
_start
didn't actually push argc and argv as parameters to_start
and when_start
tried to copy them to the stack for functionmain
- they weren't there and the resulting stack pointer (ESP) + 0x24 failed.