首页 > 其他分享 >golang 多返回值的实现原理-转载

golang 多返回值的实现原理-转载

时间:2024-03-20 23:34:30浏览次数:23  
标签:函数 esp golang ebp 寄存器 返回值 转载 指针

之前一次面试时,面试官问到 你知道golang的多返回值的实现吗,一脸懵逼,平时主要注重项目应用开发,对这块确实没关注,答得不好,各位大佬,以后建议也加强下基础哦。

今天看看 golang 中多返回值的实现。

可以简单认为 c 中多返回值的实现,其实就是通过寄存器将返回参数以指针形式传入传入参数中,我们知道通过指针是保留一份数据的,实际的数据备份就只有一份,不管是否通过地址复制,实际内容就在那。

而 golang 不同。

栈帧

栈帧结构的两端由两个指针来指定。寄存器ebp通常用做帧指针(frame pointer),而esp则用作栈指针(stack pointer)。在函数执行过程中,栈指针esp会随着数据的入栈和出栈而移动,因此函数中对大部分数据的访问都基于帧指针ebp进行。

esp和ebp: esp是栈指针,是cpu机制决定的,push、pop指令会自动调整esp的值;ebp只是存取某时刻的esp,这个时刻就是进入一个函数内后,cpu会将esp的值赋给ebp,此时就可以通过ebp对栈进行操作,比如获取函数参数,局部变量等,实际上使用esp也可以;

  • EBP:基址指针寄存器(extended base pointer),存放一个指针,永远指向系统栈最上面一个栈帧的底部

  • ESP:栈指针寄存器(extended stack pointer),存放一个指针,永远指向系统栈最上面一个栈帧的栈顶

  • EAX 寄存器也叫做累加寄存器,用于存储函数的返回值外也用于执行计算的 操作。

调用函数中push ebp,将main函数的ebp压栈,然后mov ebp, esp将当前函数的esp赋给ebp,得到当前函数的栈底地址。

//函数调用之所以能够返回,单靠保持返回地址是不够的,这一步压栈动作很重要,
//因为我们要标记函数调用者栈帧的帧底,这样才能找出保存了的返回地址,
//栈顶是不用保存的,因为上一个栈帧的顶部会是func的栈帧底部。(两栈帧相邻的)
push ebp; 

//mov指令将esp寄存器的值赋值给ebp寄存器。上一栈帧的顶部,就是这个栈帧的底部
mov ebp, esp; 

调用函数结束之前,执行leave指令,其实该指令等于下面两条指令:此时fun相关数据全部被出栈,ebp将得重新到main函数的栈底地址,esp回到函数栈顶部.

mov esp, ebp //mov 将ebp的值 赋值给esp
pop ebp  //将堆栈中的ebp值弹出

go汇编中有4个伪寄存器

分别是:

  • FP: Frame pointer,指向栈底位置,一般用来引用函数的输入参数,用来访问函数的参数
  • PC: Program counter: 程序计数器,用于分支和跳转
  • SB: Static base pointer: 一般用于声明函数或者全局变量
  • SP: Stack pointer:指向当前栈帧的局部变量的开始位置(栈顶位置),一般用来引用函数的局部变量

在 C 语言中调用一个函数,函数的参数是通过寄存器和栈传递的,在 x86_64 的机器上,6 个以下(含 6 个)的参数会按照顺序分别使用 edi、esi、edx、ecx、r8d 和 r9d 六个寄存器传递,超过 6 个的剩余参数会通过栈进行传递;函数的返回值是通过 eax 寄存器进行传递的,这也就是为什么 C 语言中不支持多个返回值。

Golang 函数参数以及返回值都是通过SP来保存的,那么也就是说是通过堆栈寄存器来保存的。所以可以做到返回多个,因为它跟参数传递使用的都是堆栈。golang的返回参数是放在栈里面的,把返回值的地址存放到栈中,golang函数调用过程,是通过fp+offset来实现传参和返回值,而不像C/C++都是通过寄存器实现传参和返回值。 所以golang能够支持多个参数返回。

