i have weird question undefined behavior between c calling convention , 64/32 bits compilation. first here code:
int f() { return 0; } int main() { int x = 42; return f(x); } as can see calling f argument while f takes no parameters. first question argument given f while calling it.
the mysterious lines
after little objdump obtained curious results. while passing x argument of f:
00000000004004b6 <f>: 4004b6: 55 push %rbp 4004b7: 48 89 e5 mov %rsp,%rbp 4004ba: b8 00 00 00 00 mov $0x0,%eax 4004bf: 5d pop %rbp 4004c0: c3 retq 00000000004004c1 <main>: 4004c1: 55 push %rbp 4004c2: 48 89 e5 mov %rsp,%rbp 4004c5: 48 83 ec 10 sub $0x10,%rsp 4004c9: c7 45 fc 2a 00 00 00 movl $0x2a,-0x4(%rbp) 4004d0: 8b 45 fc mov -0x4(%rbp),%eax 4004d3: 89 c7 mov %eax,%edi 4004d5: b8 00 00 00 00 mov $0x0,%eax 4004da: e8 d7 ff ff ff callq 4004b6 <f> 4004df: c9 leaveq 4004e0: c3 retq 4004e1: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 4004e8: 00 00 00 4004eb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) without passing x argument:
00000000004004b6 <f>: 4004b6: 55 push %rbp 4004b7: 48 89 e5 mov %rsp,%rbp 4004ba: b8 00 00 00 00 mov $0x0,%eax 4004bf: 5d pop %rbp 4004c0: c3 retq 00000000004004c1 <main>: 4004c1: 55 push %rbp 4004c2: 48 89 e5 mov %rsp,%rbp 4004c5: 48 83 ec 10 sub $0x10,%rsp 4004c9: c7 45 fc 2a 00 00 00 movl $0x2a,-0x4(%rbp) 4004d0: b8 00 00 00 00 mov $0x0,%eax 4004d5: e8 dc ff ff ff callq 4004b6 <f> 4004da: c9 leaveq 4004db: c3 retq 4004dc: 0f 1f 40 00 nopl 0x0(%rax) so can see:
4004d0: 8b 45 fc mov -0x4(%rbp),%eax 4004d3: 89 c7 mov %eax,%edi happen when call f x because not in assembly don't understand these lines.
the 64/32 bits paradoxe
otherwise tried else , start printing stack of program.
stack x given f (compiled in 64bits):
address of x: ffcf115c ffcf1128: 0 0 ffcf1130: -3206820 0 ffcf1138: -3206808 134513826 ffcf1140: 42 -3206820 ffcf1148: -145495616 134513915 ffcf1150: 1 -3206636 ffcf1158: -3206628 42 ffcf1160: -143903780 -3206784 stack x not given f (compiled in 64bits):
address of x: 3c19183c 3c191818: 0 0 3c191820: 1008277568 32766 3c191828: 4195766 0 3c191830: 1008277792 32766 3c191838: 0 42 3c191840: 4195776 0 and reason in 32bits x seems push on stack.
stack x given f (compiled in 32bits):
address of x: ffdc8eac ffdc8e78: 0 0 ffdc8e80: -2322772 0 ffdc8e88: -2322760 134513826 ffdc8e90: 42 -2322772 ffdc8e98: -145086016 134513915 ffdc8ea0: 1 -2322588 ffdc8ea8: -2322580 42 ffdc8eb0: -143494180 -2322736 why hell x appear in 32 not 64 ???
code printing: http://paste.awesom.eu/yayg/qyw6&ln
why asking such stupid questions ?
- first because didn't found standard answer question
- secondly, think calling variadic function in c without count of arguments given.
- last not least, think undefined behavior fun.
thank you taking time read until here , helping me understanding or making me realize questions pointless.
the answer that, suspect, doing undefined behavior (in case superfluous argument passed).
the actual behavior in many implementations harmless, however. argument prepared on stack, , ignored called function. called function not responsible removing arguments stack, there no harm (such unbalanced stack pointer).
this harmless behavior enabled c hackers develop, once upon time, variable argument list facility used under #include <varargs.h> in ancient versions of unix c library.
this evolved ansi c <stdarg.h>.
the idea was: pass arguments function, , march through stack dynamically retrieve them.
that won't work today. instance, can see, parameter not in fact put stack, loaded rdi register. convention used gcc on x86-64. if march through stack, won't find first several parameters. on ia-32, gcc passes parameters using stack, contrast: though can register-based behavior "fastcall" convention.
the va_arg macro <stdarg.h> correctly take account mixed register/stack parameter passing convention. (or, rather, when use correct declaration variadic function, perhaps suppress passage of trailing arguments in registers, va_arg can march through memory.)
p.s. machine code might easier follow if added optimization. instance, sequence
4004c9: c7 45 fc 2a 00 00 00 movl $0x2a,-0x4(%rbp) 4004d0: 8b 45 fc mov -0x4(%rbp),%eax 4004d3: 89 c7 mov %eax,%edi 4004d5: b8 00 00 00 00 mov $0x0,%eax is obtuse due wasteful data moves.
Comments
Post a Comment