zoukankan      html  css  js  c++  java
  • C语言函数调用完整过程

    C语言函数调用详细过程

    函数调用是步骤如下:

    1. 按照调用约定传参

      • 调用约定是调用方(Caller)和被调方(Callee)之间按相关标准
        对函数的某些行为做出是商议,其中包括下面内容:
        传参顺序:是从左往右传还是从右往左
        传参方式:是用寄存器传还是使用内存传
        平栈方式:是调用方平栈还是被调方平栈
        返回值的传递方式:是用寄存器传还是使用内存传

      • 什么是堆桟?
        一个程序运行的时候,它的进程的地址空间一般可以分为四块:
        代码区,数据区,堆,栈,每块功能如下:

        区域 功能
        代码区 存放函数被编译后的二进制可执行代码
        数据区 只读区:存放常量,例如:常量字符串,const修饰的全局变量等
        可读写区:存放全局变量和静态变量
        除去其他三个区域,剩下的都是堆,不连续
        存放函数运行时所需的参数,寄存器环境,返回值,局部变量

      以下面代码为例:

          int  TestFunction(char szBuff[],int nSize)
          {
              for (int iIndex = 0; iIndex < nSize; iIndex++)
              {
                 szBuff[iIndex] = 'x';
              }
              return 3;
          }
      
          int main()
          {
            char szBuff[32] = { "sfjdlskfjl" };
            int nRet = TestFunction(szBuff, 32);
            return 0;
          }
      

      函数参数参数传递:
      传递参数.png
      从上图中可以看出函数参数入栈

    2. 保存返回地址(紧挨着被调用函数的下一行可执行代码的内存地址)
      从上图中可以看出函数调用完成后,紧挨着的第一条指令为:
      00EB175B add esp,8
      所以,参数传递完成后就是返回值入栈:
      返回地址入栈.png

    3. 程序流程转移到被调用函数地址处

    4. 保存调用方栈底
      保存调用方栈底.png

    5. 切换到当前函数(被调用函数)的栈底
      调用方栈底保存完成后,当前的栈顶(ESP记录的地址)就成为被调用函数的栈底
      切换到被调用函数的栈底.png

    6. 为局部变量分配空间
      为局部变量分配空间.png
      这里程序为调试版本,所以为局部变量分配的空间比较大,在Release版本中
      会根据局部变量实际所需空间来分配大小

    7. 保存寄存器环境
      这里一共保存了3个寄存器,共12字节,在Release版本下,只保存两个
      保存寄存器环境.png
      在Debug版程序中(有/Zi(带有调试信息)和/Od(禁止优化)编译命令),除了为
      局部变量分配较大的内存空间外,还会将分配的局部变量空间全部置为0xCC:
      局部变量空间赋值CC.png
      这种填充方式比较直观,能够让我们在调试时直观的观察到是否发生越界等错误

    8. 开始执行函数体代码
      此时当前函数的栈的内存布局如下:
      当前函数堆桟布局.jpeg

    9. 恢复寄存器环境
      恢复寄存器环境.png

    10. 释放分配的局部变量空间
      只是将当前的栈底指针(EBP)的值赋值给栈顶指针(ESP)就完成了:
      释放局部变量空间.png

    11. 恢复调用方栈底
      恢复调用方栈底.png

    12. 平栈或者返回

      • 如果是_fastcall,_stdcall调用约定,那么被调用函数平栈后,取出返回地址
        函数流程转移到调用方
      • 其他调用约定则是直接取出保存的返回地址,函数流程返回到调用方,又调用方
        平栈
  • 相关阅读:
    ORACLE获取DML(Insert into)的方法
    联动
    浏览器插件使用
    tomcat 修改用户名和密码
    Oracle单行函数
    CVS团队源代码管理
    jotm的xml
    ORACLE获取DDL(Create Table)的几种常用的方法
    正则表达式详解
    java.lang.NoClassDefFoundError
  • 原文地址:https://www.cnblogs.com/UnknowCodeMaker/p/11002225.html
Copyright © 2011-2022 走看看