分享
  1. 首页
  2. 文章

Golang内置函数和过程调用汇编代码分析

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

Golang汇编快速指南这篇博客中,简单介绍了Golang中汇编的简单语法以及特殊之处。下面介绍Golang中的内置函数和相关操作代码的汇编实现,可以作为上篇博客的补充和实践。

汇编中过程调用的参数是通过栈来传递的,在栈上的布局如下:

参数3
参数2
参数1 <-fp 保存PC <-sp ... ... 

内置函数: new, make, append

package main
import (
 "fmt"
)
type new_int int
var (
 gobal_1 = "this is global var"
)
func main() {
 auto_1 := "this is auto_1"
 s0 := new(new_int)
 s1 := make([]int, 10)
 s2 := make([]int, 10)
 append(s2, 9999)
 fmt.Println(s1, s2)
 fmt.Println(s0)
}

下面是汇编代码:

"".main t=1 size=1936 value=0 args=0x0 locals=0x128
 // 定义函数main,栈帧大小为296字节,0字节的参数(无参数)
 0x0000 00000 (builtin.go:13) TEXT "".main+0(SB),296ドル-0
 // 将线程本地存储(thread local storage)传送到CX
 0x0000 00000 (builtin.go:13) MOVQ (TLS),CX
 // 下面是检查栈帧的大小是否超过目前分配的小
 0x0009 00009 (builtin.go:13) LEAQ -168(SP),AX
 0x0011 00017 (builtin.go:13) CMPQ AX,16(CX)
 0x0015 00021 (builtin.go:13) JHI ,30
 // 如果超过调用runtime.morestack_noctxt
 0x0017 00023 (builtin.go:13) CALL ,runtime.morestack_noctxt(SB)
 0x001c 00028 (builtin.go:13) JMP ,0
 // 扩大栈帧
 0x001e 00030 (builtin.go:13) SUBQ 296,ドルSP
 0x0025 00037 (builtin.go:13) FUNCDATA 0,ドルgclocals·e14c7473fe07b0ccdc0fdfa1a770087b+0(SB)
 0x0025 00037 (builtin.go:13) FUNCDATA 1,ドルgclocals·7a70fcb413ec620f2a7a8c3ba5f394c1+0(SB)
 // 局部变量auto_1
 0x0025 00037 (builtin.go:14) LEAQ go.string."this is auto_1"+0(SB),BX
 // string在golang中是由数据本身和其长度组成的
 // 将数据的地址移动到BP
 0x002c 00044 (builtin.go:14) MOVQ (BX),BP
 // 移动BP到栈指针152字节的位置
 0x002f 00047 (builtin.go:14) MOVQ BP,"".auto_1+152(SP)
 // 将字符串长度移动到BP
 0x0037 00055 (builtin.go:14) MOVQ 8(BX),BP
 // 移动BP到栈指针160字节的位置
 0x003b 00059 (builtin.go:14) MOVQ BP,"".auto_1+160(SP)
 // new_int类型的初始化
 // 将类型本身移动到BX
 0x0043 00067 (builtin.go:17) MOVQ $type."".new_int+0(SB),BX
 // 将BX移动到栈顶
 0x004a 00074 (builtin.go:17) MOVQ BX,(SP)
 0x004e 00078 (builtin.go:17) PCDATA 0,ドル1ドル
 // 调用runtime.newobject
 0x004e 00078 (builtin.go:17) CALL ,runtime.newobject(SB)
 // 将返回的结果移动到BX
 0x0053 00083 (builtin.go:17) MOVQ 8(SP),BX
 // 移动BP到栈指针80字节的位置
 0x0058 00088 (builtin.go:17) MOVQ BX,"".s1+80(SP)
 0x005d 00093 (builtin.go:17) NOP ,
 // 创建slice s1
 // 将类型移动到BX
 0x005d 00093 (builtin.go:18) MOVQ $type.[]int+0(SB),BX
 // 将BX(类型)移动到栈顶
 0x0064 00100 (builtin.go:18) MOVQ BX,(SP)
 // 将长度参数len移动到相对于栈顶8字节的位置
 0x0068 00104 (builtin.go:18) MOVQ 10,8ドル(SP)
 // 将容量参数cap移动到相对于栈顶16字节的位置
 0x0071 00113 (builtin.go:18) MOVQ 10,16ドル(SP)
 0x007a 00122 (builtin.go:18) PCDATA 0,ドル2ドル
 // 调用runtime.makeslice
 0x007a 00122 (builtin.go:18) CALL ,runtime.makeslice(SB)
 // 创建出的s1的参数分别保存在相对栈顶24, 32, 40字节的位置
 0x007f 00127 (builtin.go:18) MOVQ 24(SP),DX
 0x0084 00132 (builtin.go:18) MOVQ 32(SP),CX
 0x0089 00137 (builtin.go:18) MOVQ 40(SP),BX
 // CX中保存的是slice的len参数
 0x008e 00142 (builtin.go:20) MOVQ CX,"".s2_len+64(SP)
 0x0093 00147 (builtin.go:20) NOP ,
 // 将slice的array, len, cap传送给s2
 0x0093 00147 (builtin.go:21) MOVQ DX,"".s2+168(SP)
 0x009b 00155 (builtin.go:21) MOVQ CX,"".s2+176(SP)
 0x00a3 00163 (builtin.go:21) MOVQ BX,"".s2+184(SP)
 0x00ab 00171 (builtin.go:21) MOVQ BX,AX
 // 从BX中减去CX的值,结果保存在BX
 0x00ae 00174 (builtin.go:21) SUBQ CX,BX
 0x00b1 00177 (builtin.go:21) CMPQ BX,1ドル
 0x00b5 00181 (builtin.go:21) JGE ,262
 // 将类型传送到栈顶
 0x00b7 00183 (builtin.go:21) MOVQ $type.[]int+0(SB),BX
 0x00be 00190 (builtin.go:21) MOVQ BX,(SP)
 // 将旧的slice传送到栈的第二个参数
 0x00c2 00194 (builtin.go:21) MOVQ DX,"".autotmp_0001+240(SP)
 0x00ca 00202 (builtin.go:21) MOVQ DX,8(SP)
 // 将长度传送到栈上第三个参数(s2的长度)
 0x00cf 00207 (builtin.go:21) MOVQ CX,"".autotmp_0001+248(SP)
 0x00d7 00215 (builtin.go:21) MOVQ CX,16(SP)
 // 将33行的BX的值重新保存到24(SP),即s2的array
 0x00dc 00220 (builtin.go:21) MOVQ AX,"".autotmp_0001+256(SP)
 0x00e4 00228 (builtin.go:21) MOVQ AX,24(SP)
 // 将s2的长度置为1
 0x00e9 00233 (builtin.go:21) MOVQ 1,32ドル(SP)
 // 调用growslice
 0x00f2 00242 (builtin.go:21) PCDATA 0,ドル2ドル
 0x00f2 00242 (builtin.go:21) CALL ,runtime.growslice(SB)
 // 3个返回值(sliceStruct)
 0x00f7 00247 (builtin.go:21) MOVQ 40(SP),DX
 0x00fc 00252 (builtin.go:21) MOVQ 48(SP),CX
 0x0101 00257 (builtin.go:21) MOVQ 56(SP),AX
 // 增加返回的结构中len参数长度,增加1
 0x0106 00262 (builtin.go:21) MOVQ CX,SI
 0x0109 00265 (builtin.go:21) INCQ ,SI
 // 变址寻址,DX+CX*8
 0x010c 00268 (builtin.go:21) LEAQ (DX)(CX*8),BX
 // 将立即数9999传递到(BX)的内存位置
 0x0110 00272 (builtin.go:21) MOVQ 9999,ドル(BX)
 0x0117 00279 (builtin.go:21) NOP ,
 0x0117 00279 (builtin.go:21) MOVQ DX,"".autotmp_0001+240(SP)
 0x011f 00287 (builtin.go:21) MOVQ SI,"".autotmp_0001+248(SP)
 0x0127 00295 (builtin.go:21) MOVQ AX,"".autotmp_0001+256(SP)
 // 将新的slice的参数传递给s2
 0x012f 00303 (builtin.go:21) MOVQ DX,"".s2+168(SP)
 0x0137 00311 (builtin.go:21) MOVQ SI,"".s2+176(SP)
 0x013f 00319 (builtin.go:21) MOVQ AX,"".s2+184(SP)
 0x0147 00327 (builtin.go:21) NOP ,

