[Repost] On the invoice

zhaozj2021-02-16  61

In the C language, suppose we have such a function:

Int Function (Int A, INT B)

This function can be used as long as you use the result = function (1, 2) in such a way. However, when the senior language is compiled into a computer code that the computer can be identified, there is a problem to conveze: in the CPU, the computer has no way to know how many, what kind of parameters are required, no hardware can save these parameters . That is, the computer does not know how to deliver parameters to this function, and the work of passing the parameters must be coordinated by the function caller and function itself. To this end, the computer provides a data structure called a stack to support parameter transmission.

The stack is an advanced data structure, and the stack has a storage area, a stack top pointer. The stack top pointer points to the first available data item in the stack (called a stack top). The user can add data in the top of the stack top, and this operation is called a press. After the stack, the stack is automatically turned into the location of the newly added data item, and the top pointer is also modified. The user can also take the top of the stack from the stack, called the pop-up (POP), after the pop-up stack, one element under the top of the stack becomes the top of the stack, and the top pointer needs to be modified.

When the function is called, the caller sequentially stacks the parameters, then calls the function, after the function is called, and the data is obtained in the stack and calculates. After the function calculation ends, or the caller, or the function itself modifies the stack to restore the stack to the original.

In parameter delivery, there are two important issues to be clearly stated:

When the number of parameters is more than one, after any order, the parameters are pressed into the stack function. Who will make the stack recovery into the advanced language, and these two issues will be described by the function call agreement. Common calls agree:

Stdcall CDECL FastCall thiscall Naked Call

1. STDCALL calls agreed STDCALL Many times, it is called a Pascal call agreement, because Pascal is a very common teaching computer programming language, its grammar is rigorous, and the function call convention used is stdcall. In the C / C compiler of the Microsoft C series, this call is often used in Pascal macro, and similar macros has WinAPI and Callback.

The syntax for stdcall call the agreed statement (for the function of the previous article as an example):

INT __STDCALL FUNCTION (Int A, INT B)

Stdcall's call agreement means: 1) Parameter from the right direction left press stack, 2) Function itself Modify the stack 3) Function name Automatically add the debord, followed by a @ symbol, followed by the size of the parameters

Take the above function as an example, the parameter b first is punched, then the parameter A, the function calls Function (1, 2) call to the assembly language will become:

Push 2 Second Parameter Forming Push 1 First Parameter Finding The Stack Call Function Call the parameters, pay attention to this time automatically put the CS: EIP

For the function itself, you can translate:

PUSH EBP Saves the EBP register that will be used to save the stack top pointer, and you can restore the MOV EBP when the function exits. CS: EIP, A, B, EBP 8 point to the AADD EAX, the EBP 12 in the [EBP 0CH] stack is saved, and EBP recovers ESPPOP EBPRET 8 and the name of this function is translated into _function @8

Note that different compilers will insert their assembly code to provide the versatility of compilation, but the general code is. Where the ESP to EBP is retained at the beginning of the function, the end recovery is a common method of compiler.

From the function call, 2 and 1 are sequentially inserted by the PUSH, and in the function, in the function, the offset access parameters are passed through the offset relative to the EBP (i.e., the stack pointer when the function is justified). After the function is over, RET 8 indicates the stack of 8 bytes, and the function restores the stack.

2, CDECL call conventions CDECL call conventions, also known as C call conventions, is the default invocation convention in C language, and its definition syntax is:

INT Function (int A, int b) // does not add modification is C call agreement int __cdecl function (int A, int b) // clearly indicates C call conventions

When writing this article, I am unexpected, I found that the parameter stack order of the CDECL call agreed is that the parameter is the same, the parameter first is pressed into the stack to the left. The difference is that the function itself does not clean up the stack, and the caller is responsible for cleaning the stack. Due to this change, the number of C-call conventions allow the number of parameters of the function is not fixed, which is also a major feature of the C language. For the previous FUNCTION function, the assembly code after using CDECL becomes:

Call Push 1Push 2Call FunctionAdd ESP, 8 Note: Here the caller saves the EBP register at the recovery stack called function _function, the register will be used to save the stack top pointer, and you can restore MOV EBP when the function exits. ESP Save Stack Pointer MOV EAX, [EBP 8H] The EBP pointing in the stack is preserved before the Position of EBP, CS: EIP, A, B, EBP 8 points to the AADD EAX, [EBP 0CH] stack in EBP 12 save BMOV ESP, EBP Restore Esppop Ebpret Note, there is no modification of the stack here

