1、Interfacing HLL code with asm
1.1、C calling convention – standard stack frame
Arguments passed to a C function are pushed onto the stack, right to left, before the function is called. The first thing the called function does is push the (E)BP register, then copy (E)SP into it. This creates a data structure called the standard C stack frame.
32-bit code | 16-bit code, TINY, SMALL, or COMPACT memory models | 16-bit code, MEDIUM, LARGE, or HUGE memory models | |
Create standard stack frame, allocate 16 bytes for local variables, save registers | push ebp mov ebp,esp sub esp,16 push edi push esi … | push bp mov bp,sp sub sp,16 push di push si … | push bp mov bp,sp sub sp,16 push di push si … |
Restore registers, destroy stack frame, and return | … pop esi pop edi mov esp,ebp pop ebp ret | … pop si pop di mov sp,bp pop bp ret | … pop si pop di mov sp,bp pop bp retf |
Size of ‘slots’ in stack frame, i.e. stack width | 32 bits | 16 bits | 16 bits |
Location of stack frame ‘slots’ | [ebp + 8] [ebp + 12] [ebp + 16]… | [bp + 4] [bp + 6] [bp + 8]… | [bp + 6] [bp + 8] [bp + 10]… |
If an argument passed to a function is wider than the stack, it will occupy more than one ‘slot’ in the stack frame. A 64-bit value passed to a function (long long or double) will occupy 2 stack slots in 32-bit code or 4 stack slots in 16-bit code.
Function arguments are accessed with positive offsets from the BP or EBP registers. Local variables are accessed with negative offsets. The previous value of BP or EBP is stored at [bp + 0] or [ebp + 0]. The return address (IP or EIP) is stored at [bp + 2] or [ebp + 4].
1.2、C calling convention – return values
A C function usually stores its return value in one or more registers.
32-bit code | 16-bit code, all memory models | |
8-bit return value | AL | AL |
16-bit return value | AX | AX |
32-bit return value | EAX | DX:AX |
64-bit return value | EDX:EAX | space for the return value is allocated on the stack of the calling function, and a ‘hidden’ pointer to this space is passed to the called function |
128-bit return value | hidden pointer | hidden pointer |
1.3、C calling convention – saving registers
GCC expects functions to preserve the callee-save registers:
EBX, EDI, ESI, EBP, DS, ES, SS
You need not save these registers:
EAX, ECX, EDX, FS, GS, EFLAGS, floating point registers
In some OSes, FS or GS may be used as a pointer to thread local storage (TLS), and must be saved if you modify it.
1.4、C calling convention – leading underscores
Some C compilers (those for DOS and Windows, and those with COFF output) prepend an underscore to the names of C functions and global variables. If a C global variable, e.g. conv_mem_size, is accessed by asm code, it should be declared with a leading underscore in the asm code:
EXTERN _conv_mem_size ; NASM syntax
mov [_conv_mem_size],ax
Linux ELF does NOT use underscores. Watcom C uses trailing underscores for function names, and leading underscores for global variables.
If your GCC supports it, leading underscores can be turned off with the compiler option -fno-leading-underscore
Pascal calling conventions
Function arguments are pushed onto the stack from left to right before the function is called. C-style variable-length argument lists are not possible in Pascal. (Look in file STDARG.H and think about it.)
In C, the calling function must ‘clean up the stack’ (remove function arguments from the stack after the called function returns). In Pascal, the called function must do this, before returning.
Pascal identifiers are case-insensitive. MyKewlProc() will be stored in the object code file as MYKEWLPROC
Other calling conventions
The __stdcall calling convention, used by Windows, is a hybrid of the C and Pascal calling conventions. Like C, function arguments are pushed right-to-left. Like Pascal, the called function must clean up the stack. Exception: the caller must clean up the stack for functions that accept a variable number of arguments, e.g. printf(const char *format, …);
Watcom C uses a register-based calling convention. See sections 7.4, 7.5, 10.4, and 10.5 in cuserguide.pdf in the Watcom documentation. Individual functions can be declared to use the normal, stack-based calling convention.
GCC can be made to use a register calling convention by compiling with gcc -mregparm=NNN …
See the GCC documentation for details.
参考网址:http://www.hoverlees.com/blog/?p=17
参考网址:https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64
参考网址:http://www.cs.virginia.edu/~evans/cs216/guides/x86.html