Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top