Reputation: 53
When compiling C and nasm on Mac OS X, I found it is different to Linux when passing parameters and making system call. My code works but I'm really confused with it.
I write a function myprint
in nasm to print string passed from C.
Here is the C code main.c
#include <stdio.h>
void myprint(char* msg, int len);
int main(void){
myprint("hello\n",6);
return 0;
}
Here is the nasm code myprint.asm
section .text
global _myprint
_syscall:
int 0x80
ret
_myprint:
push dword [esp+8] ;after push, esp-4
push dword [esp+8]
push dword 1
mov eax,4
call _syscall
add esp,12
ret
Compile and link them:
nasm -f macho -o myprint.o myprint.asm
gcc -m32 -o main main.c myprint.o
it prints "hello" correctly.
As you can see, OS X(FreeBSD) use push to pass parameters to sys call, but the parameters char*
and int
are already pushed into the stack and their addresses are esp+4
and esp+8
. However, I have to read them from the stack and push them into stack again to make it work.
If I delete
push dword [esp+8] ;after push, esp-4
push dword [esp+8]
it will print lots of error codes and Bus error: 10
, like this:
???]?̀?j????????
?hello
`44?4
__mh_execute_headerm"ain1yprint6???;??
<??
(
libSystem.B?
`%?. _syscall__mh_execute_header_main_myprintdyld_stub_binder ??z0&?z?&?z?&?z۽??۽????N?R?N?o?N???N??N?e?N?h?N?0?zR?N???N???t??N?N???N?????@?`@b?`?`?a@c aaU??]N?zBus error: 10
Why it needs to push the parameters into stack again? How can I pass these parameters already in stack to syscall without pushing again?
Upvotes: 3
Views: 382
Reputation: 58822
This is normal for even plain C function calls. The problem is that the return address is still on the stack before the arguments. If you don't push them again below the return address you will have 2 return addresses on the stack before the arguments (the first to main
and the second to myprint
) but the syscall only expects 1.
Upvotes: 1