[go-nuts] Re: Why there are eight bytes pad in the stack frame of main function?

2022-12-21 Thread tarorual
Q2: I agree with the statement "4 are from rounding argsize up to 8 bytes". 
According to the Go internal ABI specification 

 
(although it is published for Go1.17 and later version, I think it has some 
reference value), there is a pointer-sized (8 bytes in amd64) alignments 
after stack-assigned arguments, so there are 4 bytes pad after the `int32` 
argument.
I don't understand why other 4 bytes are padded before x, not after x: a 
possible padding.png . It is more 
reasonable to pad after x, I think :)

Q3: According to the official doc A Quick Guide to Go's Assembler 
, I think the SP in  MOVL$1, "".x*+*12(*SP*) is 
"pseudo SP":

*The SP pseudo-register is a virtual stack pointer used to refer to 
frame-local variables and the arguments being prepared for function calls. 
It points to the highest address within the local stack frame, so 
references should use negative offsets in the range [−framesize, 0): 
x-8(SP), y-4(SP), and so on. *

* On architectures with a hardware register named SP, the name prefix 
distinguishes references to the virtual stack pointer from references to 
the architectural SP register. That is, x-8(SP) and -8(SP) are different 
memory locations: the first refers to the virtual stack pointer 
pseudo-register, while the second refers to the hardware's SP register. *

在2022年12月20日星期二 UTC+8 07:46:28 写道:

> Q1: stack frames are rounded to a multiple of 8 bytes, to keep the stack 
> pointer 8-byte aligned. Part of that is rounding argsize to 8 bytes. (It's 
> not strictly necessary, and we could report 4, I think, if there are no 
> return values.)
> Q2: I think 4 are from rounding argsize up to 8 bytes, and 4 are padding 
> to keep the total frame a multiple of 8 bytes.
> Q3: offsets are from the updated stack pointer (the one generated by the 
> SUBQ $24, SP instruction). So they will be positive.
>
> On Monday, December 19, 2022 at 11:31:47 AM UTC-8 tarorual wrote:
>
>> 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
>> 0x 0 (main.go:9)TEXT"".nop(SB), 
>> NOSPLIT|ABIInternal, $0-8
>> 0x 0 (main.go:9)FUNCDATA$0, 
>> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
>> 0x 0 (main.go:9)FUNCDATA$1, 
>> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
>> 0x 0 (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 not 4 bytes?*
>>
>> The following is the assembly code of main function:
>>
>> "".main STEXT size=73 args=0x0 locals=0x18 funcid=0x0
>> 0x 0 (main.go:3)TEXT"".main(SB), ABIInternal, 
>> $24-0
>> 0x 0 (main.go:3)MOVQTLS, CX
>> 0x0009 9 (main.go:3)PCDATA  $0, $-2
>> 0x0009 9 (main.go:3)MOVQ(CX)(TLS*2), CX
>> 0x0010 00016 (main.go:3)PCDATA  $0, $-1
>> 0x0010 00016 (main.go:3)CMPQSP, 16(CX)
>> 0x0014 00020 (main.go:3)PCDATA  $0, $-2
>> 0x0014 00020 (main.go:3)JLS 66
>> 0x0016 00022 (main.go:3)PCDATA  $0, $-1
>> 0x0016 00022 (main.go:3)SUBQ$24, SP
>> 0x001a 00026 (main.go:3)MOVQBP, 16(SP)
>> 0x001f 00031 (main.go:3)LEAQ16(SP), BP
>> 0x0024 00036 (main.go:3)FUNCDATA$0, 
>> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
>> 0x0024 00036 (main.go:3)FUNCDATA$1, 
>> gclocals·33cdeebe80329f1fdbee7f5874cb(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)MOVQ16(SP), BP
>> 0x003d 00061 (main.go:6)ADDQ$24, SP
>> 0x0041 00065 (main.go:6)RET
>>
>> I drawn a picture of stack according to the assembly code:
>> https://i.stack.imgur.com/AHN1b.png
>>
>> *Question2: I find there are confusing 8 bytes in the stack, why do these 
>> 8 bytes exist?*
>>
>> * Question3:  Why *MOVL$1, "".x*+*12(SP)*but not  *MOVL$1, "".x
>> *-*12(SP)? 
>>
>> I think 

[go-nuts] Re: Why there are eight bytes pad in the stack frame of main function?

2022-12-19 Thread 'Keith Randall' via golang-nuts
Q1: stack frames are rounded to a multiple of 8 bytes, to keep the stack 
pointer 8-byte aligned. Part of that is rounding argsize to 8 bytes. (It's 
not strictly necessary, and we could report 4, I think, if there are no 
return values.)
Q2: I think 4 are from rounding argsize up to 8 bytes, and 4 are padding to 
keep the total frame a multiple of 8 bytes.
Q3: offsets are from the updated stack pointer (the one generated by the 
SUBQ $24, SP instruction). So they will be positive.

On Monday, December 19, 2022 at 11:31:47 AM UTC-8 tarorual wrote:

> 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
> 0x 0 (main.go:9)TEXT"".nop(SB), 
> NOSPLIT|ABIInternal, $0-8
> 0x 0 (main.go:9)FUNCDATA$0, 
> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
> 0x 0 (main.go:9)FUNCDATA$1, 
> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
> 0x 0 (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 not 4 bytes?*
>
> The following is the assembly code of main function:
>
> "".main STEXT size=73 args=0x0 locals=0x18 funcid=0x0
> 0x 0 (main.go:3)TEXT"".main(SB), ABIInternal, 
> $24-0
> 0x 0 (main.go:3)MOVQTLS, CX
> 0x0009 9 (main.go:3)PCDATA  $0, $-2
> 0x0009 9 (main.go:3)MOVQ(CX)(TLS*2), CX
> 0x0010 00016 (main.go:3)PCDATA  $0, $-1
> 0x0010 00016 (main.go:3)CMPQSP, 16(CX)
> 0x0014 00020 (main.go:3)PCDATA  $0, $-2
> 0x0014 00020 (main.go:3)JLS 66
> 0x0016 00022 (main.go:3)PCDATA  $0, $-1
> 0x0016 00022 (main.go:3)SUBQ$24, SP
> 0x001a 00026 (main.go:3)MOVQBP, 16(SP)
> 0x001f 00031 (main.go:3)LEAQ16(SP), BP
> 0x0024 00036 (main.go:3)FUNCDATA$0, 
> gclocals·33cdeebe80329f1fdbee7f5874cb(SB)
> 0x0024 00036 (main.go:3)FUNCDATA$1, 
> gclocals·33cdeebe80329f1fdbee7f5874cb(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)MOVQ16(SP), BP
> 0x003d 00061 (main.go:6)ADDQ$24, SP
> 0x0041 00065 (main.go:6)RET
>
> I drawn a picture of stack according to the assembly code:
> https://i.stack.imgur.com/AHN1b.png
>
> *Question2: I find there are confusing 8 bytes in the stack, why do these 
> 8 bytes exist?*
>
> * Question3:  Why *MOVL$1, "".x*+*12(SP)*but not  *MOVL$1, "".x*-*
> 12(SP)? 
>
> I think memory alignment causes the above phenomenon, but I'm not sure.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/1f039f1b-c5b9-49b1-a908-428b0651b712n%40googlegroups.com.