Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing parameters when compile C and nasm

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?

like image 322
tianhaopx Avatar asked Nov 22 '25 08:11

tianhaopx


1 Answers

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.

like image 126
Jester Avatar answered Nov 24 '25 21:11

Jester



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!