Before executing main() operating system must perform a bunch of other operations to properly configure the environment before execution control is processed by your application. Thus, most of what is currently on the stack is garbage left over from previous operations.
Before executing main() you can find argc and argv on the stack.
EDIT:
The kinda user comment made me go through the debugging process of the build application in gdb and examine the stack to back up the statement I made in the original answer.
Therefore, please consider the following assembly code written in nasm:
section .data mymsg db "hello, world", 0xa ; string with a carriage-return mylen equ $-mymsg ; string length in bytes section .text global mystart ; make the main function externally visible mystart: ; prepare the arguments for syscall write() push dword mylen ; msg length push dword mymsg ; msg to write push dword 1 ; file descriptor number ; call write() mov eax, 0x4 ; 0x4 identifies syscall write() sub esp, 4 ; OS X (and BSD) syscalls needs "extra space" on stack int 0x80 ; trigger the call ; clean up the stack add esp, 16 ; 3 args * 4 bytes/arg + 4 bytes extra space = 16 bytes ; prepare argument for syscall exit() push dword 0 ; exit status returned to the operating system ; call exit() mov eax, 0x1 ; 0x1 identifies syscall exit() sub esp, 4 ; OS X (and BSD) system calls needs "extra space" on stack int 0x80 ; trigger the call
I compiled this on Mac OS X using
nasm -f macho -o hello.o hello.nasm ld -o hello -e mystart hello.o
As you can probably tell from the source code, the start of the application is determined by mystart , and it does not accept any parameters.
Now let's make this study more interesting by opening this program in gdb :
gdb ./hello
After downloading gdb for educational purposes, it is important to set the cmd line parameter for this application, even if it was not written to accept any.
set args deadbeef
At the moment, the application is still not working. We need to set a breakpoint at the beginning of the main function so that we can check the stack to find out what happens before our application starts to execute its own code:
break mystart
Run the run command on gdb to start the application and abort. Now we can check the stack with
x/20xw $esp
outputs:
(gdb) x/20xw $esp 0xbffff8cc: 0x00002000 0x00000000 0x00000002 0xbffff96c 0xbffff8dc: 0xbffff98b 0x00000000 0xbffff994 0xbffff9b0 0xbffff8ec: 0xbffff9c1 0xbffff9d1 0xbffffa0b 0xbffffa40 0xbffff8fc: 0xbffffa5b 0xbffffa86 0xbffffa97 0xbffffaad 0xbffff90c: 0xbffffad8 0xbffffafa 0xbffffb06 0xbffffb28
Yes sir, this command prints the contents of the stack. It tells gdb to show 20 words in hexadecimal, starting with the address stored in the $esp register.
Let's see that $esp actually points to 0xbffff8cc , fine, but when analyzing what is stored at this memory address, another address is displayed: 0x00002000 . What does this indicate?
(gdb) x/20sw 0x00002000 0x2000 <mymsg>: "hello, world\n"
Not a shocker, right ?! So let's see what some other table addresses point to:
(gdb) x/1sw 0xbffff96c 0xbffff96c: "/Developer/workspace/asm/hello"
Wow. This is truly an original name and path app stored right on the stack! Surprisingly, let me continue with the following interesting table address:
(gdb) x/1sw 0xbffff98b 0xbffff98b: "deadbeef"
Jackpot! The cmd argument that we passed when running our application was also saved on the stack. As I said earlier, among the garbage stored on the stack, before executing your application, you can also find the cmd line parameters that were used to execute the application, even if the main() function of the application is void and doesn't accept any parameters.