How to understand assembly code related to defer

210 views
Skip to first unread message

j2gg0s

unread,
Sep 26, 2023, 10:43:27 AM9/26/23
to golang-nuts
How to understand assmbly code `  47ae26: 48 8d 0d bb 06 02 00          leaq    132795(%rip), %rcx      # 0x49b4e8 <go:func.*+0x220>`

Go code:
```
//go:noinline
func add(a, b int) int {
        defer func() {
                fmt.Println(3)
        }()
        return a + b
}

func main() {
        add(10, 20)
}
```

Build by `GOOS=linux GOARCH=amd64 GOSSAFUNC=main.add go21 build main.go`

Assembly code
```
objdump -D -S main | grep "main.add>:" -A 30
000000000047ae00 <main.add>:
; func add(a, b int) int {
  47ae00: 49 3b 66 10                   cmpq    16(%r14), %rsp
  47ae04: 76 5b                         jbe     0x47ae61 <main.add+0x61>
  47ae06: 55                            pushq   %rbp
  47ae07: 48 89 e5                      movq    %rsp, %rbp
  47ae0a: 48 83 ec 18                   subq    $24, %rsp
  47ae0e: 66 44 0f d6 7c 24 10          movq    %xmm15, 16(%rsp)
  47ae15: c6 44 24 07 00                movb    $0, 7(%rsp)
  47ae1a: 48 c7 44 24 08 00 00 00 00    movq    $0, 8(%rsp)
;       return a + b
  47ae23: 48 01 d8                      addq    %rbx, %rax
;       defer func() {
  47ae26: 48 8d 0d bb 06 02 00          leaq    132795(%rip), %rcx      # 0x49b4e8 <go:func.*+0x220>
  47ae2d: 48 89 4c 24 10                movq    %rcx, 16(%rsp)
  47ae32: c6 44 24 07 01                movb    $1, 7(%rsp)
;       return a + b
  47ae37: 48 89 44 24 08                movq    %rax, 8(%rsp)
  47ae3c: c6 44 24 07 00                movb    $0, 7(%rsp)
  47ae41: e8 7a 00 00 00                callq   0x47aec0 <main.add.func1>
  47ae46: 48 8b 44 24 08                movq    8(%rsp), %rax
  47ae4b: 48 83 c4 18                   addq    $24, %rsp
  47ae4f: 5d                            popq    %rbp
  47ae50: c3                            retq
  47ae51: e8 8a 47 fb ff                callq   0x42f5e0 <runtime.deferreturn>
  47ae56: 48 8b 44 24 08                movq    8(%rsp), %rax
  47ae5b: 48 83 c4 18                   addq    $24, %rsp
  47ae5f: 5d                            popq    %rbp
  47ae60: c3                            retq
; func add(a, b int) int {
  47ae61: 48 89 44 24 08                movq    %rax, 8(%rsp)
```

j2gg0s

unread,
Sep 26, 2023, 11:18:04 AM9/26/23
to golang-nuts
Append:

  49b4e8: c0 ae 47 00 00 00 00         shrb $0, 71(%rsi)

Ian Lance Taylor

unread,
Sep 26, 2023, 9:38:17 PM9/26/23
to j2gg0s, golang-nuts
On Tue, Sep 26, 2023 at 7:43 AM j2gg0s <feys...@gmail.com> wrote:
>
> How to understand assmbly code ` 47ae26: 48 8d 0d bb 06 02 00 leaq 132795(%rip), %rcx # 0x49b4e8 <go:func.*+0x220>`

The best place to start is

https://go.googlesource.com/proposal/+/refs/heads/master/design/34481-opencoded-defers.md

Ian

j2gg0s

unread,
Sep 27, 2023, 12:09:54 AM9/27/23
to golang-nuts
Thanks @lan

Already read it, I actually started here.

What I can't understand is x64 rip-relative address.

leaq    132795(%rip), %rcx      # 0x49b4e8 <go:func.*+0x220>

why 132795, and what is loaded into rcx 

Kurtis Rader

unread,
Sep 27, 2023, 12:43:05 AM9/27/23
to j2gg0s, golang-nuts
More context regarding your question might help. Why are you trying to understand the assembly code? Are you trying to debug a failure in the wild? Are you trying to make the implementation more efficient? Are you simply curious how the implementation works? Your question is rather broad and likely to require a lot of explanatory text. It is unlikely someone will write that explanatory text without a good reason. They might give you a link, like Ian did, to a document that describes the high level details. But it is unlikely there is a public document, like an enhancement proposal, that answers your question at the level of detail of specific instruction sequences.