内置函数: copy

package main
import (
 "fmt"
)
func main() {
 s1 := make([]int, 10)
 s2 := make([]int, 10)
 copy(s1, s2)
 fmt.Println(s1, s2)
}

下面是汇编代码:

"".main t=1 size=624 value=0 args=0x0 locals=0x108
 0x0000 00000 (builtin.go:7) TEXT "".main+0(SB),264ドル-0
 0x0000 00000 (builtin.go:7) MOVQ (TLS),CX
 0x0009 00009 (builtin.go:7) LEAQ -136(SP),AX
 0x0011 00017 (builtin.go:7) CMPQ AX,16(CX)
 0x0015 00021 (builtin.go:7) JHI ,30
 0x0017 00023 (builtin.go:7) CALL ,runtime.morestack_noctxt(SB)
 0x001c 00028 (builtin.go:7) JMP ,0
 0x001e 00030 (builtin.go:7) SUBQ 264,ドルSP
 0x0025 00037 (builtin.go:7) FUNCDATA 0,ドルgclocals·7c13896baab3273e10662a9a37b348ce+0(SB)
 0x0025 00037 (builtin.go:7) FUNCDATA 1,ドルgclocals·978d33e7717760c8870a69548dc9a2fb+0(SB)
 // 创建切片s1
 0x0025 00037 (builtin.go:8) MOVQ $type.[]int+0(SB),BX
 0x002c 00044 (builtin.go:8) MOVQ BX,(SP)
 0x0030 00048 (builtin.go:8) MOVQ 10,8ドル(SP)
 0x0039 00057 (builtin.go:8) MOVQ 10,16ドル(SP)
 0x0042 00066 (builtin.go:8) PCDATA 0,ドル0ドル
 0x0042 00066 (builtin.go:8) CALL ,runtime.makeslice(SB)
 0x0047 00071 (builtin.go:8) MOVQ 24(SP),DX
 0x004c 00076 (builtin.go:8) MOVQ 32(SP),CX
 0x0051 00081 (builtin.go:8) MOVQ 40(SP),AX
 0x0056 00086 (builtin.go:8) MOVQ DX,"".s1+88(SP)
 0x005b 00091 (builtin.go:8) MOVQ CX,"".s1+96(SP)
 0x0060 00096 (builtin.go:8) MOVQ AX,"".s1+104(SP)
 // 创建切片s2
 0x0065 00101 (builtin.go:9) MOVQ $type.[]int+0(SB),BX
 0x006c 00108 (builtin.go:9) MOVQ BX,(SP)
 0x0070 00112 (builtin.go:9) MOVQ 10,8ドル(SP)
 0x0079 00121 (builtin.go:9) MOVQ 10,16ドル(SP)
 0x0082 00130 (builtin.go:9) PCDATA 0,ドル1ドル
 0x0082 00130 (builtin.go:9) CALL ,runtime.makeslice(SB)
 0x0087 00135 (builtin.go:9) MOVQ 24(SP),DX
 0x008c 00140 (builtin.go:9) MOVQ 32(SP),CX
 0x0091 00145 (builtin.go:9) MOVQ 40(SP),AX
 // 将s1的数据保存到SI, BP, BX
 0x0096 00150 (builtin.go:11) MOVQ "".s1+88(SP),SI
 0x009b 00155 (builtin.go:11) MOVQ "".s1+96(SP),BP
 0x00a0 00160 (builtin.go:11) MOVQ "".s1+104(SP),BX
 // 将BX保存到224(SP)
 0x00a5 00165 (builtin.go:11) MOVQ BX,"".autotmp_0005+224(SP)
 // 将s2的数据保存到栈上
 0x00ad 00173 (builtin.go:11) MOVQ DX,"".s2+64(SP)
 0x00b2 00178 (builtin.go:11) MOVQ CX,"".s2+72(SP)
 0x00b7 00183 (builtin.go:11) MOVQ AX,"".s2+80(SP)
 // 将AX保存到152(SP)
 0x00bc 00188 (builtin.go:11) MOVQ AX,"".autotmp_0006+152(SP)
 // 将BP保存到216(SP)
 0x00c4 00196 (builtin.go:11) MOVQ BP,"".autotmp_0000+216(SP)
 // 从204到220是比较s1和s2的长度
 // 哪个比较大就用它作为参数
 // 复制BP到AX, BP保存的是s1的len
 0x00cc 00204 (builtin.go:11) MOVQ BP,AX
 // 将CX保存到144(SP)
 0x00cf 00207 (builtin.go:11) MOVQ CX,"".autotmp_0006+144(SP)
 // 比较s2的长度(CX)和s1的长度(BP)
 // 如果小于0则跳转到223
 // 否则执行220
 0x00d7 00215 (builtin.go:11) CMPQ CX,BP
 0x00da 00218 (builtin.go:11) JGE ,223
 0x00dc 00220 (builtin.go:11) MOVQ CX,AX
 
 // 将s1的array作为第一个参数
 0x00df 00223 (builtin.go:11) MOVQ SI,"".autotmp_0000+208(SP)
 0x00e7 00231 (builtin.go:11) MOVQ SI,(SP)
 // 将s2的array作为第二个参数
 0x00eb 00235 (builtin.go:11) MOVQ DX,"".autotmp_0006+136(SP)
 0x00f3 00243 (builtin.go:11) MOVQ DX,8(SP)
 // AX中保存的是s2的长度
 0x00f8 00248 (builtin.go:11) MOVQ AX,BX
 // shl 左移位操作, 左移3位
 0x00fb 00251 (builtin.go:11) SHLQ 3,ドルBX
 // 将BX作为第三个参数
 0x00ff 00255 (builtin.go:11) MOVQ BX,16(SP)
 0x0104 00260 (builtin.go:11) PCDATA 0,ドル2ドル
 0x0104 00260 (builtin.go:11) CALL ,runtime.memmove(SB)

