[转]Calling Convention
1. 比较齐全的:http://www.agner.org/optimize/calling_conventions.pdf
2. 一个nasm的example: http://cs.lmu.edu/~ray/notes/nasmexamples/
If you are writing assembly language functions that will link with C, and you're using gcc, you must obey the gcc calling conventions. These are:
- Parameters are pushed on the stack, right to left, and are removed by the caller after the call.
- After the parameters are pushed, the call instruction is made, so when the called function gets control, the return address is at
[esp], the first parameter is at[esp+4], etc. - If you want to use any of the following registers:
ebx,esi,edi,ebp,ds,es,ss, you must save and restore their values. In other words, these values must not change across function calls. When you make calls, you can assume these won't change (as long as everyone plays by the rules). - A function that returns an integer value should return it in
eax, a 64-bit integer inedx:eax, and a floating point value should be returned on the fpu stack top.
3. nasm的functiohn calls: http://net.pku.edu.cn/~course/cs201/2004/Assembly/nasm-0.98.36-xdoc/html/nasmdoc8.html
8.1.2 Function Definitions and Function Calls
The C calling conventionThe C calling convention in 32-bit programs is as follows. In the following description, the words caller and callee are used to denote the function doing the calling and the function which gets called.
- The caller pushes the function's parameters on the stack, one after another, in reverse order (right to left, so that the first argument specified to the function is pushed last).
- The caller then executes a near
CALLinstruction to pass control to the callee. - The callee receives control, and typically (although this is not actually necessary, in functions which do not need to access their parameters) starts by saving the value of
ESPinEBPso as to be able to useEBPas a base pointer to find its parameters on the stack. However, the caller was probably doing this too, so part of the calling convention states thatEBPmust be preserved by any C function. Hence the callee, if it is going to set upEBPas a frame pointer, must push the previous value first. - The callee may then access its parameters relative to
EBP. The doubleword at[EBP]holds the previous value ofEBPas it was pushed; the next doubleword, at[EBP+4], holds the return address, pushed implicitly byCALL. The parameters start after that, at[EBP+8]. The leftmost parameter of the function, since it was pushed last, is accessible at this offset fromEBP; the others follow, at successively greater offsets. Thus, in a function such asprintfwhich takes a variable number of parameters, the pushing of the parameters in reverse order means that the function knows where to find its first parameter, which tells it the number and type of the remaining ones. - The callee may also wish to decrease
ESPfurther, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets fromEBP. - The callee, if it wishes to return a value to the caller, should leave the value in
AL,AXorEAXdepending on the size of the value. Floating-point results are typically returned inST0. - Once the callee has finished processing, it restores
ESPfromEBPif it had allocated local stack space, then pops the previous value ofEBP, and returns viaRET(equivalently,RETN). - When the caller regains control from the callee, the function parameters are still on the stack, so it typically adds an immediate constant to
ESPto remove them (instead of executing a number of slowPOPinstructions). Thus, if a function is accidentally called with the wrong number of parameters due to a prototype mismatch, the stack will still be returned to a sensible state since the caller, which knows how many parameters it pushed, does the removing.
There is an alternative calling convention used by Win32 programs for Windows API calls, and also for functions called by the Windows API such as window procedures: they follow what Microsoft calls the __stdcall convention. This is slightly closer to the Pascal convention, in that the callee clears the stack by passing a parameter to the RET instruction. However, the parameters are still pushed in right-to-left order.
Thus, you would define a function in C style in the following way:
global _myfunc
_myfunc:
push ebp
mov ebp,esp
sub esp,0x40 ; 64 bytes of local stack space
mov ebx,[ebp+8] ; first parameter to function
; some more code
leave ; mov esp,ebp / pop ebp
ret
At the other end of the process, to call a C function from your assembly code, you would do something like this:
extern _printf
; and then, further down...
push dword [myint] ; one of my integer variables
push dword mystring ; pointer into my data segment
call _printf
add esp,byte 8 ; `byte' saves space
; then those data items...
segment _DATA
myint dd 1234
mystring db 'This number -> %d <- should be 1234',10,0
This piece of code is the assembly equivalent of the C code
int myint = 1234;
printf("This number -> %d <- should be 1234\n", myint);
4. nasm的pascal calling convention: http://net.pku.edu.cn/~course/cs201/2004/Assembly/nasm-0.98.36-xdoc/html/nasmdoc7.html#section-7.5.1
The 16-bit Pascal calling convention is as follows. In the following description, the words caller and callee are used to denote the function doing the calling and the function which gets called.
- The caller pushes the function's parameters on the stack, one after another, in normal order (left to right, so that the first argument specified to the function is pushed first).
- The caller then executes a far
CALLinstruction to pass control to the callee. - The callee receives control, and typically (although this is not actually necessary, in functions which do not need to access their parameters) starts by saving the value of
SPinBPso as to be able to useBPas a base pointer to find its parameters on the stack. However, the caller was probably doing this too, so part of the calling convention states thatBPmust be preserved by any function. Hence the callee, if it is going to set upBPas a frame pointer, must push the previous value first. - The callee may then access its parameters relative to
BP. The word at[BP]holds the previous value ofBPas it was pushed. The next word, at[BP+2], holds the offset part of the return address, and the next one at[BP+4]the segment part. The parameters begin at[BP+6]. The rightmost parameter of the function, since it was pushed last, is accessible at this offset fromBP; the others follow, at successively greater offsets. - The callee may also wish to decrease
SPfurther, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets fromBP. - The callee, if it wishes to return a value to the caller, should leave the value in
AL,AXorDX:AXdepending on the size of the value. Floating-point results are returned inST0. Results of typeReal(Borland's own custom floating-point data type, not handled directly by the FPU) are returned inDX:BX:AX. To return a result of typeString, the caller pushes a pointer to a temporary string before pushing the parameters, and the callee places the returned string value at that location. The pointer is not a parameter, and should not be removed from the stack by theRETFinstruction. - Once the callee has finished processing, it restores
SPfromBPif it had allocated local stack space, then pops the previous value ofBP, and returns viaRETF. It uses the form ofRETFwith an immediate parameter, giving the number of bytes taken up by the parameters on the stack. This causes the parameters to be removed from the stack as a side effect of the return instruction. - When the caller regains control from the callee, the function parameters have already been removed from the stack, so it needs to do nothing further.
Thus, you would define a function in Pascal style, taking two Integer-type parameters, in the following way:
global myfunc
myfunc: push bp
mov bp,sp
sub sp,0x40 ; 64 bytes of local stack space
mov bx,[bp+8] ; first parameter to function
mov bx,[bp+6] ; second parameter to function
; some more code
mov sp,bp ; undo "sub sp,0x40" above
pop bp
retf 4 ; total size of params is 4
At the other end of the process, to call a Pascal function from your assembly code, you would do something like this:
extern SomeFunc
; and then, further down...
push word seg mystring ; Now push the segment, and...
push word mystring ; ... offset of "mystring"
push word [myint] ; one of my variables
call far SomeFunc
This is equivalent to the Pascal code
procedure SomeFunc(String: PChar; Int: Integer);
SomeFunc(@mystring, myint);

浙公网安备 33010602011771号