调用约定
传参测试:
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是协程(用户态的线程),可以使用简单的语法来开一个新线程来执行内容
协程的栈由goruntine分配和管理,当某线程开始执行某个函数时,函数开头会插入一段代码,来判断是否栈空间即将用完。相较于标准的C语言,它没有判断这种情况,如果真的遇到了,会直接报错。而Go在认为函数使用的栈会超过栈空间时,就会调用runtime_morestack_noctxt函数。
1
| while ( SP <= g->stackguard )
|
上面是判断代码,g->stackguard是g结构体中的stackguard值,它是指向stack.lo + StackGuard的位置,它表明了安全阈值,如果SP比这个安全阈值小,它就会进行runtime_morestack_noctxt
](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
runtime_morestack_noctxt函数做了以下几个操作:
- 创建一个原本栈大小两倍的栈空间
- 把原本栈的所有内容复制到新栈
- 将新栈中所有和栈有关的指针地址都修改正确
- 销毁原栈
其中,第三步的具体操作是和gc(垃圾回收)机制有关的。通过gc查询根节点当前存在的变量,即可知道其对应的指针,从而让gorutine更新指针信息。于此同时,编译器的逃逸分析(分析一个变量是否会离开某个函数栈帧)也可以起到作用,对于要逃逸的变量,一般分配在堆上,否则分配在栈上,记录后,对于堆上的指向栈的变量也就可以用类似的方法来修改。
参考文献
深入研究goroutine栈 | 花木兰
Goroutine是如何处理栈的? - Jiajun的技术笔记