+-----------+---\
| 返回值2 | \
+-----------+  \
| 返回值1 |  \
+---------+-+  
| 参数2 |  这些在调用函数中
+-----------+  
| 参数1 |   /
+-----------+  /
| 返回地址 | /
+-----------+--\/-----fp值
| 局部变量 | \
| ... | 被调用数栈祯
|   | /
+-----------+--/+---sp值

原文链接:https://blog.csdn.net/u014618114/article/details/119361688

标签:函数,esp,golang,ebp,寄存器,返回值,转载,指针
From: https://www.cnblogs.com/davis12/p/18086377

相关文章

  • golang vs python 应用项目语言选择
    目录1.语言选择2.python语言特点及应用场景2.1语言特点1.简单2.易于学习3.自由且开放4.丰富的库5.互动模式6.跨平台性7.可扩展8.数据库9.可嵌入10.高级语言2.2应用场景Python在系统编程中的应用Python在网络爬虫方面的应用Python在人工智能、科学计算中的应用Python在WEB开发中......
  • 游戏汉化时使用的像素字体(转载)
    原文链接https://zhuanlan.zhihu.com/p/573922877警告:我想你应该知道大多数字体需要商业授权。如果是商业汉化需要使用像素字体,请注意对应字体授权范围和商用条件。很多中文像素字体溯源困难,本文中列举的授权情况基本为推断,不代表实际情况。稍微介绍一下一般游戏汉化时使用的。......
  • golang 运行时死锁排查和检测
    当运行的系统发生goroutine等待获取锁时间超过预期时,判定为发生了死锁。因目前代码中使用了一些公开的锁实例,调用链也比较长,对问题排查带来了很大困扰。为了便于问题排查,需要借助工具来实现。1.发生死锁的判定依据和原因1.1判定依据如下为使用Mutex锁产生的锁等待,并持续了2......
  • C++ 重载运算符返回值问题
    事实上,我们的重载运算符返回void、返回对象本身、返回对象引用都是可以的,并不是说一定要返回一个引用,只不过在不同的情况下需要不同的返回值。那么什么情况下要返回对象的引用呢?原因有两个:允许进行连续赋值;防止返回对象(返回对象也可以进行连续赋值(常规的情况,如a=b=c,而不......
  • golang实现数据分组
    背景:从数据库里查出了532条数据,这532条数据需要通过一个接口过滤符合条件的,由于过滤比较流程长,过滤接口避免超时,只允许一次请求100条,于是我们就需要针对这个532条数据进行分组。思路:就是把这个数据分成6组,前5组是100条,第6组是32条。max=532/100取整,532%100不等于零max+1,创建一个......
  • 如何画好一张架构图? 转载
    ......
  • C++ 返回值优化
    1.函数返回机制函数返回值的传递分为两种情况:当返回的对象大小不超过8字节时,通过寄存器(eaxedx)返回。当返回的对象大小大于8字节时,通过栈返回。此处需要注意的时候,如果返回的是struct或者class对象,即使其大小不大于8字节,也是通过栈返回的。在通过栈返回的时候,栈上会有一块......
  • golang sync.Map之如何设计一个并发安全的读写分离结构?
    在golang中,想要并发安全的操作map,可以使用sync.Map结构,sync.Map是一个适合读多写少的数据结构,今天我们来看看它的设计思想,来看看为什么说它适合读多写少的场景。如下,是golang中sync.Map的数据结构,其中属性read是只读的map,dirty是负责写入的map,sync.Map中的键值对value......
  • Mysql带返回值与不带返回值的2种存储过程
    时间:2018-03-3000:25:57过程1:带返回值:dropprocedureifexistsproc_addNum;createprocedureproc_addNum(inxint,inyint,outsumint)BEGINSETsum=x+y;end然后,执行过程,out输出返回值:callproc_addNum(2,3,@sum);select@sum;过程2:不带返回值:dropp......
  • Golang案例开发之gopacket监听网卡抓包(2)
    文章目录前言二、实践监听网卡抓包1.代码2.知识点OpenLive方法SetBPFFilter断言总结前言本节实战,监听指定网卡,进行网络抓包,根据分层,解析不同分层包的内容。二、实践监听网卡抓包1.代码代码如下(示例):packagemainimport( "fmt" "log" "......