[转]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: ebxesiediebpdsesss, 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 in edx: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 CALL instruction 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 ESP in EBP so as to be able to use EBP as 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 that EBP must be preserved by any C function. Hence the callee, if it is going to set up EBP as 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 of EBP as it was pushed; the next doubleword, at [EBP+4], holds the return address, pushed implicitly by CALL. The parameters start after that, at [EBP+8]. The leftmost parameter of the function, since it was pushed last, is accessible at this offset from EBP; the others follow, at successively greater offsets. Thus, in a function such as printf which 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 ESP further, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets from EBP.
  • The callee, if it wishes to return a value to the caller, should leave the value in ALAX or EAX depending on the size of the value. Floating-point results are typically returned in ST0.
  • Once the callee has finished processing, it restores ESP from EBP if it had allocated local stack space, then pops the previous value of EBP, and returns via RET (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 ESP to remove them (instead of executing a number of slow POP instructions). 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 CALL instruction 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 SP in BP so as to be able to use BP as 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 that BP must be preserved by any function. Hence the callee, if it is going to set up BP as 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 of BP as 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 from BP; the others follow, at successively greater offsets.
  • The callee may also wish to decrease SP further, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets from BP.
  • The callee, if it wishes to return a value to the caller, should leave the value in ALAX or DX:AX depending on the size of the value. Floating-point results are returned in ST0. Results of type Real (Borland's own custom floating-point data type, not handled directly by the FPU) are returned in DX:BX:AX. To return a result of type String, 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 the RETF instruction.
  • Once the callee has finished processing, it restores SP from BP if it had allocated local stack space, then pops the previous value of BP, and returns via RETF. It uses the form of RETF with 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);

 

 

 

posted @ 2013-07-01 13:07  Scan.  阅读(604)  评论(0)    收藏  举报