高版本的Go编译器,为什么在使用原生go代码是使用寄存器传参,但是在汇编实现中却使用栈传参?有可能改变这种行为吗?

Author: qshuaiCreated Jul 16, 2024Updated Nov 24, 2024

Go version:

go version go1.22.1 linux/amd64
  • 使用go代码实现:
package main

//go:noinline
func add(a, b uint64) uint64 {
	return a + b
}

func main() {
	_ = add(2, 3)
}

指令:使用了寄存器传参(命令: go build add_native.gogo tool objdump -s '^main.' add_native):

TEXT main.add(SB) /root/project/go/src/github.com/qshuai/test/asm/add_native.go
  add_native.go:5	0x45d140		4801d8			ADDQ BX, AX     // 使用寄存器处理参数和返回值
  add_native.go:5	0x45d143		c3			RET

TEXT main.main(SB) /root/project/go/src/github.com/qshuai/test/asm/add_native.go
  add_native.go:8	0x45d160		493b6610		CMPQ SP, 0x10(R14)
  add_native.go:8	0x45d164		761d			JBE 0x45d183
  add_native.go:8	0x45d166		55			PUSHQ BP
  add_native.go:8	0x45d167		4889e5			MOVQ SP, BP
  add_native.go:8	0x45d16a		4883ec10		SUBQ $0x10, SP
  add_native.go:9	0x45d16e		b802000000		MOVL $0x2, AX
  add_native.go:9	0x45d173		bb03000000		MOVL $0x3, BX
  add_native.go:9	0x45d178		e8c3ffffff		CALL main.add(SB)
  add_native.go:10	0x45d17d		4883c410		ADDQ $0x10, SP
  add_native.go:10	0x45d181		5d			POPQ BP
  add_native.go:10	0x45d182		c3			RET
  add_native.go:8	0x45d183		e898cdffff		CALL runtime.morestack_noctxt.abi0(SB)
  add_native.go:8	0x45d188		ebd6			JMP main.main(SB)
  • 使用汇编实现add函数
// go code
package main

//go:noinline
func add(a, b uint64) uint64

func main() {
	_ = add(2, 3)
}

// asm
TEXT ·add(SB), $0-0
  ADDQ BX, AX
  RET

指令:使用栈传参(命令:go buildgo tool objdump -s '^main.' xxx):

TEXT main.main(SB) /root/project/go/src/github.com/qshuai/test/asm/add.go
  add.go:6		0x45d140		493b6610		CMPQ SP, 0x10(R14)
  add.go:6		0x45d144		7632			JBE 0x45d178
  add.go:6		0x45d146		55			PUSHQ BP
  add.go:6		0x45d147		4889e5			MOVQ SP, BP
  add.go:6		0x45d14a		4883ec18		SUBQ $0x18, SP
  add.go:7		0x45d14e		48c7042402000000	MOVQ $0x2, 0(SP)    // 使用栈传参:2
  add.go:7		0x45d156		48c744240803000000	MOVQ $0x3, 0x8(SP)  // 使用栈传参:3
  add.go:7		0x45d15f		90			NOPL
  add.go:7		0x45d160		e81b000000		CALL main.add.abi0(SB)
  add.go:7		0x45d165		450f57ff		XORPS X15, X15
  add.go:7		0x45d169		644c8b3425f8ffffff	MOVQ FS:0xfffffff8, R14
  add.go:8		0x45d172		4883c418		ADDQ $0x18, SP
  add.go:8		0x45d176		5d			POPQ BP
  add.go:8		0x45d177		c3			RET
  add.go:6		0x45d178		e8a3cdffff		CALL runtime.morestack_noctxt.abi0(SB)
  add.go:6		0x45d17d		ebc1			JMP main.main(SB)

TEXT main.add.abi0(SB) /root/project/go/src/github.com/qshuai/test/asm/add_amd64.s
  add_amd64.s:2		0x45d180		4801d8			ADDQ BX, AX  // 这个逻辑就错误了
  add_amd64.s:3		0x45d183		c3			RET

Source: chai2010/advanced-go-programming-book