--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/69d8ca43-d4e7-4945-ab94-9951fa51188dn%40googlegroups.com.


--
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

Ian Lance Taylor

unread,
Sep 27, 2023, 12:44:10 AM9/27/23
to j2gg0s, golang-nuts
On Tue, Sep 26, 2023 at 9:10 PM j2gg0s <feys...@gmail.com> wrote:
>
> Already read it, I actually started here.
>
> What I can't understand is x64 rip-relative address.
>
> leaq 132795(%rip), %rcx # 0x49b4e8 <go:func.*+0x220>
>
> why 132795, and what is loaded into rcx

It's a reference to another address in the program. The comment from
the disassembler tells you that it refers to the address go:func.* +
0x220. The linker constructs the offset 132795.

Ian



> 在2023年9月27日星期三 UTC+8 09:38:17<Ian Lance Taylor> 写道:
>>
>> On Tue, Sep 26, 2023 at 7:43 AM j2gg0s <feys...@gmail.com> wrote:
>> >
>> > How to understand assmbly code ` 47ae26: 48 8d 0d bb 06 02 00 leaq 132795(%rip), %rcx # 0x49b4e8 <go:func.*+0x220>`
>>
>> The best place to start is
>>
>> https://go.googlesource.com/proposal/+/refs/heads/master/design/34481-opencoded-defers.md
>>
>> Ian
>

j2gg0s

unread,
Sep 27, 2023, 2:06:32 AM9/27/23
to golang-nuts
Related go code:
    22  //go:noinline
    23  func add(a, b int) int {
    24          defer func() {
    25                  fmt.Println(3)
    26          }()
    27          return a + b
    28  }

Build by: GOOS=linux GOARCH=amd64 go21 build main.go

