I am used to seeing command line arguments referenced by (convention (A)):
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax # argc
movl 4(%ebp), %ebx # pointer to argv[0] string
movl 8($ebp), %ecx # pointer to argv[1] string
Sometimes, I've seen the list start at an offset of 8, and this is not the (main) question. What I've noticed in a program is this translation and reference which I am confused about, to get argv[1]
(convention (B)):
movl 0xc(%ebp), %eax # pointer to a pointer to argv[0] (argc is at offset 8)
addl $0x4, %eax # argv[1] is a pointer at offset 4 from the pointer to argv[0]
movl (%eax), %eax # load where it points to, which is the argv[1] string
(at offset 16(%ebp)
I see a pointer to an environmental variable)
(1) Is there any reason for this different convention?
(2) Is there a compiler option to force gcc to use what I believe to be the standard convention (A) above?
(3) Is there a reason gcc uses convention (B)?
(4) Why the additional offset of 8?
System info:
- Ubuntu 12.04
- gcc 4.6.3
- compiled with fno-stack-protector
If you're dealing with a program that has been linked to the C runtime, then the
argc
andargv
parameters are passed (assuming x86) withargc
atebp+8
andargv
atebp+12
. that's because the C runtime performs it's own initialization and passes the arguments tomain()
using the normal C ABI.The calling convention that you say you're used to seeing (with
argc
at the top of the stack, followed byargv[0]
..argv[argc]
) is the state of the stack as set up by the Linux system call that starts a new program.Note that your assembly oriented code example:
looks to be off by 4 for each of the last three lines because of the initial
pushl
instruction.