x86 calling conventions

原创 2010年08月20日 22:34:00
From Wikipedia, the free encyclopedia
Jump to: navigation, search

This article describes, in computing, the calling conventions used on the x86 architecture.

Calling conventions describe the interface of called code:

  • The order in which parameters are allocated
  • Where parameters are placed (pushed on the stack or placed in registers)
  • Which registers may be used by the function
  • Whether the caller or the callee is responsible for unwinding the stack on return

This is intimately related with the assignment of sizes and formats to programming-language types. Another closely related topic is name mangling, which determines how symbol names in the code map to symbol names used by the linker. Calling conventions, type representations, and name mangling are all part of what is known as an Application Binary Interface (ABI).

There are often subtle differences in how various compilers implement these conventions, so it is often difficult to interface code which is compiled by different compilers. On the other hand, conventions which are used as an API standard (such as stdcall) are necessarily very uniformly implemented.

Contents

[hide]

[edit] Historical background

In the times of minicomputers, the machine manufacturer also used to provide an OS for it and most (if not all) of the software, including compilers for various languages. So there used to be only one calling convention per language: the one implemented by the manufacturer's compilers.

The IBM PC case was totally different. One firm (IBM) provided the hardware, another (Intel) made the processor, the third (Microsoft) was responsible for the OS (MS-DOS), and many others wrote compilers for quite a number of programming languages. Different mutually exclusive calling schemes were thus designed to satisfy their different requirements.

[edit] Caller clean-up

In these conventions the caller cleans the arguments from the stack, which allows for variable argument lists, eg. printf().

[edit] cdecl

The cdecl calling convention is used by many C systems for the x86 architecture. In cdecl, function parameters are pushed on the stack in a right-to-left order. Function return values are returned in the EAX register (except for floating point values, which are returned in the x87 register ST0). Registers EAX, ECX, and EDX are available for use in the function.

On Linux, gcc is the de-facto standard for calling conventions. Since gcc 4.5 the stack must be aligned to a 16-byte boundary when calling a function (previous versions only required a 4-byte alignment).

For instance, the following C code function prototype and function call:

int function_name(int, int, int);
int a, b, c, x;
...
x = function_name(a, b, c);

will produce the following x86 Assembly code (written in MASM syntax, with destination first):

push c
push b
push a
call function_name
add esp, 12 ;Stack clearing
mov x, eax

The calling function cleans the stack after the function call returns.

There are some variations in the interpretation of cdecl, particularly in how to return values. As a result, x86 programs compiled for different operating system platforms and/or by different compilers can be incompatible, even if they both use the "cdecl" convention and do not call out to the underlying environment. Some compilers return simple data structures with the length of 2 registers or less in EAX:EDX, and larger structures and class objects requiring special treatment by the exception handler (e.g., a defined constructor, destructor, or assignment) are returned in memory. To pass "in memory", the caller allocates memory and passes a pointer to it as a hidden first parameter; the callee populates the memory and returns the pointer, popping the hidden pointer when returning.

In Linux/gcc double/floating point values should be pushed on the stack via the x87 pseudo-stack. Like so:

sub esp,8;    make room for the double
fld [ebp+x]; load our double onto the floating point stack
fstp [esp];  push our double onto the stack
call func;
add esp,8;

Using this method ensures it is pushed on the stack in the correct format.

The cdecl calling convention is usually the default calling convention for x86 C compilers, although many compilers provide options to automatically change the calling conventions used. To manually define a function to be cdecl, some support the following syntax:

void _cdecl function_name(params);

The _cdecl modifier must be included in the function prototype, and in the function declaration to override any other settings that might be in place.

[edit] syscall

This is similar to cdecl in that arguments are pushed right to left. EAX, ECX, and EDX are not preserved. The size of the parameter list in doublewords is passed in AL.

Syscall is the standard calling convention for 32 bit OS/2 API.

[edit] optlink

Arguments are pushed right to left. The three lexically first (leftmost) arguments are passed in EAX, EDX, and ECX and up to four floating-point arguments are passed in ST(0) through ST(3), although space for them is reserved in the argument list on the stack. Results are returned in EAX or ST(0). Registers EBP, EBX, ESI, and EDI are preserved.

Optlink is used by the IBM VisualAge compilers.

[edit] Callee clean-up

