Function call process from the perspective of Assembly

Source: Internet
Author: User
Sometimes, we need to have a deep understanding of the details of the programming language, such as the programming language structure-how functions are implemented and how functions are executed. Let's take an example to see how the stack changes when a function is called. The first thing to understand is the Operation Stack Segment. ss can only use esp or ebp registers, and other registers eaxebxedx cannot be enough. Esp always points to the top of the stack, and ebp uses

Sometimes, we need to have a deep understanding of the details of the programming language, such as the programming language structure-how functions are implemented and how functions are executed. Let's take an example to see how the stack changes when a function is called.

#include 
 
  long test(int a,int b){    a = a + 1;    b = b + 100;    return a + b;}void main(){    printf("%d",test(1000,2000));}
 

Write a 32-bit assembly as follows:

; //////////////////////////////////////// //////////////////////////////////////// //////////////////////. 386. model flat, stdcall; here we use stdcall, which is the pressure starting from the last when the function parameter is pressed to the stack, and the called function is responsible for clearing the stack option casemap: none; Case Sensitive: delib msvcrt. lib; here the class library is introduced, which is equivalent to # include
 
  
Printf proto c: DWORD,: VARARG; this is to declare the function header we will use, then the assembler will automatically go to msvcrt. found in lib;: The parameters behind the VARARG table are not sure because C is like printf (const char *,...);; note that the called function is not responsible for clearing the stack because it does not know the number of parameters. Instead, the caller is responsible for clearing the stack. dataszTextFmt BYTE '% d', 0; this is used for type conversion. like C, the character is of the BYTE type a dword 1000. suppose B dword 2000; there is no difference between int and long when processing values in double words; //////////////////////////////////////// //////////////////////////////////////// /////////. code_test proc; A: DWORD, B: DWORD push ebp mov ebp, esp mov eax, dword ptr ss: [ebp + 8] add eax, 1 mov edx, dword ptr ss: [ebp + 0Ch] add edx, 100 add eax, edx pop ebp retn 8_test endp_main proc push dword ptr ds: B; in the disassembly, we can see that B is not B, but a [******] Digital dword ptr, which means we put [*****] in the ds (data segment); in the beginning, a double-character-length value is obtained to push dword ptr ds: a; the corresponding byte ptr *** is to take a byte, for example, mov al, byte ptr ds: szTextFmt; get % instead of d call _ test push eax. assume that the address of push eax is ×××× push offset szTextFmt call printf add esp, 8 ret _ main endpend _ main; //////////////////////////////////////// ///////////////////// the stack changes are described below
 

The first thing to understand is the Operation Stack Segment. ss can only use esp or ebp registers, and other registers eax ebx edx cannot be enough. Esp always points to the top of the stack, and ebp is used to address the stack segment.

Push command is the pressure stack ESP = ESP-4, pop command is the output stack ESP = ESP + 4.

Assume that the initial stack of the main function is ESP = 400.

Push dword ptr ds: B; ESP-4 = 396-> inside the value is 2000 is the value of B push dword ptr ds:; ESP-4 = 392-> the value is 1000 is a value call test; ESP-4 = 388-> What is the value inside? This is too important because the principle we use to find game functions lies. The value is the address of the next command of the call test Command-> push eax address ×××× to the test function to push ebp; ESP-4 = 384-> It saves the current ebp value instead of clearing ebp mov ebp, esp; here ESP = 384 does not change, but ebp = esp = 384, why do we need to do this? because we need to use ebp to find the mov eax and dword ptr ss in the stack: [ebp + 8]; the disassembly is like this. think about why a is [ebp + 8]. let's look up the address 392 in the stack and save the value of a. Here ebp = 384 plus 8 is exactly 392; in this way, the passed 1000 is taken out. eax = 1000add eax, 1; equivalent to a + 1 eax = 1001mov edx, dword ptr ss: [ebp + 0Ch]; 0Ch = 12. the stack address is 384 + 12 = 396, that is, 2000. edx = 2000add edx, 100; equivalent to B + 100 edx = 2100add eax, edx; eax = eax + edx = 1001 + 2100 = 3101 here eax has saved the final result; because win32 assembly generally uses eax to return results, if the final result is not in eax, it should be put into eax; for example, if my result is saved in the nRet variable, mov eax should be like this at the end, dword ptr nRetpop ebp; ESP = 384 + 4 = 388 and the value stored in the top 384 of the stack is saved to ebp to restore the original value of ebp; in the beginning, we pressed the ebp value to the stack. mov ebp and esp have changed the ebp value. here, recovery ensures the stack balance retn 8; ESP + 8-> 396 here, retn is called by the system. we don't need to worry that the system will automatically direct the EIP pointer to the next instruction of the original call; because the system automatically restores the pressure stack of the call ESP + 4 restores the call pressure stack. at this time, ESP = 400 is the stack where the function call starts. that is to say, the stack before the function call is the same as that after the function call; this is the stack balance. because we use the retn 8 above stdcall, it means that the caller is responsible for restoring the stack. the test function is called, so we are responsible for adding 8 to the stack, call where the system automatically restores the push eax; ESP-4 = 396-> which saves the eax value 3101; the above has seen that eax stores the return value, we want to pass it to printf is also through the stack transfer push offset szTextFmt; ESP-4 = 392-> inside the save szTextFmt address that is C inside the pointer is actually nothing to pass the string, we upload all the addresses. DWORD is the most widely used string type in the compilation process, whether in assembly or C. The transfer parameters in the game are much simpler than call printf; ESP-4 = 388-> which saves the address of the next command add esp, 8; ESP + 8 = 400 restores the stack status before calling printf. as mentioned above, the parameters following printf are: VARARG has a caller to restore the stack. Therefore, printf does not have any commands such as retn 8. this is because the caller is responsible for clearing the stack. main is the caller. so the following sentence is "add esp, 8. restore the stack to the point where printf is called. The pressure stack in call printf is restored by the system and completed by the system. we don't need to worry about it. it is enough to know that it is saved as the return address; the ret; the other thing returned by the main function is that the system automatically handles the task.

This article is available at http://www.nowamagic.net/librarys/veda/detail/232.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.