Disassembler by: objdump -D -S main
Assembly code:
179228  000000000047ae20 <main.add>:
179229  ; func add(a, b int) int {
179230    47ae20: 49 3b 66 10                   cmpq    16(%r14), %rsp
179231    47ae24: 76 5b                         jbe     0x47ae81 <main.add+0x61>
179232    47ae26: 55                            pushq   %rbp
179233    47ae27: 48 89 e5                      movq    %rsp, %rbp
179234    47ae2a: 48 83 ec 18                   subq    $24, %rsp
179235    47ae2e: 66 44 0f d6 7c 24 10          movq    %xmm15, 16(%rsp)
179236    47ae35: c6 44 24 07 00                movb    $0, 7(%rsp)
179237    47ae3a: 48 c7 44 24 08 00 00 00 00    movq    $0, 8(%rsp)
179238  ;       return a + b
179239    47ae43: 48 01 d8                      addq    %rbx, %rax
179240  ;       defer func() {
179241    47ae46: 48 8d 0d 9b 06 02 00          leaq    132763(%rip), %rcx      # 0x49b4e8 <go:func.*+0x220>
179242    47ae4d: 48 89 4c 24 10                movq    %rcx, 16(%rsp)
179243    47ae52: c6 44 24 07 01                movb    $1, 7(%rsp)
179244  ;       return a + b
179245    47ae57: 48 89 44 24 08                movq    %rax, 8(%rsp)
179246    47ae5c: c6 44 24 07 00                movb    $0, 7(%rsp)
179247    47ae61: e8 7a 00 00 00                callq   0x47aee0 <main.add.func1>
179248    47ae66: 48 8b 44 24 08                movq    8(%rsp), %rax
179249    47ae6b: 48 83 c4 18                   addq    $24, %rsp
179250    47ae6f: 5d                            popq    %rbp
179251    47ae70: c3                            retq


According to my understanding:
1. `179241    47ae46: 48 8d 0d 9b 06 02 00          leaq    132763(%rip), %rcx      # 0x49b4e8 <go:func.*+0x220>` want to load address of main.add.func1 to register rcx. Is this understanding correct?
2.1 rip 0x47ae4d, 0x47ae4d + 132763 = 0x49b4e8,
2.2 main.add.func1's address is 0x47b0c0
objdump -D -S main | grep "main.add.func1>:" -A 31
000000000047aee0 <main.add.func1>:
2.3 i just found 0x49b4e8 in rodata
2.4 So, What is stored at 0x49b4e8?

j2gg0s

unread,
Sep 27, 2023, 2:09:28 AM9/27/23
to golang-nuts
It's not a bug or a performance issue.

Just because I am about to have a long hoilday, so I want to learn some knowledge about go compiler.
But as a newbie in assembly, I spent some time on Google but couldn't understand this instruction.

j2gg0s

unread,
Sep 27, 2023, 5:02:57 AM9/27/23
to golang-nuts
Append

When I constructed a stack allocated defer, I knew the meaning of this instruction.

before call deferprocStack, we assign _defer.fn = defer func() { fmt.Println(1) }
```
; defer func() { fmt.Println(1) }()
  47ae56: 48 8d 0d 8b 16 02 00         leaq 136843(%rip), %rcx      # 0x49c4e8 <go:func.*+0x220>
  47ae5d: 48 89 8c 24 d8 01 00 00       movq %rcx, 472(%rsp)
  47ae65: 48 8d 84 24 c0 01 00 00       leaq 448(%rsp), %rax
  47ae6d: e8 8e 41 fb ff               callq 0x42f000 <runtime.deferprocStack>
  47ae72: 85 c0                         testl %eax, %eax      ; TODO
  47ae74: 0f 85 d9 01 00 00             jne 0x47b053 <main.add+0x233>
```

Ian Lance Taylor

unread,
Sep 27, 2023, 11:34:21 PM9/27/23
to j2gg0s, golang-nuts
Sort of. 0x49b4e8 is the address of the function descriptor for
main.add.func1. If you look at address 0x49b4e8 you will see that it
contains the value 0x47aee0, which is the address of the code for
main.add.func1. For function descriptors see
https://go.dev/s/go11func.

> 2.1 rip 0x47ae4d, 0x47ae4d + 132763 = 0x49b4e8,

Yes, as the disassembler comment says.

> 2.2 main.add.func1's address is 0x47b0c0
> objdump -D -S main | grep "main.add.func1>:" -A 31
> 000000000047aee0 <main.add.func1>:

Well, 0x47aee0, not 0x47b0c0

> 2.3 i just found 0x49b4e8 in rodata
> 2.4 So, What is stored at 0x49b4e8?

The code for main.add.func1.

Ian


> 在2023年9月27日星期三 UTC+8 12:44:10<Ian Lance Taylor> 写道:
>>
>> On Tue, Sep 26, 2023 at 9:10 PM j2gg0s <feys...@gmail.com> wrote:
>> >
>> > Already read it, I actually started here.
>> >
>> > What I can't understand is x64 rip-relative address.
>> >
>> > leaq 132795(%rip), %rcx # 0x49b4e8 <go:func.*+0x220>
>> >
>> > why 132795, and what is loaded into rcx
>>
>> It's a reference to another address in the program. The comment from
>> the disassembler tells you that it refers to the address go:func.* +
>> 0x220. The linker constructs the offset 132795.
>>
>> Ian
>>
>>
>>
>> > 在2023年9月27日星期三 UTC+8 09:38:17<Ian Lance Taylor> 写道:
>> >>
>> >> On Tue, Sep 26, 2023 at 7:43 AM j2gg0s <feys...@gmail.com> wrote:
>> >> >
>> >> > How to understand assmbly code ` 47ae26: 48 8d 0d bb 06 02 00 leaq 132795(%rip), %rcx # 0x49b4e8 <go:func.*+0x220>`
>> >>
>> >> The best place to start is
>> >>
>> >> https://go.googlesource.com/proposal/+/refs/heads/master/design/34481-opencoded-defers.md
>> >>
>> >> Ian
>> >
>> > --
>> > 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...@googlegroups.com.
>> > To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/69d8ca43-d4e7-4945-ab94-9951fa51188dn%40googlegroups.com.
>
> --
> 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...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/3981c7b9-804b-4dd6-959c-9da0656bb317n%40googlegroups.com.

j2gg0s

unread,
Oct 7, 2023, 7:57:39 AM10/7/23
to golang-nuts

Thanks for the guidance, the corresponding documentation helped me a lot
Reply all
Reply to author
Forward
0 new messages