I am doing the Pintos project on the side to learn more about operating systems. I finished Project 1 and have started the second project. I already have setup stack verified and working (via hex_dump). Right now I am having issues getting the correct syscall arguments.
In user/syscall.c there are 4 assembly stubs(0 - 4 stubs) that the user syscall wrap.
#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)
I have some code inside of my syscall_handler that calls the correct function inside of the kernel.
static void syscall_handler (struct intr_frame *f) {
uint32_t *args = f->esp;
if (args[0] == SYS_WRITE) {
f->eax = write(args);
}
Inside of my write function I am printing out the FD and 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);
Running 'echo hello stack overflow 1 22 333' will yield the result below. Note I added the notes in parentheses. () <- Something is getting screwed up and FD is getting overridden with the size (including null terminator)
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
Ive ran this with GDB setting breakpoints and dumping frames and have not been able to figure it out. Has anyone encountered anything similar? If so how did you fix it?
Thanks!
I discovered a bug recently in
user/syscall.c
that could be affecting you. Try applying this patch touser/syscall.c
:Here's the long story...
In the macro
syscall3
for example, the expected assembly code to be generated looks something like thisThis should work as long as the stack looks exactly as expected just push the interrupt instruction. Here is what the disassembled
write
function looks like in of the test programs (generated byobjdump -d pintos/src/userprog/build/tests/userprog/args-many
):There is an enormous problem with these instructions. Because the arguments are being pushed onto the stack relative to the stack pointer
%esp
, the wrong arguments are pushed onto the stack! This is because%esp
changes after everypushl
instruction.After doing some digging on the extended asm syntax for gcc, I think I found the right fix. The
%esp
register needs to be added to the Clobbers list in the extended asm instruction for eachsyscall*
. This is because eachpushl
instruction modifies%esp
indirectly, so we need to inform gcc of that modification so that it does not use%esp
improperly in the generated instructions.