In go1.17, the function call specification has been updated to use nine registers to store parameters and return values (because the registers are faster), while before GO1.17, the parameters and return values of function calls are put on the stack, so the test codes are verified by GO1.17 and GO1.16.4 respectively:

package main

func main(a) {
	callee(1.2.3.4.5.6.7.8.9.10)}func callee(a, b, c, d, e, f, g, h, i, j int) (int.int.int.int.int.int.int.int.int.int) {
	localVar := 1  // A local variable is deliberately added to make the next callee stack easier to understand
	_ = localVar
	return 1.2.3.4.5.6.7.8.9, localVar
}
Copy the code

1.16.4

Run the go tool compile -s -n -l main.go command to output the following (remove unimportant details) :

"".main STEXT size=170 args=0x0 locals=0xa8 funcid=0x0(...).0x002f 00047 (main.go:4)        MOVQ    $1, (SP)   // The first argument passed to Callee
        0x0037 00055 (main.go:4)        MOVQ    $2.8(SP)
        0x0040 00064 (main.go:4)        MOVQ    $3.16(SP)
        0x0049 00073 (main.go:4)        MOVQ    $4.24(SP)
        0x0052 00082 (main.go:4)        MOVQ    $5.32(SP)
        0x005b 00091 (main.go:4)        MOVQ    $6.40(SP)
        0x0064 00100 (main.go:4)        MOVQ    $7.48(SP)
        0x006d 00109 (main.go:4)        MOVQ    $8.56(SP)
        0x0076 00118 (main.go:4)        MOVQ    $9.64(SP)
        0x007f 00127 (main.go:4)        MOVQ    $10.72(SP) // The last argument passed to Callee(...)."".callee STEXT nosplit size=254 args=0xa0 locals=0x10 funcid=0x0(...).0x007d 00125 (main.go:8)        MOVQ    $1."".localVar(SP)
        0x0085 00133 (main.go:10)       MOVQ    $1."".~r10+104(SP)  // Local variables
        0x008e 00142 (main.go:10)       MOVQ    $2."".~r11+112(SP)  // The first return value
        0x0097 00151 (main.go:10)       MOVQ    $3."".~r12+120(SP)
        0x00a0 00160 (main.go:10)       MOVQ    $4."".~r13+128(SP)
        0x00ac 00172 (main.go:10)       MOVQ    $5."".~r14+136(SP)
        0x00b8 00184 (main.go:10)       MOVQ    $6."".~r15+144(SP)
        0x00c4 00196 (main.go:10)       MOVQ    $7."".~r16+152(SP)
        0x00d0 00208 (main.go:10)       MOVQ    $8."".~r17+160(SP)
        0x00dc 00220 (main.go:10)       MOVQ    $9."".~r18+168(SP) // The last return value
        0x00e8 00232 (main.go:10)       MOVQ    "".localVar(SP), AX
        
        (...)
Copy the code

The stack layout of Main and Callee is as follows:

As you can see, version 1,16 of go passes all arguments and return values through the stack

1.17

Go tool compile -s -l main.go there is no -n

"".main STEXT size=103 args=0x0 locals=0x60 funcid=0x0(...).0x0014 00020 (main.go:4)        MOVQ    $10, (SP)  // the tenth argument
        0x001c 00028 (main.go:4)        MOVL    $1, AX     // First argument
        0x0021 00033 (main.go:4)        MOVL    $2, BX
        0x0026 00038 (main.go:4)        MOVL    $3, CX
        0x002b 00043 (main.go:4)        MOVL    $4, DI
        0x0030 00048 (main.go:4)        MOVL    $5, SI
        0x0035 00053 (main.go:4)        MOVL    $6, R8
        0x003b 00059 (main.go:4)        MOVL    $7, R9
        0x0041 00065 (main.go:4)        MOVL    $8, R10
        0x0047 00071 (main.go:4)        MOVL    $9, R11    // The ninth argument(...)."".callee STEXT nosplit size=59 args=0x58 locals=0x0 funcid=0x0(...).0x0000 00000 (main.go:10)       MOVQ    $10."".~r19+16(SP)  // the 10th return value
        0x0009 00009 (main.go:10)       MOVL    $1, AX      // the first return value
        0x000e 00014 (main.go:10)       MOVL    $2, BX
        0x0013 00019 (main.go:10)       MOVL    $3, CX
        0x0018 00024 (main.go:10)       MOVL    $4, DI
        0x001d 00029 (main.go:10)       MOVL    $5, SI
        0x0022 00034 (main.go:10)       MOVL    $6, R8
        0x0028 00040 (main.go:10)       MOVL    $7, R9
        0x002e 00046 (main.go:10)       MOVL    $8, R10
        0x0034 00052 (main.go:10)       MOVL    $9, R11     // The ninth return value
        0x003a 00058 (main.go:10)       RET
        
        (...)
Copy the code

As you can see, only 9 general purpose registers are officially used, which are AX, BX, CX, DI, SI, R8, R9, R10, and R11, which are placed on the stack in order.