When the callee cleans the arguments from the stack it needs to be known at compile time how many bytes the stack needs to be adjusted. Therefore, these calling conventions are not compatible with variable argument lists, eg. printf(). They may be, however, slightly more space efficient, as the code needed to unwind the stack does not need to be generated by the calling code.

Functions which utilize these conventions are easy to recognize in ASM code because they will unwind the stack prior to returning. The x86 ret instruction allows an optional byte parameter that specifies the number of stack locations to unwind before returning to the caller. Such code looks like this:

 ret 12

[edit] pascal

The parameters are pushed on the stack in left-to-right order (opposite of cdecl), and the callee is responsible for balancing the stack before return.

This calling convention was common in the following 16 bit APIs: OS/2 1.x , Microsoft Windows 3.x, and Borland Delphi version 1.x.

[edit] register

An alias for Borland fastcall.

[edit] stdcall

The stdcall[1] calling convention is a variation on the pascal calling convention in which parameters are passed on the stack, pushed right-to-left. Registers EAX, ECX, and EDX are designated for use within the function. Return values are stored in the EAX register. The callee is responsible for cleanup of the stack.

Stdcall is the standard calling convention for the Microsoft Win32 API and for Open Watcom C++.

[edit] fastcall

Conventions entitled fastcall have not been standardized, and have been implemented differently, depending on the compiler vendor. Typically fastcall calling conventions pass one or more arguments in registers which reduces the number of memory accesses required for the call.

[edit] Microsoft fastcall

  • Microsoft or GCC [2] __fastcall[3] convention (aka __msfastcall) passes the first two arguments (evaluated left to right) that fit into ECX and EDX. Remaining arguments are pushed onto the stack from right to left.

[edit] Borland fastcall

Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right[4].

It is the default calling convention of Borland Delphi, where it is known as register.

[edit] Watcom register based calling convention

Watcom does not support the __fastcall keyword except to alias it to null. The register calling convention may be selected by command line switch. (However, IDA uses __fastcall anyway for uniformity)

Up to 4 registers are assigned to arguments in the order eax, edx, ebx, ecx. Arguments are assigned to registers from left to right. If any argument cannot be assigned to a register (say it is too large) it, and all subsequent arguments, are assigned to the stack. Arguments assigned to the stack are pushed from right to left. Names are mangled by adding a suffixed underscore.

Variadic functions fall back to the Watcom stack based calling convention.

The Watcom C/C++ compiler also uses the #pragma aux[5] directive that allows the user to specify his own calling convention. As its manual states, "Very few users are likely to need this method, but if it is needed, it can be a lifesaver".

[edit] TopSpeed / Clarion / JPI

The first four integer parameters are passed in registers eax, ebx, ecx and edx. Floating point parameters are passed on the floating point stack – registers st0, st1, st2, st3, st4, st5 and st6. Structure parameters are always passed on the stack. Additional parameters are passed on the stack after registers are exhausted. Integer values are returned in eax, pointers in edx and floating point types in st0.

[edit] safecall

In Borland Delphi on Microsoft Windows, the safecall calling convention encapsulates COM (Component Object Model) error handling, so that exceptions aren't leaked out to the caller, but are reported in the HRESULT return value, as required by COM/OLE. When calling a safecall function from Delphi code, Delphi also automatically checks the returned HRESULT and raises an exception if necessary. Together with language-level support for COM interfaces and automatic IUnknown handling (implicit AddRef/Release/QueryInterface calls), the safecall calling convention makes COM/OLE programming in Delphi easy and elegant.

The safecall calling convention is the same as the stdcall calling convention, except that exceptions are passed back to the caller in EAX as a HResult (instead of in FS:[0]), while the function result is passed by reference on the stack as though it were a final "out" parameter. When calling a Delphi function from Delphi this calling convention will appear just like any other calling convention, because although exceptions are passed back in EAX, they are automatically converted back to proper exceptions by the caller. When using COM objects created in other languages, the HResults will be automatically raised as exceptions, and the result for Get functions is in the result rather than a parameter. When creating COM objects in Delphi with safecall, there is no need to worry about HResults, as exceptions can be raised as normal but will be seen as HResults in other languages.

function function_name(a: DWORD): DWORD; safecall;

Returns a result and raises exceptions like a normal Delphi function, but it passes values and exceptions as though it was:

function function_name(a: DWORD; out Result: DWORD): HResult; stdcall;

[edit] Either caller or callee clean-up

