32bit 64bit - Calling C function which takes no parameters with parameters -


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