I don't know the cross-platform answer to your question. But this made me curious. So what do we do? Look at the stack!
For the first iteration:
test.c
int main(void) {
return 0;
}
test2.c
int main(int argc, char *argv[]) {
return 0;
}
And now look at the assembly output:
$ gcc -S -o test.s test.c
$ cat test.s
.file "test.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
popl %ebp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
Nothing exciting here. Except for one thing: both C programs have the same assembly output!
This basically makes sense; we never really have to push/pop anything off of the stack for main(), since it's the first thing on the call stack.
So then I wrote this program:
int main(int argc, char *argv[]) {
return argc;
}
And its asm:
main:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
popl %ebp
ret
This tells us that "argc" is located at 8(%ebp)
So now for two more C programs:
int main(int argc, char *argv[]) {
__asm__("movl 8(%ebp), %eax
"
"popl %ebp
"
"ret");
/*return argc;*/
}
int main(void) {
__asm__("movl 8(%ebp), %eax
"
"popl %ebp
"
"ret");
/*return argc;*/
}
We've stolen the "return argc" code from above and pasted it into the asm of these two programs. When we compile and run these, and then invoke echo $?
(which echos the return value of the previous process) we get the "right" answer. So when I run "./test a b c d" then $?
gives me "5" for both programs - even though only one has argc/argv defined. This tells me that, on my platform, argc is for sure placed on the stack. I'd bet that a similar test would confirm this for argv.
Try this on Windows!