Go函数调用Redux

前段时间在以前的帖子我答应带在功能围棋是如何工作的调用和调用堆栈进一步看看。 我认为找到了一种很好的方法来兑现这一诺言,所以去吧。

那么什么是调用栈? 好吧,这是一个内存区域,用于保存局部变量和调用参数,并跟踪函数应返回的位置。 每个goroutine都有自己的堆栈。 您几乎可以说goroutine是它的堆栈。

这是我将用来显示实际堆栈的代码。 这只是一系列简单的函数调用。 main()调用f1(0xdeadbeef) ,然后调用f2(0xabad1dea),后者调用f3(0xbaddcafe)。 然后f3()向其参数添加一个,并将其存储在称为local的局部变量中。 然后,它获取本地地址并从该地址开始打印出内存。 由于本地在堆栈上,因此将打印堆栈。

这是程序的输出。 它是从本地地址开始的内存转储,显示为十六进制的8字节整数列表。 每个整数的地址在左侧,而该地址的int在右侧。

我们知道local应该等于0xBADDCAFE + 1或0xBADDCAFF,这确实是我们在转储开始时看到的。

C42003FF28: BADDCAFF C42003FF30: C42003FF48 C42003FF38: 1088BEB C42003FF40: BADDCAFE C42003FF48: C42003FF60 C42003FF50: 1088BAB C42003FF58: ABAD1DEA C42003FF60: C42003FF78 C42003FF68: 1088B6B C42003FF70: DEADBEEF C42003FF78: C42003FFD0 C42003FF80: 102752A C42003FF88: C420064000 C42003FF90: 0 C42003FF98: C420064000 C42003FFA0: 0 C42003FFA8: 0 C42003FFB0: 0 C42003FFB8: 0 C42003FFC0: C4200001A0 1088BEB is main.f2 /Users/phil/go/src/github.com/philpearl/stack/main.go 19 1088BAB is main.f1 /Users/phil/go/src/github.com/philpearl/stack/main.go 15 1088B6B is main.main /Users/phil/go/src/github.com/philpearl/stack/main.go 11 102752A is runtime.main /usr/local/Cellar/go/1.8/libexec/src/runtime/proc.go 194
  • 下一个数字是0xC42003FF48,它是转储的第5行的地址。
  • 之后,我们有0x1088BEB。 事实证明,这是可执行代码的地址,如果将其提供给运行时。FuncForPC,我们会看到它是main.go第19行的地址,这是f2()的最后一行。 这是f3()返回时我们返回的地址。
  • 接下来,我们有0xBADDCAFE,这是我们调用f3()的参数

如果我们继续下去,我们将继续看到这种模式。 在下面,我标记了内存转储,显示了堆栈指针如何在转储中回溯以及函数参数和返回地址位于何处。

C42003FF28: BADDCAFF Local variable in f3() +-C42003FF30: C42003FF48 | C42003FF38: 1088BEB return to f2() main.go line 19 | C42003FF40: BADDCAFE f3() parameter +-C42003FF48: C42003FF60 | C42003FF50: 1088BAB return to f1() main.go line 15 | C42003FF58: ABAD1DEA f2() parameter +-C42003FF60: C42003FF78 | C42003FF68: 1088B6B return to main() main.go line 11 | C42003FF70: DEADBEEF f1() parameter +-C42003FF78: C42003FFD0 C42003FF80: 102752A return to runtime.main()

从中我们可以看到很多事情。

  • 首先,堆栈从高位地址开始,并且随着函数调用的进行,堆栈地址减少。
  • 进行函数调用时,调用者将参数压入堆栈,然后是返回地址(调用函数中下一条指令的地址),然后是指向堆栈中较高点的指针。
  • 当调用返回时展开堆栈时,该指针用于在堆栈上查找上一个函数调用。
  • 局部变量存储在堆栈指针之后。

我们可以使用相同的技术来查看一些稍微复杂的函数调用。 在此版本中,我添加了更多参数和一些返回值到f2()。

这次我直接跳到标记输出。

C42003FF10: BADDCAFF local variable in f3() +-C42003FF18: C42003FF30 | C42003FF20: 1088BFB return to f2() | C42003FF28: BADDCAFE f3() parameter +-C42003FF30: C42003FF60 | C42003FF38: 1088BBF return to f1() | C42003FF40: ABAD1DEA0001 f2() first parameter | C42003FF48: ABAD1DEA0002 f2() second parameter | C42003FF50: 110A100 space for f2() return value | C42003FF58: C42000E240 space for f2() return value +-C42003FF60: C42003FF78 | C42003FF68: 1088B6B return to main() | C42003FF70: DEADBEEF f1() parameter +-C42003FF78: C42003FFD0 C42003FF80: 102752A return to runtime.main()

由此我们可以看到

  • 调用函数在函数参数之前为被调用函数的返回值留出空间。 (请注意,这些值尚未初始化,因为该函数尚未返回!)
  • 参数以相反顺序推入堆栈。

希望所有这些都有意义! 如果您走到了这一步并且喜欢它或学到了一些东西,请按一下那颗心。 没有您,我无法赚取互联网积分。

白天,菲尔在 ravelin.com 打击犯罪 您可以加入他: https //angel.co/ravelin/jobs

From: https://hackernoon.com/go-function-calls-redux-609fdd1c90fd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值