函数调用

package main
import (
 "fmt"
)
func f1(a int) int {
 fmt.Println(a)
 return a + 123
}
func main() {
 b := f1(123)
 fmt.Println(b)
}

下面是汇编代码:

"".f1 t=1 size=240 value=0 args=0x10 locals=0x70
 0x0000 00000 (builtin.3.go:7) TEXT "".f1+0(SB),112ドル-16
 0x0000 00000 (builtin.3.go:7) MOVQ (TLS),CX
 0x0009 00009 (builtin.3.go:7) CMPQ SP,16(CX)
 0x000d 00013 (builtin.3.go:7) JHI ,22
 0x000f 00015 (builtin.3.go:7) CALL ,runtime.morestack_noctxt(SB)
 0x0014 00020 (builtin.3.go:7) JMP ,0
 0x0016 00022 (builtin.3.go:7) SUBQ 112,ドルSP
 0x001a 00026 (builtin.3.go:7) FUNCDATA 0,ドルgclocals·480b8f52e76ecc554a5236babfd9a6e5+0(SB)
 0x001a 00026 (builtin.3.go:7) FUNCDATA 1,ドルgclocals·403a8d79fd24b295e8557f6970497aa3+0(SB)
 // 因为栈帧的大小是112字节
 // 所以在120(FP)处保存的是第一个参数
 0x001a 00026 (builtin.3.go:8) MOVQ "".a+120(FP),BX
 // 下面的代码将a转换为接口类型
 // 因为fmt.Println需要的是空接口类型的参数
 0x001f 00031 (builtin.3.go:8) MOVQ BX,"".autotmp_0001+48(SP)
 0x0024 00036 (builtin.3.go:8) LEAQ "".autotmp_0000+72(SP),BX
 0x0029 00041 (builtin.3.go:8) MOVQ 0,ドル(BX)
 0x0030 00048 (builtin.3.go:8) MOVQ 0,8ドル(BX)
 0x0038 00056 (builtin.3.go:8) LEAQ "".autotmp_0000+72(SP),BX
 0x003d 00061 (builtin.3.go:8) CMPQ BX,0ドル
 0x0041 00065 (builtin.3.go:8) JEQ 1,226ドル
 0x0047 00071 (builtin.3.go:8) MOVQ 1,ドルDX
 0x004e 00078 (builtin.3.go:8) MOVQ 1,ドルCX
 0x0055 00085 (builtin.3.go:8) MOVQ BX,"".autotmp_0002+88(SP)
 0x005a 00090 (builtin.3.go:8) MOVQ DX,"".autotmp_0002+96(SP)
 0x005f 00095 (builtin.3.go:8) MOVQ CX,"".autotmp_0002+104(SP)
 0x0064 00100 (builtin.3.go:8) MOVQ $type.int+0(SB),BX
 0x006b 00107 (builtin.3.go:8) MOVQ BX,(SP)
 0x006f 00111 (builtin.3.go:8) LEAQ "".autotmp_0001+48(SP),BX
 0x0074 00116 (builtin.3.go:8) MOVQ BX,8(SP)
 0x0079 00121 (builtin.3.go:8) PCDATA 0,ドル1ドル
 0x0079 00121 (builtin.3.go:8) CALL ,runtime.convT2E(SB)
 0x007e 00126 (builtin.3.go:8) MOVQ 16(SP),CX
 0x0083 00131 (builtin.3.go:8) MOVQ 24(SP),AX
 0x0088 00136 (builtin.3.go:8) MOVQ "".autotmp_0002+88(SP),BX
 0x008d 00141 (builtin.3.go:8) MOVQ BX,(SP)
 0x0091 00145 (builtin.3.go:8) MOVQ CX,"".autotmp_0004+56(SP)
 0x0096 00150 (builtin.3.go:8) MOVQ CX,8(SP)
 0x009b 00155 (builtin.3.go:8) MOVQ AX,"".autotmp_0004+64(SP)
 0x00a0 00160 (builtin.3.go:8) MOVQ AX,16(SP)
 0x00a5 00165 (builtin.3.go:8) PCDATA 0,ドル1ドル
 0x00a5 00165 (builtin.3.go:8) CALL ,runtime.writebarrieriface(SB)
 // 传递参数给fmt.Println,并调用
 0x00aa 00170 (builtin.3.go:8) MOVQ "".autotmp_0002+88(SP),BX
 0x00af 00175 (builtin.3.go:8) MOVQ BX,(SP)
 0x00b3 00179 (builtin.3.go:8) MOVQ "".autotmp_0002+96(SP),BX
 0x00b8 00184 (builtin.3.go:8) MOVQ BX,8(SP)
 0x00bd 00189 (builtin.3.go:8) MOVQ "".autotmp_0002+104(SP),BX
 0x00c2 00194 (builtin.3.go:8) MOVQ BX,16(SP)
 0x00c7 00199 (builtin.3.go:8) PCDATA 0,ドル2ドル
 0x00c7 00199 (builtin.3.go:8) CALL ,fmt.Println(SB)
 // 将a加上123,并返回
 0x00cc 00204 (builtin.3.go:9) MOVQ "".a+120(FP),BX
 0x00d1 00209 (builtin.3.go:9) ADDQ 123,ドルBX
 0x00d5 00213 (builtin.3.go:9) MOVQ BX,"".~r1+128(FP)
 0x00dd 00221 (builtin.3.go:9) ADDQ 112,ドルSP
 0x00e1 00225 (builtin.3.go:9) RET ,
 0x00e2 00226 (builtin.3.go:8) MOVL AX,(BX)
 0x00e4 00228 (builtin.3.go:8) JMP ,71
 
 
 "".main t=1 size=240 value=0 args=0x0 locals=0x70
 0x0000 00000 (builtin.3.go:12) TEXT "".main+0(SB),112ドル-0
 0x0000 00000 (builtin.3.go:12) MOVQ (TLS),CX
 0x0009 00009 (builtin.3.go:12) CMPQ SP,16(CX)
 0x000d 00013 (builtin.3.go:12) JHI ,22
 0x000f 00015 (builtin.3.go:12) CALL ,runtime.morestack_noctxt(SB)
 0x0014 00020 (builtin.3.go:12) JMP ,0
 // 将SP减去112(栈的大小),栈向下增长
 0x0016 00022 (builtin.3.go:12) SUBQ 112,ドルSP
 0x001a 00026 (builtin.3.go:12) FUNCDATA 0,ドルgclocals·73423680ca5f2d7df4fe760a82d507fb+0(SB)
 0x001a 00026 (builtin.3.go:12) FUNCDATA 1,ドルgclocals·403a8d79fd24b295e8557f6970497aa3+0(SB)
 // 将123放在栈顶
 0x001a 00026 (builtin.3.go:13) MOVQ 123,ドル(SP)
 0x0022 00034 (builtin.3.go:13) PCDATA 0,ドル0ドル
 // 调用f1
 0x0022 00034 (builtin.3.go:13) CALL ,"".f1(SB)
 // 将结果8(SP)存入BX
 0x0027 00039 (builtin.3.go:13) MOVQ 8(SP),BX
 0x002c 00044 (builtin.3.go:13) NOP ,
 // 将BX存放到48(SP), 是一个临时变量,BX中保存的是f1的调用结果
 0x002c 00044 (builtin.3.go:14) MOVQ BX,"".autotmp_0010+48(SP)

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

本文来自:天地孤影任我行

感谢作者:华子

查看原文:Golang内置函数和过程调用汇编代码分析

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

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

用户登录

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

今日阅读排行

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

一周阅读排行

    加载中

关注我

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

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

给该专栏投稿 写篇新文章

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

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