書接上回。如今咱們知道_rt0_go這個彙編過程是GO語言的真正入口並作了一些初始化工做,本文來大略的過一下這個過程和它調用的幾個runtime裏的函數。linux
Windwos Live Writer寫的文章,編碼有問題,對不住各位:我不想改。windows
 函數
MOVL    argc+0(FP), AX
MOVL    argv+4(FP), BX
SUBL    $128, SP        // plenty of scratch
ANDL    $~15, SP
MOVL    AX, 120(SP)        // save argc, argv away
MOVL    BX, 124(SP)
這一段主要是處理操做系統傳來的參數,並把他們保存到棧上測試
 優化
MOVL    $runtime路g0(SB), BP
LEAL    (-64*1024+104)(SP), BX
MOVL    BX, g_stackguard(BP)
MOVL    BX, g_stackguard0(BP)
MOVL    SP, g_stackbase(BP)ui
 this
// find out information about the processor we're on
MOVL    $0, AX
CPUID
CMPL    AX, $0
JE    nocpuinfo
MOVL    $1, AX
CPUID
MOVL    CX, runtime·cpuid_ecx(SB)
MOVL    DX, runtime·cpuid_edx(SB)編碼
測試CPUID的目的在於充分利用硬件的能力,在GO源碼中的哈希部分用到了它,在哈希的時候用aes&sse指令提升速度。操作系統
 orm
    // if there is an _cgo_init, call it to let it
    // initialize and to set up GS.  if not,
    // we set up GS ourselves.
    MOVL    _cgo_init(SB), AX
    TESTL    AX, AX
    JZ    needtls
    MOVL    $setmg_gcc<>(SB), BX
    MOVL    BX, 4(SP)
    MOVL    BP, 0(SP)
    CALL    AX
    // update stackguard after _cgo_init
    MOVL    $runtime·g0(SB), CX
    MOVL    g_stackguard0(CX), AX
    MOVL    AX, g_stackguard(CX)
    // skip runtime·ldt0setup(SB) and tls test after _cgo_init for non-windows
    CMPL runtime·iswindows(SB), $0
    JEQ ok
needtls:
    // skip runtime·ldt0setup(SB) and tls test on Plan 9 in all cases
    CMPL    runtime·isplan9(SB), $1
    JEQ    ok
    // set up %gs
    CALL    runtime·ldt0setup(SB)
    // store through it, to make sure it works
    get_tls(BX)
    MOVL    $0x123, g(BX)
    MOVL    runtime·tls0(SB), AX
    CMPL    AX, $0x123
    JEQ    ok
 
// set up m and g "registers"
get_tls(BX)
LEAL    runtime·g0(SB), CX
MOVL    CX, g(BX)
LEAL    runtime·m0(SB), AX
MOVL    AX, m(BX)
// save m->g0 = g0
MOVL    CX, m_g0(AX)
CALL    runtime·emptyfunc(SB)    // fault if stack check is wrong
// convention is D is always cleared
CLD
CALL    runtime·check(SB)
這段檢查一下運行時函數調用,emptyfunc只有一條ret指令,會當即返回。
 
// saved argc, argv
MOVL    120(SP), AX
MOVL    AX, 0(SP)
MOVL    124(SP), AX
MOVL    AX, 4(SP)
CALL    runtime·args(SB)
CALL    runtime·osinit(SB)
CALL    runtime·hashinit(SB)
CALL    runtime·schedinit(SB)
// create a new goroutine to start program
PUSHL    $runtime·main·f(SB)    // entry
PUSHL    $0    // arg size
ARGSIZE(8)
CALL    runtime·newproc(SB)
ARGSIZE(-1)
POPL    AX
POPL    AX
// start this M
CALL    runtime·mstart(SB)
INT $3
RET
DATA    runtime·main·f+0(SB)/4,$runtime·main(SB)
GLOBL    runtime·main·f(SB),RODATA,$4
1,args在windows下不執行,目前只有在linux下執行
2,osinit會加載一些dll,並設置控制檯和獲取系統信息
3,hashinit在檢測到CPU支持ase和sse指令集時,會優化執行速度。
 
_rt0_go最後調用的幾個C函數都在proc.c裏面,到這裏就容易理解了。追蹤newproc/newproc1能夠發現它先推入goexit後推入main,這說明goexit是在main退出後執行的。在棧裏的表現就好像是goexit調用了main,其實這樣作只是爲了讓main退出後能彈出goexit的地址。因此上文所指的runtime.caller的錯誤信息也就不難理解了。