In MSDN, the modification automatically adds a predecessor before the function name, so the function name is recorded in _function in the symbol table, but I don't see this change when compiling.

Since the parameters are sequenced from the right to left, the first parameter is closest to the top of the stack, so when the number of parameters are used, the position of the first parameter in the stack can certainly know, as long as the parameters are not The number can be determined according to the first latter subsequent parameters, you can use an unproducible parameter, such as the Sprintf function in the CRT, is defined as:

INT Sprintf (Char * Buffer, Const Char * Format, ...)

Since all uncertain parameters can be determined via Format, there is no problem with the parameters of the number of applications.

3, FastCallFastCall call agreement and stdcall, which means:

The first and second DWORD parameters of the function (or smaller size) passed through ECX and EDX, other parameters passed from the right left sequential stack called function cleaning stack function name modification rules with stdcall its declaration syntax : Int FastCall Function (Int A, INT B) 4, ThiscallThiscall is the only function modification that cannot be explicitly indicated because thisCall is not a keyword. It is a C class member function default call agreement. Since the member function call has a THIS pointer, it must be dealt with, thiscall means:

The parameter is determined from the right to left. If the number of parameters is determined, the THIS pointer passes to the caller via ECX; if the number of parameters is uncertain, the THIS pointer is pressed into the stack after all parameter stacks. For the number of parameters, the caller clensizes the stack, otherwise the function clensizes the stack to illustrate this call agreement, defined as follows and using the code:

Class a {public: int function1 (int A, int b); int function2 (int A, ...);}; int a :: function1 (int a, int b) {RETURN A B;} # incrude Int A :: function2 (int A, ...) {va_list ap; va_start (ap, a); int i; int result = 0; for (i = 0; i

After the Callee function is translated into compilation:

// call the function function1 0401C1D push 200401C1F push 100401C21 lea ecx, [ebp-8] 00401C24 call function1 Note that there is no stack // this function call function2 00401C29 push 300401C2B push 200401C2D push 100401C2F push 300401C31 lea eax, [ebp-8 ] Here, this pointer 00401C34 PUSH EAX00401C35 CALL FUNCTION 200401C3A Add ESP, 14H

It can be seen that if the number of parameters is fixed, it is similar to stdcall, similar to CDECL.

5, Naked Call This is a rare call agreement, and general programming do not use it. The compiler does not add initialization and cleaning code to this function. It is more special. You cannot return the return value with Return, you can only return the result with the insert assembly. This is generally used in real mode driver design, assuming that a summary of the addition program is defined, can be defined as:

__Declspec (Naked) Int Add (int A, int b) {__ASM MOV Eax, A __ASM Add Eax, B __ASM Ret}

Note that this function does not have an explicit RETURN return value, returns to the implementation of the EAX register, and the RET instructions that exit the function must be explicitly inserted. The above code is translated into compilation, it becomes:

MOV EAX, [EBP 8] ADD EAX, [EBP 12] RET 8 Note that this modification is used in combination with __stdcall, and CDECL, the front is the code used in conjunction with CDECL, the code combined with stdcall, change to make:

__declspec (naked) int __stdcall function (int A, int b) {__ASM MOV EAX, A __ASM ADD EAX, B __ASM RET 8 // Note the back 8}

As for this function being called, the normal CDECL and STDCALL call function are consistent.

Common issues caused by function call conventions If the definition agreement is inconsistent, the stack will result in damage, resulting in serious problems, and below is two common problems:

Function prototype declaration and function body definition When the DLL import function declares that the latter is declared as an example, suppose we declare a function in the DLL species:

__declspec (DLLEXPORT) INT FUNC (Int A, INT B); // Note that there is no STDCALL here, using CDECL usage time code:

Typedef int (* WinAPI DLLFUNC) FUNC (INT A, INT B); HLIB = loadingLibrary (...); DLLFUNC FUNC = (DLLFUNC) getProcaddress (...) // This modified call agreed Result = Func (1, 2); // cause errors

Since the caller does not understand the meaning of WinAPI's meaning, the above code inevitably causes the stack to be destroyed, and the CHECKESP function inserted by the MFC when compiling will tell you that the stack is destroyed.

转载请注明原文地址:https://www.9cbs.com/read-19530.html

New Post(0)