go - 为什么在这种情况下会生成不同的 go-assembler 代码?
问题描述
生成汇编代码时注意到奇怪的事情
func foo(v uint64) (b [8]byte) {
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
b[4] = byte(v >> 32)
b[5] = byte(v >> 40)
b[6] = byte(v >> 48)
b[7] = byte(v >> 56)
return b
}
func foo(v uint64) [8]byte {
var b [8]byte
b[0] = byte(v)
b[1] = byte(v >> 8)
b[2] = byte(v >> 16)
b[3] = byte(v >> 24)
b[4] = byte(v >> 32)
b[5] = byte(v >> 40)
b[6] = byte(v >> 48)
b[7] = byte(v >> 56)
return b
}
生成了这个汇编代码
"".foo STEXT nosplit size=20 args=0x10 locals=0x0 funcid=0x0
0x0000 00000 (main.go:6) TEXT "".foo1(SB), NOSPLIT|ABIInternal, $0-16
0x0000 00000 (main.go:6) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (main.go:6) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x0000 00000 (main.go:6) MOVQ $0, "".b+16(SP)
0x0009 00009 (main.go:15) MOVQ "".v+8(SP), AX
0x000e 00014 (main.go:15) MOVQ AX, "".b+16(SP)
0x0013 00019 (main.go:16) RET
和
"".foo STEXT nosplit size=59 args=0x10 locals=0x10 funcid=0x0
0x0000 00000 (main.go:6) TEXT "".foo(SB), NOSPLIT|ABIInternal, $16-16
0x0000 00000 (main.go:6) SUBQ $16, SP
0x0004 00004 (main.go:6) MOVQ BP, 8(SP)
0x0009 00009 (main.go:6) LEAQ 8(SP), BP
0x000e 00014 (main.go:6) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x000e 00014 (main.go:6) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x000e 00014 (main.go:6) MOVQ $0, "".~r1+32(SP)
0x0017 00023 (main.go:7) MOVQ $0, "".b(SP)
0x001f 00031 (main.go:16) MOVQ "".v+24(SP), AX
0x0024 00036 (main.go:16) MOVQ AX, "".b(SP)
0x0028 00040 (main.go:17) MOVQ "".b(SP), AX
0x002c 00044 (main.go:17) MOVQ AX, "".~r1+32(SP)
0x0031 00049 (main.go:17) MOVQ 8(SP), BP
0x0036 00054 (main.go:17) ADDQ $16, SP
0x003a 00058 (main.go:17) RET
在第二种情况下,您可以看到编译器看到有一个局部变量。为什么会这样?为什么会生成如此不同的代码?
go version go1.16 windows/amd64
带有asm代码的文件来自
go tool compile -S mail.go > main.s
https://go.godbolt.org/z/G8K79K48G - 小asm代码
https://go.godbolt.org/z/Yv853E6P3 - 长asm代码
解决方案
这是之间的区别
func foo(v uint64) [8]byte {
和
func foo(v uint64) (b [8]byte) {
当您将返回指定为 时[8]byte
,您只是将返回类型告知编译器foo
。
但是,(b [8]byte)
上面不仅通过指定返回类型,而且
- 分配 8 个字节的内存
- 声明变量
b
, 类型[8]byte
- 初始化
b
为零填充分配的 64 位。
当您使用手动复制(b [8]byte)
时
var b [8]byte
然后它必须手动检查上面指定的项目符号列表。
0x0000 00000 (main.go:6) SUBQ $16, SP
0x0004 00004 (main.go:6) MOVQ BP, 8(SP)
0x0009 00009 (main.go:6) LEAQ 8(SP), BP
推荐阅读
- php - Laravel dosent 通过 ajax 删除记录?
- android-studio - 在 Android Studio 中使用 Kotlin 未解决的引用
- delphi - 从 IdHTTPServer 获取参数 - Firemonkey
- python - 多处理共享变量
- c# - 不将预填充值写入查看的模型
- java - 使用 UI.getCurrent().navigate 从另一个类导航时,类中的异步更新不起作用
- regex - bash if 语句中正则表达式和非正则表达式的混合
- android - AirLocation 库的问题
- vue.js - 错误“未知的自定义元素...”仅适用于某些 Vuetify 组件,如 v-expansion-panels
- node.js - 为什么 npm run watch 命令显示错误?