美文网首页
理解函数的调用过程

理解函数的调用过程

作者: 梦工厂 | 来源:发表于2020-09-30 14:52 被阅读0次
    一、函数的范围
    二、函数的调用
          2.1 函数的进入
          2.2 函数的退出
          2.3. 函数返回值的传递 (不同编译器、不同平台是不一样的)
          2.4. Go为什么可以返回多个值?
    

    一、函数的范围

    ebp寄存器指向函数的栈底,esp寄存器指向函数的栈顶,共同划分了函数的活动范围。
    减小esp的值相当于在栈上开辟空间,而增大esp的值相当于在栈上回收空间;

    二、函数的调用

    2.1 函数的进入
    • 参数入栈,从右到左,有的通过寄存器传递;
    • call function(1将当前指令的下一个指令地址压入栈中.2跳转到函数体执行)
    • push ebp: 把ebp压入栈中(old ebp);
    • mov ebp,esp: ebp=esp
    • [可选] sub esp,XXX: 在栈上分配XXX字节的临时空间;
    • [可选] push XXX:保存寄存器的值,可以保证寄存器在函数调用前后保持不变;
      栈的变化
    函数的标准开头
    2.2 函数的退出
    • [可选] pop XXX:如有必要,恢复保存过的寄存器;
    • mov esp,ebp: 恢复esp同时回收局部的变量空间;
    • pop ebp: 从栈中恢复保存的ebp的值;
    • ret: 从栈中取得返回地址,并跳转到该位置;
    2.3. 函数返回值的传递 (不同编译器、不同平台是不一样的)
    • 函数将返回值存储到eax寄存器中,返回后函数的调用方再去读取eax;
    • eax本身只有4个字节,对于5~8个字节对象的情况,惯例是通过eax和edx联合返回. eax储存返回值低4字节,而edx存储返回值高1~4字节;
    • 对于更大的对象:
      1. 调用方函数A额外开辟一片空间,称为temp;
      2. 将temp的地址作为隐藏函数传递给函数B;
      3. 函数B将数据拷贝给temp对象,并将temp对象的地址用eax传出;
      4. 函数B返回后,函数A将eax指向的temp对象的内容拷贝给相应变量;
    2.4. Go为什么可以返回多个值?

    不同平台对于函数有不同的调用规范.

    • 例如32位通过栈传递参数, 通过eax寄存器传递返回值.
    • 64位windows通过rcx, rdx, r8, r9传递前4个参数, 通过栈传递第5个开始的参数, 通过eax寄存器传递返回值.
    • 64位linux, unix通过rdi, rsi, rdx, rcx, r8, r9传递前6个参数, 通过栈传递第7个开始的参数, 通过eax寄存器传递返回值.
    • go并不使用这些调用规范(除非涉及到与原生代码交互), go有一套独自的调用规范. 所有参数都通过栈传递, 返回值也通过栈传递。go函数可以有多个返回值的原因也在于此. 因为返回值都通过栈传递了。
      汇编分析Go语言函数的调用

    相关文章

      网友评论

          本文标题:理解函数的调用过程

          本文链接:https://www.haomeiwen.com/subject/ployuktx.html