v1.f()
0x109959d 488d059c1a0500 LEAQ go.itab.*main.concrete,main.abstract(SB), AX
0x10995a4 8400 TESTB AL, 0(AX)
0x10995a6 488d05eba40f00 LEAQ runtime.zerobase(SB), AX
0x10995ad 48890424 MOVQ AX, 0(SP)
0x10995b1 e81a000000 CALL main.(*concrete).f(SB)
Let's run that line by line.
0x109959d 488d059c1a0500 LEAQ go.itab.*main.concrete,main.abstract(SB), AX
We first load the tab
field of the itab
struct into the address pointed by the stack pointer
(SP). This itab
refers to the field 'itab' of the iface struct (see runtime2.go):
type iface struct {
tab *itab
data unsafe.Pointer
}
0x10995a4 8400 TESTB AL, 0(AX)
Test that ``
0x10995a6 488d05eba40f00 LEAQ runtime.zerobase(SB), AX
0x10995ad 48890424 MOVQ AX, 0(SP)
Now that the tab
address is contained in the address pointed by the SP, it's time to find out
which concrete implementation of f()
should be called:
0x10995b1 e81a000000 CALL main.(*concrete).f(SB)
And here is the dispath function main.(*concrete).f
:
TEXT main.(*concrete).f(SB) <autogenerated>
0x10995d0 65488b0c2530000000 MOVQ GS:0x30, CX
0x10995d9 483b6110 CMPQ 0x10(CX), SP
0x10995dd 7631 JBE 0x1099610
0x10995df 4883ec08 SUBQ $0x8, SP
0x10995e3 48892c24 MOVQ BP, 0(SP)
0x10995e7 488d2c24 LEAQ 0(SP), BP
0x10995eb 488b5920 MOVQ 0x20(CX), BX
0x10995ef 4885db TESTQ BX, BX
0x10995f2 7523 JNE 0x1099617
0x10995f4 48837c241000 CMPQ $0x0, 0x10(SP)
0x10995fa 740e JE 0x109960a
0x10995fc e8bffeffff CALL main.concrete.f(SB)
0x1099601 488b2c24 MOVQ 0(SP), BP
0x1099605 4883c408 ADDQ $0x8, SP
0x1099609 c3 RET
0x109960a e8c1ddf6ff CALL runtime.panicwrap(SB)
0x109960f 90 NOPL
0x1099610 e80b7ffbff CALL runtime.morestack_noctxt(SB)
0x1099615 ebb9 JMP main.(*concrete).f(SB)
0x1099617 488d7c2410 LEAQ 0x10(SP), DI
0x109961c 48393b CMPQ DI, 0(BX)
0x109961f 75d3 JNE 0x10995f4
0x1099621 488923 MOVQ SP, 0(BX)
0x1099624 ebce JMP 0x10995f4
v2.f()
0x10995b6 e805ffffff CALL main.concrete.f(SB)