分享
  1. 首页
  2. 文章

Golang协程栈概述

丁凯 · · 2864 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

说明

计算机中的栈一个很大的应用场合使用在函数调用中。我们这里简单说说golang的协程栈布局,学过计算机的应该都不会陌生。

程序事例

package main
func f(a, b int) int {
 sum := 0
 sum = a + b
 for i := 0; i < 1000; i++ {
 println("sum is:", sum)
 }
 return sum
}
func main() {
 f(1, 2)
}

汇编代码

(gdb) disas
Dump of assembler code for function main.main:
0x00000000004010b0 <main.main+0>: mov %fs:0xfffffffffffffff8,%rcx
0x00000000004010b9 <main.main+9>: cmp 0x10(%rcx),%rsp
0x00000000004010bd <main.main+13>: jbe 0x4010de <main.main+46>
0x00000000004010bf <main.main+15>: sub 0ドルx18,%rsp
0x00000000004010c3 <main.main+19>: movq 0ドルx1,(%rsp)
0x00000000004010cb <main.main+27>: movq 0ドルx2,0x8(%rsp)
0x00000000004010d4 <main.main+36>: callq 0x401000 <main.f>
0x00000000004010d9 <main.main+41>: add 0ドルx18,%rsp
0x00000000004010dd <main.main+45>: retq
0x00000000004010de <main.main+46>: callq 0x44abd0 <runtime.morestack_noctxt>
0x00000000004010e3 <main.main+51>: jmp 0x4010b0 <main.main>
0x00000000004010e5 <main.main+53>: add %al,(%rax)
0x00000000004010e7 <main.main+55>: add %al,(%rax)
0x00000000004010e9 <main.main+57>: add %al,(%rax)
0x00000000004010eb <main.main+59>: add %al,(%rax)
0x00000000004010ed <main.main+61>: add %al,(%rax)
0x00000000004010ef <main.main+63>: add %ah,-0x75(%rax,%rcx,2)
End of assembler dump.
(gdb) disas
Dump of assembler code for function main.f:
0x0000000000401000 <main.f+0>: mov %fs:0xfffffffffffffff8,%rcx
0x0000000000401009 <main.f+9>: cmp 0x10(%rcx),%rsp
0x000000000040100d <main.f+13>: jbe 0x401097 <main.f+151>
0x0000000000401013 <main.f+19>: sub 0ドルx20,%rsp
0x0000000000401017 <main.f+23>: mov 0x28(%rsp),%rbx
0x000000000040101c <main.f+28>: mov 0x30(%rsp),%rbp
0x0000000000401021 <main.f+33>: add %rbp,%rbx
0x0000000000401024 <main.f+36>: mov %rbx,0x10(%rsp)
0x0000000000401029 <main.f+41>: xor %eax,%eax
0x000000000040102b <main.f+43>: mov %rax,0x18(%rsp)
0x0000000000401030 <main.f+48>: cmp 0ドルx3e8,%rax
0x0000000000401036 <main.f+54>: jge 0x401088 <main.f+136>
......
0x0000000000401088 <main.f+136>: mov 0x10(%rsp),%rbx
0x000000000040108d <main.f+141>: mov %rbx,0x38(%rsp)
0x0000000000401092 <main.f+146>: add 0ドルx20,%rsp

执行过程中stack变化情况

在main调用f()时,协程堆栈情况:

注意:这里的返回地址是由call指令自动push至esp所指向内存,而参数内容则是由调用者main函数设置的,如下代码:

// we have 2 argument and 1 return value
// so must reserve 24 bytes in amd64(0x18)
0x00000000004010bf <main.main+15>: sub 0ドルx18,%rsp
0x00000000004010c3 <main.main+19>: movq 0ドルx1,(%rsp)
0x00000000004010cb <main.main+27>: movq 0ドルx2,0x8(%rsp)
0x00000000004010d4 <main.main+36>: callq 0x401000 <main.f>

在f函数内部执行时,会扩充当前stack,为了临时存储一些本地变量,如sum等,则f执行时堆栈情况如下:

可以看到为本地变量sum和i自动在栈上分配了存储空间,计算sum,然后将sum的值存储到f()返回值该去的地方((esp) + 0x38)

可以简单看看main.f()的主要汇编代码

// sub esp to allocate space for local variable
0x0000000000401013 <main.f+19>: sub 0ドルx20,%rsp
// get parameters, compute and store sum 
0x0000000000401017 <main.f+23>: mov 0x28(%rsp),%rbx
0x000000000040101c <main.f+28>: mov 0x30(%rsp),%rbp
0x0000000000401021 <main.f+33>: add %rbp,%rbx
// store sum in (esp) + 0x10
0x0000000000401024 <main.f+36>: mov %rbx,0x10(%rsp)
// for loop assemble code
0x0000000000401029 <main.f+41>: xor %eax,%eax
0x000000000040102b <main.f+43>: mov %rax,0x18(%rsp)
0x0000000000401030 <main.f+48>: cmp 0ドルx3e8,%rax
0x0000000000401036 <main.f+54>: jge 0x401088 <main.f+136>
......
// store sum into return value address(esp + 0x38)
// and shrink stack((%esp) + 0x20) and return to main 
0x0000000000401088 <main.f+136>: mov 0x10(%rsp),%rbx
0x000000000040108d <main.f+141>: mov %rbx,0x38(%rsp)
0x0000000000401092 <main.f+146>: add 0ドルx20,%rsp

参考资料

http://www.cs.nyu.edu/courses/fall04/V22.0201-003/ia32_chap_03.pdf

有疑问加站长微信联系(非本文作者)

本文来自:知乎专栏

感谢作者:丁凯

查看原文:Golang协程栈概述

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
2864 次点击
被以下专栏收入,发现更多相似内容
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