[edit] thiscall

This calling convention is used for calling C++ non-static member functions. There are two primary versions of thiscall used depending on the compiler and whether or not the function uses variable arguments.

For the GCC compiler, thiscall is almost identical to cdecl: the calling function cleans the stack, and the parameters are passed in right-to-left order. The difference is the addition of the this pointer, which is pushed onto the stack last, as if it were the first parameter in the function prototype.

On the Microsoft Visual C++ compiler, the this pointer is passed in ECX and it is the callee that cleans the stack, mirroring the stdcall convention used in C for this compiler and in Windows API functions. When functions use a variable number of arguments, it is the caller that cleans the stack (cf. cdecl).

The thiscall calling convention can only be explicitly specified on Microsoft Visual C++ 2005 and later. On any other compiler thiscall is not a keyword. (Disassemblers like IDA, however, have to specify it anyway. So IDA uses keyword __thiscall for this)

[edit] Intel ABI

According to the Intel ABI, the EAX, EDX, and ECX are to be free for use within a procedure or function, and need not be preserved.

[edit] Microsoft x64 calling convention

The x64 calling convention (for long mode on x86-64) takes advantage of additional register space in the AMD64/Intel 64 platform. The registers RCX, RDX, R8, R9 are used for integer and pointer arguments (in that order left to right), and XMM0, XMM1, XMM2, XMM3 are used for floating point arguments. Additional arguments are pushed onto the stack (left to right). Integer return values (similar to x86) are returned in RAX if 64 bits or less. Floating point return values are returned in XMM0. Parameters less than 64 bits long are not zero extended; the high bits contain garbage.

When compiling for the x64 architecture using Microsoft tools, there is only one calling convention — the one described here, so that stdcall, thiscall, cdecl, fastcall, etc., are now all one and the same.

In the Microsoft x64 calling convention, it's the caller's responsibility to allocate 32 bytes of "shadow space" on the stack right before calling the function (regardless of the actual number of parameters used), and to pop the stack after the call. The shadow space is used to spill RCX, RDX, R8, and R9.[1]

For example, a function taking 5 integer arguments will take the first to fourth in registers, and the fifth will be pushed on the top of the shadow space. So the stack will be composed (in ascendant order) by the shadow space (32 bytes) followed by the fifth parameter.

In x86-64, Visual Studio 2008 stores floating point numbers in XMM6 and XMM7 (as well as XMM8 through XMM15); consequently, for x86-64, user-written assembly language routines must preserve XMM6 and XMM7 (as compared to x86 wherein user-written assembly language routines did not need to preserve XMM6 and XMM7). In other words, user-written assembly language routines must be updated to save/restore XMM6 and XMM7 before/after the function when being ported from x86 to x86-64.

On x86, one could create thunks that convert any function call from stdcall to thiscall by placing the 'this' pointer in ECX and jumping to the member function address. In x64 a universal stdcall-to-thiscall thunk cannot be written, except for functions that take no arguments. Putting the implicit 'this' in place requires shifting all the arguments, whose number and sizes are unknown.

[edit] AMD64 ABI convention

The calling convention of the AMD64 application binary interface is followed on Linux and other non-Microsoft operating systems. The registers RDI, RSI, RDX, RCX, R8 and R9 are used for integer and pointer arguments while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. As in the Microsoft x64 calling convention, additional arguments are pushed onto the stack and the return value is stored in RAX.

[edit] Standard exit and entry sequences for C code

Please note that all the following examples apply only to x86 (32-bit) code.

The Standard Entry Sequence to a function is as follows:

_function:
    push ebp       ;store the old base pointer
    mov ebp, esp   ;make the base pointer point to the current
                   ;stack location – at the top of the stack is the 
                   ;old ebp, followed by the return address and then
                   ;the parameters.
    sub esp, x     ;x is the size, in bytes, of all
                   ;"automatic variables" in the function

This sequence preserves the original base pointer EBP; points EBP to the current stack pointer (which points at the old EBP, followed by the return address and then the function parameters); and then creates space for automatic variables on the stack. Local variables are created on the stack with each call to the function, and are cleaned up at the end of each function. This behaviour allows for functions to be called recursively. In C and C++, variables declared "automatic" are created in this way.

The Standard Exit Sequence goes as follows:

mov esp, ebp   ;reset the stack to "clean" away the local variables
pop ebp        ;restore the original base pointer
ret            ;return from the function

