理解函数的调用过程

一、函数的范围
二、函数的调用
      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语言函数的调用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容