调用约定

传参测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func test10(a, b, c, d, e, f, g, h, i, j int) (
int, int, int, int, int,
int, int, int, int, int,
) {
fmt.Printf(
"Received parameters:\n"+
" a=%d b=%d c=%d d=%d e=%d\n"+
" f=%d g=%d h=%d i=%d j=%d\n",
a, b, c, d, e,
f, g, h, i, j,
)
return a + 1, b + 1, c + 1, d + 1, e + 1,
f + 1, g + 1, h + 1, i + 1, j + 1
}

编译为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
158 mov     [rsp+150h+var_150], 0Ah
158 mov eax, 1
158 mov ebx, 2
158 mov ecx, 3
158 mov edi, 4
158 mov esi, 5
158 mov r8d, 6
158 mov r9d, 7
158 mov r10d, 8
158 mov r11d, 9
158 call main_test10
158 mov [rsp+150h+var_C0], rbx
158 mov [rsp+150h+var_C8], rcx
158 mov [rsp+150h+var_D0], rdi
158 mov [rsp+150h+var_D8], rsi
158 mov [rsp+150h+var_E0], r8
158 mov [rsp+150h+var_E8], r9
158 mov [rsp+150h+var_F0], r10
158 mov [rsp+150h+var_F8], r11

同时函数内部最后:

1
2
3
4
5
6
7
8
9
10
11
130 mov     rcx, [rsp+128h+var_F0]
130 mov [rsp+128h+arg_8], rcx
130 mov rax, [rsp+128h+var_A8]
130 mov rbx, [rsp+128h+var_B0]
130 mov rcx, [rsp+128h+var_B8]
130 mov rdi, [rsp+128h+var_C0]
130 mov rsi, [rsp+128h+var_C8]
130 mov r8, [rsp+128h+var_D0]
130 mov r9, [rsp+128h+var_D8]
130 mov r10, [rsp+128h+var_E0]
130 mov r11, [rsp+128h+var_E8]

说明,golang的调用约定是rax,rbx,rcx,rdi,rsi,r8,r9,r10,r11,之后逆序压栈。返回值同理。

goruntine栈

goruntine是协程(用户态的线程),可以使用简单的语法来开一个新线程来执行内容

1
go func(){xxxxx}

协程的栈由goruntine分配和管理,当某线程开始执行某个函数时,函数开头会插入一段代码,来判断是否栈空间即将用完。相较于标准的C语言,它没有判断这种情况,如果真的遇到了,会直接报错。而Go在认为函数使用的栈会超过栈空间时,就会调用runtime_morestack_noctxt函数。

1
while ( SP <= g->stackguard )

上面是判断代码,g->stackguard是g结构体中的stackguard值,它是指向stack.lo + StackGuard的位置,它表明了安全阈值,如果SP比这个安全阈值小,它就会进行runtime_morestack_noctxt

网图,来自[深入研究goroutine栈 | 花木兰](https://s2.loli.net/2025/07/24/PHRT7sZm1o2Y89w.png)

runtime_morestack_noctxt函数做了以下几个操作:

  • 创建一个原本栈大小两倍的栈空间
  • 把原本栈的所有内容复制到新栈
  • 将新栈中所有和栈有关的指针地址都修改正确
  • 销毁原栈

其中,第三步的具体操作是和gc(垃圾回收)机制有关的。通过gc查询根节点当前存在的变量,即可知道其对应的指针,从而让gorutine更新指针信息。于此同时,编译器的逃逸分析(分析一个变量是否会离开某个函数栈帧)也可以起到作用,对于要逃逸的变量,一般分配在堆上,否则分配在栈上,记录后,对于堆上的指向栈的变量也就可以用类似的方法来修改。

参考文献

深入研究goroutine栈 | 花木兰

Goroutine是如何处理栈的? - Jiajun的技术笔记