Recovering the previous frame is an action so common that there's an opcode just to do that, called 'leave'. Thus, the exit sequence can also be written as follows:

leave          ;reset the stack and restore the original base pointer
ret            ;return from the function

While functions tend to have only one entry point, they may have multiple exit points, and thus may well have more than one standard exit sequence, or a jump to the standard exit sequence in the function body.

The following C function:

int _cdecl MyFunction(int i){ 
    int k;
    return i + k;
}

would produce the equivalent asm code:

;entry sequence
push ebp
mov ebp, esp
sub esp, 4     ;create function stack frame
 
;function code
mov eax, [ebp + 8] 
               ;move parameter i to accumulator
add eax, [ebp - 4]
               ;add k to i
               ;result is returned in eax
 
;exit sequence
mov esp, ebp
pop ebp
ret

Many compilers can optimize these standard sequences away when not needed, for instance when a function does not use local temporaries (often called "no stackframe generation"). If you require them e.g. for interlanguage interfacing, you probably need to search your compiler manual for a compiler directive (or pragma) to turn this kind of optimization locally off.

x86-64栈帧布局分布

摘自:http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64A few months ago I’ve written...
  • chinaclock
  • chinaclock
  • 2015年12月16日 21:06
  • 1255

学习日志-onMeasure等问题

一、 注意:从Android2.2开始,为了更好的使用,fill_parent被改为match_parent。因为当我们把一个子部件设置为fill_parent之后,该部件不是占有同等级部件剩余的空...
  • dacainiao007
  • dacainiao007
  • 2013年08月14日 16:32
  • 1585

几种调用约定(Calling convention)的介绍

调用约定(Calling convention):决定函数参数传送时入栈和出栈的顺序,由调用者还是被调用者把参数弹出栈,以及编译器用来识别函数名字的修饰约定。函数调用约定有多种,这里简单说一下: 1...
  • suxinpingtao51
  • suxinpingtao51
  • 2013年09月23日 02:49
  • 1298

OPENGL学习开篇

今天算是开篇吧, 2014. 2. 22 太久太久没写东西了,导致学习能力也退化了,浮躁的社会让我一点也没有了耐心,什么东西看两眼不会就寻思着别的办法去了。这是一种恶习...  思来想去,这几年除了...
  • u013741364
  • u013741364
  • 2014年02月22日 20:15
  • 1071

OpenStack METADATA不工作的分析方法

CentOS Linux 7 (Core) Kernel 3.10.0-229.7.2.el7.x86_64 on an x86_64centos-1 login: cloud-init[742]: ...
  • Tomstrong_369
  • Tomstrong_369
  • 2017年03月22日 14:05
  • 1355

Picasso源码分析(四):不变模式、建造者模式和Request的预处理

Request的不变模式(Immutable Pattern)  不变模式可增强对象的强壮型,允许多个对象共享某一个对象,降低了对该对象进行并发访问时的同步化开销。如果需要修改一个不变对象的状态,那么...
  • shihui512
  • shihui512
  • 2016年06月14日 17:06
  • 1322

VCS引起的oracle数据库异常重启一例

1. 环境描述 操作系统版本:SUSE Linux Enterprise Server 10 sp2 (x86_64) 数据库版本:Oracle 11.1.0.7.16 VCS版本:5.1 blog...
  • HW_LiBo
  • HW_LiBo
  • 2014年11月16日 13:09
  • 3534

Curator源码解析(三)访问接口分析

接着上一篇,将分析测试程序中的访问接口部分。 2调用ZooKeeper访问接口 初始化和启动分析完了,操作接口调用代码如下: String path = ZKPaths.makePath(PATH, ...
  • jiq408694711
  • jiq408694711
  • 2015年01月04日 23:17
  • 2917

非模态对话框的指针释放的理解

最近项目
  • ximi19881011
  • ximi19881011
  • 2014年04月20日 22:04
  • 1135

GATK使用方法详解(原始数据的处理)

转自:https://www.plob.org/article/7009.html 1. 对原始下机fastq文件进行过滤和比对(mapping) 对于Illumina下机数据推荐使用bwa进...
  • whiffen_cann
  • whiffen_cann
  • 2017年02月22日 14:50
  • 1678
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:x86 calling conventions
举报原因:
原因补充:

(最多只允许输入30个字)