Calling Conventions: Difference between revisions

m
Reverted edits by Melina148 (talk) to last revision by Moonchild
[unchecked revision][unchecked revision]
m (Reverted edits by Melina148 (talk) to last revision by Moonchild)
 
(11 intermediate revisions by 5 users not shown)
Line 22:
| System V i386 || eax, edx || none || stack (right to left)<sup>[[#Note1|1]]</sup> || || eax, ecx, edx || ebx, esi, edi, ebp, esp || ebp
|-
| System V X86_64<sup>[[#Note2|2]]</sup> || rax, rdx || rdi, rsi, rdx, rcx, r8, r9 || stack (right to left)<sup>[[#Note1|1]]</sup> || 16-byte at call<sup>[[#Not3Note3|3]]</sup> || rax, rdi, rsi, rdx, rcx, r8, r9, r10, r11 || rbx, rsp, rbp, r12, r13, r14, r15 || rbp
|-
| Microsoft x64 || rax || rcx, rdx, r8, r9 || stack (right to left)<sup>[[#Note1|1]]</sup> || 16-byte at call<sup>[[#Note3|3]]</sup> || rax, rcx, rdx, r8, r9, r10, r11 || rbx, rdi, rsi, rsp, rbp, r12, r13, r14, r15 || rbp
|-
| ARM || r0, r1 || r0, r1, r2, r3 || stack || 8 byte<sup>[[#Note4|4]]</sup> || r0, r1, r2, r3, r12 || r4, r5, r6, r7, r8, r9, r10, r11, r13, r14 ||
Line 34 ⟶ 36:
 
<small id="Note4">Note 4: Stack is 8 byte aligned at all times outside of prologue/epilogue of function.</small>
 
== System V ABI ==
{{Main|System V ABI}}
 
The System V ABI is one of the major ABIs in use today and is virtually universal among Unix systems. It is the calling convention used by toolchains such as <tt>i686-elf-gcc</tt> and <tt>x86_64-elf-gcc</tt>.
 
==External References==
Line 39 ⟶ 46:
 
<syntaxhighlight lang="c">
int fee(int fie, char foe, double fum);
</syntaxhighlight>
 
Line 69 ⟶ 76:
==Name Mangling==
 
In some object formats ([[a.out]]), the name of a C function is automagically mangled by prepending it with an underscore ('"_'"). Thus, to call a C function <tt>foo()</tt> in assembly with such a format, you must define it as <tt>extern _foo</tt> instead of <tt>extern foo</tt>. This requirement does not apply to most modern formats such as [[COFF]], [[PE]], and [[ELF]].
 
C++ name mangling is much more severe, as the C++ compiler encodes the type information from the parameter list into the symbol. (This is what enables function overloading in C++ in the first place.) The binutilsBinutils package contains the tool <tt>c++filt</tt> that can be used to determine the correct mangled name.
 
==Registers==
Line 77 ⟶ 84:
 
==Passing Function Arguments==
GCC/x86 passes function arguments on the stack. These arguments are pushed in reverse order from their order in the argument list. Furthermore, since the x86 protected-mode stack operations operate on doubleword (32-bit) values, the values are always pushed as a doubleword32-bit value, even if the actual value is less than a full doubleword32-bit value. Thus, for function <tt>foo()</tt>, the value of <tt>quux</tt> (a 48-bit FP value) is pushed first as two doublewords32-bit values, low-dword32-bit-value first; the value of <tt>baz</tt> is pushed as the first byte of in doubleword32-bit value; and then finally <tt>bar</tt> is pushed as a doubleword32-bit value.
 
To pass arguments to a C function, the calling function must push the argument values as described above. Thus, to call foo() from a [[NASM]] assembly program, you would do something like this
 
<syntaxhighlight lang="asm">
push eax ; low dword32-bit of quux
push edx ; high dword32-bit of quux
push bl ; baz
push ecx ; bar
Line 92 ⟶ 99:
In the GCC/x86 C calling convention, the first thing any function that accepts formal arguments should do is push the value of <tt>EBP</tt> (the frame base pointer of the calling function), then copy the value of <tt>ESP</tt> to <tt>EBP</tt>. This sets the function's own frame pointer, which is used to track both the arguments and (in C, or in any properly reentrant assembly code) the local variables.
 
To access arguments passed by a C function, you need to use the <tt>EBP</tt> an offset equal to 4 * (n + 2), where n is the number of the parameter in the argument list (not the number in the order it was pushed by), zero-indexed. The + 2 is an added offset for the calling function's saved frame pointer and return pointer (pushed automatically by <tt>CALL</tt>, and popped by <tt>RET</tt>).
 
Thus, in function <tt>fee</tt>, to move <tt>fie</tt> into <tt>EAX</tt>, <tt>foe</tt> into <tt>BL</tt>, and <tt>fum</tt> into <tt>EAX</tt> and <tt>EDX</tt>, you would write (in NASM):
Line 99 ⟶ 106:
mov ecx, [ebp + 8] ; fie
mov bl, [ebp + 12] ; foe
mov edx, [ebp + 16] ; low dword32-bit of fum
mov eax, [ebp + 20] ; high dword32-bit of fum
</syntaxhighlight>
 
Line 109 ⟶ 116:
*[http://www.delorie.com/djgpp/doc/ug/asm/calling.html DJGPP FAQ: GCC calling conventions]
*[http://gul.ime.usp.br/Docs/docs/howto/other-formats/html/HOWTO-INDEX-html/Assembly-HOWTO-5.html Linux Assembly Language HOWTO chapter 5]
*http://myfiles.execpcosdev.comorg/mirrors/~geezer/osd/libc/index.htm
 
[[Category:ABI]]
[[Category:C]]
[[de:Aufrufkonventionen]]
Anonymous user