C function call Principle

Source: Internet
Author: User

C function call Principle

 

Function call Process

 

The C calling convention in 16-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 CALL Instruction to pass control to the callee. This CALL Is either near or far depending on the memory model. the callee controls es control, and typically (although this is not actually necessary, in functions which do not need to access their parameters) starts by saving the value 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 C function. Hence the callee, if it is going to set up BP AsFrame pointer, Must push the previous value first. The callee may then access its parameters relative BP . The word [BP] Holds the previous value BP As it was pushed; the next word, [BP+2] , Holds the offset part of the return address, pushed implicitly CALL . In a small-model (near) function, the parameters start after that, [BP+4] ; In a large-model (far) function, the segment part of the return address lives [BP+4] , And the parameters begin [BP+6] . The leftmost parameter of the function, since it was pushed last, is accessible at this offset from BP ; The others follow, at successively greater offsets. Thus, in a function such 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 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, shocould leave the value in AL , AX Or DX:AX Depending on the size of the value. Floating-point results are sometimes (depending on the compiler) returned in ST0 . Once the callee has finished processing, it restores SP From BP If it had allocated local stack space, then pops the previous value BP , And returns RETN Or RETF Depending on memory model. When the caller regains control from the callee, the function parameters are still on the stack, so it typically adds an immediate constant SP 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, whichKnowsHow many parameters it pushed, does the removing. reference the call process example and test cases from the NASM Manual
    /* Take three parameters as an example. In AT & T32 assembly, the stack increases from fun to low address (p0, p1, p2); 1. parameter stack entry, right-> leftgcc practice: Where p0 p1 p2 stands for immediate count movl $ p2 8 (% esp) movl $ p1 4 (% esp) movl $ p0 (% esp) | _______ | ebp-> | _______ | |__ p2 ___ | |__ p1 ___ |__ p0 ___ | <-esp | _______ | _______ | 2. call fun | _______ | ebp-> | _______ | |__ p2 ___ | |__ p1 ___ |__ p0 ___ |__ ret __| <-esp | _______ | 3. jump to fun code push % eb Pmovl % esp, % ebp | _______ | |__ p2 ___ | |__ p1 ___ | |__ p0 ___ |__ ret __| ebp-> |__ ebp __| <-esp | _______ | the stored ebp is the ebp in step 1, that is, the previous ebp, not the ebp on the left of the figure. If the stack grows to a low address, the old ebp = [ebp] ret = [ebp + 4] p0 = [ebp + 8] p1 = [ebp + 12] p2 = [ebp + 16] 4. decrease ESP further, so as to allocate space on the stack for local variables, which will then be accessible at negative offsets from EBP. su Bl $24, % esp allocate stack space as needed, example 24/4 = 6 4B local variables | _______ | |__ p2 ___ | |__ p1 ___ |__ p0 ___ |__ ret __ | ebp-> |__ ebp __| | _______ | <= esp + 12 = ebp-12 | _______ | <-esp | _______ | 5. returns the 5.1 adjustment Stack pointer Method 1: addl $24, % esp Method 2: movl % ebp, % esp | _______ | |__ p2 ___ | |__ p1 ___ | |__ p0 ___ |__ ret __| ebp-> |__ ebp __| <-esp | _______ | _______ | 5.2 the old frame pointer = destroy the current stack frame popl % ebp | _______ | ebp-> | _______ | |__ p2 ___ | |__ p1 ___ | |__ p0 ___ |__ ret __| <-esp |__ ebp __ | _______ | 5.3 return the caller ret | _______ | ebp-> | _______ | __p2 ___ | |__ p1 ___ | |__ p0 ___ | <-esp |__ ret __| |__ ebp __| |_______ | | _______ | The esp must be adjusted to remove the parameter. Gcc did not do this step. Esp is reserved here. When the function is called again below, the old value will be overwritten. See step 1! Steps 5.1 and 5.2 can be replaced by the leave command * // verification # include
       
        
    # Include
        
         
    Void fun (int a, int B) {int local; unsigned int I, j; long ret; local = 12; a = 10; // printf ("% d \ n", a); # if 1asm volatile ("movl % ebp, % eax \ n \ t" "movl % esp, % ebx \ n \ t ":" = a "(I)," = B "(j) :); printf (" ebp = % p; esp = % p \ n ", I, j); printf (" local auto var: % d \ n ", I-j ); // space occupied by local variables asm volatile ("movl 12 (% ebp), % eax \ n \ t" // parameter B "movl 8 (% ebp ), % ebx \ n \ t "// parameter a" movl 4 (% ebp), % ecx \ n \ t "// ret: "= a" (I), "= B" (j), "= c" (ret) :); printf ("p2 = % x; p1 = % x; ret = % p \ n ", I, j, ret); # endif} int main (int argc, char * argv []) {fun (1, 2 ); exit (0 );}
        
       
    Summary

    1-if you compile the Assembly on your own, you need to handle the work yourself, as well as the protection measures for the pressure stack out of some registers

    2-step 5.2: When the ebp pops up, a stack frame does not exist, that is, the function environment has been revoked. Therefore, if you return a local variable reference in fun, it will be meaningless. This is the most common problem !!!

    3-local variable space allocation. In other words, the size of esp should be determined by the symbol table during compilation!

     

Related Article

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.