乐趣区

关于golang:golang-morestacknoctxt解析

go version go16.2, maxOS Mojave
原理能够从 https://juejin.cn/post/684490…,本片单纯解析源码

哪里调用

原函数

package main

func testMoreStack(a, b int) int {return testMoreStack(1, b)
}
func main() {}

编译

go tool compile -N -l -S ./main2.go > ./main2~~~~.s

关上生成文件 main2.s

"".testMoreStack STEXT size=93 args=0x18 locals=0x28 funcid=0x0
    0x0000 00000 (./main2.go:7)    TEXT    "".testMoreStack(SB), ABIInternal, $40-24
    0x0000 00000 (./main2.go:7)    MOVQ    (TLS), CX                   // CX = *g
    0x0009 00009 (./main2.go:7)    CMPQ    SP, 16(CX)                  // if SP > g.stackguard1
    0x000d 00013 (./main2.go:7)    PCDATA    $0, $-2
    0x000d 00013 (./main2.go:7)    JLS    86                             // true 跳到 86
    0x000f 00015 (./main2.go:7)    PCDATA    $0, $-1
    0x000f 00015 (./main2.go:7)    SUBQ    $40, SP
    0x0013 00019 (./main2.go:7)    MOVQ    BP, 32(SP)
    0x0018 00024 (./main2.go:7)    LEAQ    32(SP), BP
    0x001d 00029 (./main2.go:7)    FUNCDATA    $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x001d 00029 (./main2.go:7)    FUNCDATA    $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x001d 00029 (./main2.go:7)    MOVQ    $0, "".~r2+64(SP)
    0x0026 00038 (./main2.go:8)    MOVQ    "".b+56(SP), AX
    0x002b 00043 (./main2.go:8)    MOVQ    $1, (SP)
    0x0033 00051 (./main2.go:8)    MOVQ    AX, 8(SP)
    0x0038 00056 (./main2.go:8)    PCDATA    $1, $0
    0x0038 00056 (./main2.go:8)    CALL    "".testMoreStack(SB)
    0x003d 00061 (./main2.go:8)    MOVQ    16(SP), AX
    0x0042 00066 (./main2.go:8)    MOVQ    AX, ""..autotmp_3+24(SP)
    0x0047 00071 (./main2.go:8)    MOVQ    AX, "".~r2+64(SP)
    0x004c 00076 (./main2.go:8)    MOVQ    32(SP), BP
    0x0051 00081 (./main2.go:8)    ADDQ    $40, SP
    0x0055 00085 (./main2.go:8)    RET
    0x0056 00086 (./main2.go:8)    NOP
    0x0056 00086 (./main2.go:7)    PCDATA    $1, $-1
    0x0056 00086 (./main2.go:7)    PCDATA    $0, $-2
    0x0056 00086 (./main2.go:7)    CALL    runtime.morestack_noctxt(SB)
    0x005b 00091 (./main2.go:7)    PCDATA    $0, $-1
    0x005b 00091 (./main2.go:7)    JMP    0                              // 跳到 0
    0x0000 65 48 8b 0c 25 00 00 00 00 48 3b 61 10 76 47 48  eH..%....H;a.vGH
    0x0010 83 ec 28 48 89 6c 24 20 48 8d 6c 24 20 48 c7 44  ..(H.l$ H.l$ H.D
    0x0020 24 40 00 00 00 00 48 8b 44 24 38 48 c7 04 24 01  $@....H.D$8H..$.
    0x0030 00 00 00 48 89 44 24 08 e8 00 00 00 00 48 8b 44  ...H.D$......H.D
    0x0040 24 10 48 89 44 24 18 48 89 44 24 40 48 8b 6c 24  $.H.D$.H.D$@H.l$
    0x0050 20 48 83 c4 28 c3 e8 00 00 00 00 eb a3            H..(........
    rel 5+4 t=17 TLS+0
    rel 57+4 t=8 "".testMoreStack+0
    rel 87+4 t=8 runtime.morestack_noctxt+0

本函数栈 40 字节, 调用栈24 字节, 函数返回 PC 8 字节 字节共 72 字节,
栈地位:

地位
64(SP) 返回值
56(SP) 参数 b
48(SP) 参数 a
40(SP) PC
32(SP) base point
24(SP) 长期存调用 testMoreStack 的返回值
16(SP) 调用 testMoreStack 的返回值
8(SP) 调用 testMoreStack 的第二个参数
0(SP) 调用 testMoreStack 的第一个参数

伪代码

label0:
if SP > g.stackguard1 {CALL runtime.morestack_noctxt(SB)
    jump label0
} else {do something}

开始执行

以 asm_arm64.s 为例

TEXT runtime·morestack_noctxt(SB),NOSPLIT|NOFRAME,$0-0
 MOVW $0, R26
 B runtime·morestack(SB)
 
// Called during function prolog when more stack is needed.
// Caller has already loaded:
// R3 prolog's LR (R30)
//
// The traceback routines see morestack on a g0 as being
// the top of a stack (for example, morestack calling newstack
// calling the scheduler calling newm calling gc), so we must
// record an argument size. For that purpose, it has no arguments.
TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
    // Cannot grow scheduler stack (m->g0).
    MOVD    g_m(g), R8          // R8 = g.m
    MOVD    m_g0(R8), R4        // R4 = g.m.g0
    CMP    g, R4                   // if g == g0
    BNE    3(PC)                   // 不等跳过上面两个指令(不能在 g0 执行 morestack)
    BL    runtime·badmorestackg0(SB)
    B    runtime·abort(SB)

    // Cannot grow signal stack (m->gsignal).
    MOVD    m_gsignal(R8), R4   // R4 = g.m.gsignal
    CMP    g, R4                   // if g == gsignal
    BNE    3(PC)                   // 不等跳过上面两个指令(不能在 g0 执行 gsignal)
    BL    runtime·badmorestackgsignal(SB)
    B    runtime·abort(SB)

    // Called from f.
    // Set g->sched to context in f
    MOVD    RSP, R0                             // R0 = RSP
    MOVD    R0, (g_sched+gobuf_sp)(g)           // g.sched.gobuf.sp = R0
    MOVD    R29, (g_sched+gobuf_bp)(g)          // g.sched.gobuf.bp = R29
    MOVD    LR, (g_sched+gobuf_pc)(g)           // g.sched.gobuf.pc = R29
    MOVD    R3, (g_sched+gobuf_lr)(g)           // g.sched.gobuf.lr = R3
    MOVD    R26, (g_sched+gobuf_ctxt)(g)

    // Called from f.
    // Set m->morebuf to f's callers.
    MOVD    R3, (m_morebuf+gobuf_pc)(R8)    // f's caller's PC
    MOVD    RSP, R0
    MOVD    R0, (m_morebuf+gobuf_sp)(R8)    // f's caller's RSP
    MOVD    g, (m_morebuf+gobuf_g)(R8)

    // Call newstack on m->g0's stack.
    MOVD    m_g0(R8), g                     // 
    BL    runtime·save_g(SB)
    MOVD    (g_sched+gobuf_sp)(g), R0
    MOVD    R0, RSP
    MOVD    (g_sched+gobuf_bp)(g), R29
    MOVD.W    $0, -16(RSP)    // create a call frame on g0 (saved LR; keep 16-aligned)
    BL    runtime·newstack(SB)

    // Not reached, but make sure the return PC from the call to newstack
    // is still in this function, and not the beginning of the next.
    UNDEF
退出移动版