Confusion about layout of stack and the conventions for calling between Go functions

package main

func main() {
  var x int32 = 1
  nop(x)
}

//go:noinline
func nop(x int32) {}

Go version: go1.16.15 windows/amd64

I wrote above code and compiled it into assembly with go1.16.15 tool compile -S -N -l main.go for truly understanding Go functions call.

The following is the assembly code of nop function:

"".nop STEXT nosplit size=1 args=0x8 locals=0x0 funcid=0x0
        0x0000 00000 (main.go:9)        TEXT    "".nop(SB), NOSPLIT|ABIInternal, $0-8
        0x0000 00000 (main.go:9)        FUNCDATA        $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (main.go:9)        FUNCDATA        $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0000 00000 (main.go:9)        RET

Obviously, the nop function returns directly without doing anything. It only has a int32 type parameter, but we can see the argsize is 8 bytes in the assembly:

TEXT “”.nop(SB), NOSPLIT|ABIInternal, $0-8

Question1: Why the argsize is 8 bytes but not 4 bytes?

The following is the assembly code of main function:

"".main STEXT size=73 args=0x0 locals=0x18 funcid=0x0
        0x0000 00000 (main.go:3)        TEXT    "".main(SB), ABIInternal, $24-0
        ;; ...omitted stack-split prologue...
        0x0016 00022 (main.go:3)        SUBQ    $24, SP
        0x001a 00026 (main.go:3)        MOVQ    BP, 16(SP)
        0x001f 00031 (main.go:3)        LEAQ    16(SP), BP
        0x0024 00036 (main.go:3)        FUNCDATA        $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0024 00036 (main.go:3)        FUNCDATA        $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
        0x0024 00036 (main.go:4)        MOVL    $1, "".x+12(SP)
        0x002c 00044 (main.go:5)        MOVL    $1, (SP)
        0x0033 00051 (main.go:5)        PCDATA  $1, $0
        0x0033 00051 (main.go:5)        CALL    "".nop(SB)
        0x0038 00056 (main.go:6)        MOVQ    16(SP), BP
        0x003d 00061 (main.go:6)        ADDQ    $24, SP
        0x0041 00065 (main.go:6)        RET
        ;; ...omitted stack-split epilogue...

I drawn a picture of stack according to the assembly code:
confusing 8 bytes

Question2: I find there are confusing 8 bytes in the stack, why do these 8 bytes exist?

I think memory alignment causes the above phenomenon, but I’m not sure.

Question3: I think the SP in MOVL $1, "".x+12(SP) is “pseudo SP”, so why MOVL $1, "".x+12(SP) but not MOVL $1, "".x-12(SP)?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.