原文地址: https://yuchanns.org/posts/2020/01/31/golang-assembly/

歡迎訪問我的博客 yuchanns'Atelier

有時候我們想要知道寫出來的代碼是怎麼編譯執行的,這時候 go tool compile 就是一個很好用的工具。

本文相關代碼 yuchanns/gobyexample

如何輸出彙編代碼

有三種方法可以輸出go代碼的彙編代碼:

  • go tool compile 生成obj文件
  • go build -gcflags 生成最終二進制文件
  • 先go build然後在go tool objdump 對二進制文件進行反彙編
    當然,具體行爲還需要在這些命令後面加上具體的 flag 。flag的內容可以通過查閱 官方文檔 獲得。

本文涉及Flags說明

-N 禁止優化

-S 輸出彙編代碼

-l 禁止內聯

什麼是內聯

如果學過 c/c++ 就知道,通過 inline 關鍵字修飾的函數叫做內聯函數。內聯函數的優勢是在編譯過程中直接展開函數中的代碼,將其替換到源碼的函數調用位置,這樣可以節省函數調用的消耗,提高運行速度。適用於函數體短小且頻繁調用的函數,如果函數體太大了,會增大目標代碼。是一種空間換時間的做法。

go編譯器會智能判斷對代碼進行優化和使用匯編。而我們在分析學習代碼調用情況的時候需要禁止掉這些優化,避免混淆理解。

以下我們使用 go build -gcflags="-N -l -S" file 來獲得彙編代碼。

獲取一份簡單的彙編代碼

現在手上有一份關於range的代碼,但是我們運行之後出現了一些問題 [1] [2]

package assembly

import "fmt"

func RangeClause() {
    arr := []int{1, 2, 3}
    var newArr []*int
    for _, v := range arr {
        newArr = append(newArr, &v)
    }
    for _, v := range newArr {
        fmt.Println(*v)
    }
}

結果輸出了三個3。

也許我們在學習過程中見過類似的錯誤,然後設法(或者別人告訴我們怎麼)避免錯誤,但是仍然百思不得其解,知其然不知其所以然。

這時候獲取彙編代碼就可以排上用場了。

執行 go build -gcflags="-N -l -S" range_clause.go ,得到下面這份輸出結果:

"".RangeClause STEXT size=842 args=0x0 locals=0x158
        0x0000 00000 (range_clause.go:5)     TEXT    "".RangeClause(SB), ABIInternal, $344-0
        0x0000 00000 (range_clause.go:5)     MOVQ    (TLS), CX
        0x0009 00009 (range_clause.go:5)     LEAQ    -216(SP), AX
        0x0011 00017 (range_clause.go:5)     CMPQ    AX, 16(CX)
        0x0015 00021 (range_clause.go:5)     JLS     832
        0x001b 00027 (range_clause.go:5)     SUBQ    $344, SP
        0x0022 00034 (range_clause.go:5)     MOVQ    BP, 336(SP)
        0x002a 00042 (range_clause.go:5)     LEAQ    336(SP), BP
        0x0032 00050 (range_clause.go:5)     FUNCDATA        $0, gclocals·f0a67958015464e4cc8847ce0df60843(SB)
        0x0032 00050 (range_clause.go:5)     FUNCDATA        $1, gclocals·1be50b3ff1c6bce621b19ced5cafc212(SB)
        0x0032 00050 (range_clause.go:5)     FUNCDATA        $2, gclocals·160a1dd0c9595e8bcf8efc4c6b948d91(SB)
        0x0032 00050 (range_clause.go:5)     FUNCDATA        $3, "".RangeClause.stkobj(SB)
        0x0032 00050 (range_clause.go:6)     PCDATA  $0, $1
        0x0032 00050 (range_clause.go:6)     PCDATA  $1, $0
        0x0032 00050 (range_clause.go:6)     LEAQ    ""..autotmp_9+120(SP), AX
        0x0037 00055 (range_clause.go:6)     PCDATA  $1, $1
        0x0037 00055 (range_clause.go:6)     MOVQ    AX, ""..autotmp_8+152(SP)
        0x003f 00063 (range_clause.go:6)     PCDATA  $0, $0
        0x003f 00063 (range_clause.go:6)     TESTB   AL, (AX)
        0x0041 00065 (range_clause.go:6)     MOVQ    ""..stmp_0(SB), AX
        0x0048 00072 (range_clause.go:6)     MOVQ    AX, ""..autotmp_9+120(SP)
        0x004d 00077 (range_clause.go:6)     MOVUPS  ""..stmp_0+8(SB), X0
        0x0054 00084 (range_clause.go:6)     MOVUPS  X0, ""..autotmp_9+128(SP)
        0x005c 00092 (range_clause.go:6)     PCDATA  $0, $1
        0x005c 00092 (range_clause.go:6)     PCDATA  $1, $0
        0x005c 00092 (range_clause.go:6)     MOVQ    ""..autotmp_8+152(SP), AX
        0x0064 00100 (range_clause.go:6)     TESTB   AL, (AX)
        0x0066 00102 (range_clause.go:6)     JMP     104
        0x0068 00104 (range_clause.go:6)     PCDATA  $0, $0
        0x0068 00104 (range_clause.go:6)     PCDATA  $1, $2
        0x0068 00104 (range_clause.go:6)     MOVQ    AX, "".arr+240(SP)
        0x0070 00112 (range_clause.go:6)     MOVQ    $3, "".arr+248(SP)
        0x007c 00124 (range_clause.go:6)     MOVQ    $3, "".arr+256(SP)
        0x0088 00136 (range_clause.go:7)     PCDATA  $1, $3
        0x0088 00136 (range_clause.go:7)     MOVQ    $0, "".newArr+216(SP)
        0x0094 00148 (range_clause.go:7)     XORPS   X0, X0
        0x0097 00151 (range_clause.go:7)     MOVUPS  X0, "".newArr+224(SP)
        0x009f 00159 (range_clause.go:8)     PCDATA  $0, $1
        0x009f 00159 (range_clause.go:8)     LEAQ    type.int(SB), AX
        0x00a6 00166 (range_clause.go:8)     PCDATA  $0, $0
        0x00a6 00166 (range_clause.go:8)     MOVQ    AX, (SP)
        0x00aa 00170 (range_clause.go:8)     CALL    runtime.newobject(SB)
        0x00af 00175 (range_clause.go:8)     PCDATA  $0, $1
        0x00af 00175 (range_clause.go:8)     MOVQ    8(SP), AX
        0x00b4 00180 (range_clause.go:8)     PCDATA  $0, $0
        0x00b4 00180 (range_clause.go:8)     PCDATA  $1, $4
        0x00b4 00180 (range_clause.go:8)     MOVQ    AX, "".&v+192(SP)
        0x00bc 00188 (range_clause.go:8)     MOVQ    "".arr+256(SP), AX
        0x00c4 00196 (range_clause.go:8)     MOVQ    "".arr+248(SP), CX
        0x00cc 00204 (range_clause.go:8)     PCDATA  $0, $2
        0x00cc 00204 (range_clause.go:8)     PCDATA  $1, $5
        0x00cc 00204 (range_clause.go:8)     MOVQ    "".arr+240(SP), DX
        0x00d4 00212 (range_clause.go:8)     PCDATA  $0, $0
        0x00d4 00212 (range_clause.go:8)     PCDATA  $1, $6
        0x00d4 00212 (range_clause.go:8)     MOVQ    DX, ""..autotmp_5+288(SP)
        0x00dc 00220 (range_clause.go:8)     MOVQ    CX, ""..autotmp_5+296(SP)
        0x00e4 00228 (range_clause.go:8)     MOVQ    AX, ""..autotmp_5+304(SP)
        0x00ec 00236 (range_clause.go:8)     MOVQ    $0, ""..autotmp_10+112(SP)
        0x00f5 00245 (range_clause.go:8)     MOVQ    ""..autotmp_5+296(SP), AX
        0x00fd 00253 (range_clause.go:8)     MOVQ    AX, ""..autotmp_11+104(SP)
        0x0102 00258 (range_clause.go:8)     JMP     260
        0x0104 00260 (range_clause.go:8)     MOVQ    ""..autotmp_11+104(SP), CX
        0x0109 00265 (range_clause.go:8)     CMPQ    ""..autotmp_10+112(SP), CX
        0x010e 00270 (range_clause.go:8)     JLT     277
        0x0110 00272 (range_clause.go:8)     JMP     516
        0x0115 00277 (range_clause.go:8)     MOVQ    ""..autotmp_10+112(SP), CX
        0x011a 00282 (range_clause.go:8)     SHLQ    $3, CX
        0x011e 00286 (range_clause.go:8)     PCDATA  $0, $3
        0x011e 00286 (range_clause.go:8)     ADDQ    ""..autotmp_5+288(SP), CX
        0x0126 00294 (range_clause.go:8)     PCDATA  $0, $0
        0x0126 00294 (range_clause.go:8)     MOVQ    (CX), CX
        0x0129 00297 (range_clause.go:8)     MOVQ    CX, ""..autotmp_12+96(SP)
        0x012e 00302 (range_clause.go:8)     PCDATA  $0, $2
        0x012e 00302 (range_clause.go:8)     MOVQ    "".&v+192(SP), DX
        0x0136 00310 (range_clause.go:8)     PCDATA  $0, $0
        0x0136 00310 (range_clause.go:8)     MOVQ    CX, (DX)
        0x0139 00313 (range_clause.go:9)     PCDATA  $0, $3
        0x0139 00313 (range_clause.go:9)     MOVQ    "".&v+192(SP), CX
        0x0141 00321 (range_clause.go:9)     PCDATA  $0, $0
        0x0141 00321 (range_clause.go:9)     PCDATA  $1, $7
        0x0141 00321 (range_clause.go:9)     MOVQ    CX, ""..autotmp_13+184(SP)
        0x0149 00329 (range_clause.go:9)     MOVQ    "".newArr+232(SP), CX
        0x0151 00337 (range_clause.go:9)     MOVQ    "".newArr+224(SP), DX
        0x0159 00345 (range_clause.go:9)     PCDATA  $0, $4
        0x0159 00345 (range_clause.go:9)     PCDATA  $1, $8
        0x0159 00345 (range_clause.go:9)     MOVQ    "".newArr+216(SP), BX
        0x0161 00353 (range_clause.go:9)     LEAQ    1(DX), SI
        0x0165 00357 (range_clause.go:9)     CMPQ    SI, CX
        0x0168 00360 (range_clause.go:9)     JLS     364
        0x016a 00362 (range_clause.go:9)     JMP     446
        0x016c 00364 (range_clause.go:9)     PCDATA  $0, $-2
        0x016c 00364 (range_clause.go:9)     PCDATA  $1, $-2
        0x016c 00364 (range_clause.go:9)     JMP     366
        0x016e 00366 (range_clause.go:9)     PCDATA  $0, $5
        0x016e 00366 (range_clause.go:9)     PCDATA  $1, $9
        0x016e 00366 (range_clause.go:9)     MOVQ    ""..autotmp_13+184(SP), AX
        0x0176 00374 (range_clause.go:9)     PCDATA  $0, $6
        0x0176 00374 (range_clause.go:9)     LEAQ    (BX)(DX*8), DI
        0x017a 00378 (range_clause.go:9)     PCDATA  $0, $-2
        0x017a 00378 (range_clause.go:9)     PCDATA  $1, $-2
        0x017a 00378 (range_clause.go:9)     CMPL    runtime.writeBarrier(SB), $0
        0x0181 00385 (range_clause.go:9)     JEQ     389
        0x0183 00387 (range_clause.go:9)     JMP     439
        0x0185 00389 (range_clause.go:9)     MOVQ    AX, (BX)(DX*8)
        0x0189 00393 (range_clause.go:9)     JMP     395
        0x018b 00395 (range_clause.go:9)     PCDATA  $0, $0
        0x018b 00395 (range_clause.go:9)     PCDATA  $1, $6
        0x018b 00395 (range_clause.go:9)     MOVQ    BX, "".newArr+216(SP)
        0x0193 00403 (range_clause.go:9)     MOVQ    SI, "".newArr+224(SP)
        0x019b 00411 (range_clause.go:9)     MOVQ    CX, "".newArr+232(SP)
        0x01a3 00419 (range_clause.go:9)     JMP     421
        0x01a5 00421 (range_clause.go:8)     MOVQ    ""..autotmp_10+112(SP), CX
        0x01aa 00426 (range_clause.go:8)     INCQ    CX
        0x01ad 00429 (range_clause.go:8)     MOVQ    CX, ""..autotmp_10+112(SP)
        0x01b2 00434 (range_clause.go:8)     JMP     260
        0x01b7 00439 (range_clause.go:9)     PCDATA  $0, $-2
        0x01b7 00439 (range_clause.go:9)     PCDATA  $1, $-2
        0x01b7 00439 (range_clause.go:9)     CALL    runtime.gcWriteBarrier(SB)
        0x01bc 00444 (range_clause.go:9)     JMP     395
        0x01be 00446 (range_clause.go:9)     PCDATA  $0, $4
        0x01be 00446 (range_clause.go:9)     PCDATA  $1, $8
        0x01be 00446 (range_clause.go:9)     MOVQ    DX, ""..autotmp_21+64(SP)
        0x01c3 00451 (range_clause.go:9)     PCDATA  $0, $5
        0x01c3 00451 (range_clause.go:9)     LEAQ    type.*int(SB), AX
        0x01ca 00458 (range_clause.go:9)     PCDATA  $0, $4
        0x01ca 00458 (range_clause.go:9)     MOVQ    AX, (SP)
        0x01ce 00462 (range_clause.go:9)     PCDATA  $0, $0
        0x01ce 00462 (range_clause.go:9)     MOVQ    BX, 8(SP)
        0x01d3 00467 (range_clause.go:9)     MOVQ    DX, 16(SP)
        0x01d8 00472 (range_clause.go:9)     MOVQ    CX, 24(SP)
        0x01dd 00477 (range_clause.go:9)     MOVQ    SI, 32(SP)
        0x01e2 00482 (range_clause.go:9)     CALL    runtime.growslice(SB)
        0x01e7 00487 (range_clause.go:9)     PCDATA  $0, $4
        0x01e7 00487 (range_clause.go:9)     MOVQ    40(SP), BX
        0x01ec 00492 (range_clause.go:9)     MOVQ    48(SP), AX
        0x01f1 00497 (range_clause.go:9)     MOVQ    56(SP), CX
        0x01f6 00502 (range_clause.go:9)     LEAQ    1(AX), SI
        0x01fa 00506 (range_clause.go:9)     MOVQ    ""..autotmp_21+64(SP), DX
        0x01ff 00511 (range_clause.go:9)     JMP     366
        0x0204 00516 (range_clause.go:11)    PCDATA  $0, $0
        0x0204 00516 (range_clause.go:11)    PCDATA  $1, $10
        0x0204 00516 (range_clause.go:11)    MOVQ    "".newArr+232(SP), AX
        0x020c 00524 (range_clause.go:11)    MOVQ    "".newArr+224(SP), CX
        0x0214 00532 (range_clause.go:11)    PCDATA  $0, $2
        0x0214 00532 (range_clause.go:11)    PCDATA  $1, $0
        0x0214 00532 (range_clause.go:11)    MOVQ    "".newArr+216(SP), DX
        0x021c 00540 (range_clause.go:11)    PCDATA  $0, $0
        0x021c 00540 (range_clause.go:11)    PCDATA  $1, $11
        0x021c 00540 (range_clause.go:11)    MOVQ    DX, ""..autotmp_6+264(SP)
        0x0224 00548 (range_clause.go:11)    MOVQ    CX, ""..autotmp_6+272(SP)
        0x022c 00556 (range_clause.go:11)    MOVQ    AX, ""..autotmp_6+280(SP)
        0x0234 00564 (range_clause.go:11)    MOVQ    $0, ""..autotmp_14+88(SP)
        0x023d 00573 (range_clause.go:11)    MOVQ    ""..autotmp_6+272(SP), AX
        0x0245 00581 (range_clause.go:11)    MOVQ    AX, ""..autotmp_15+80(SP)
        0x024a 00586 (range_clause.go:11)    JMP     588
        0x024c 00588 (range_clause.go:11)    MOVQ    ""..autotmp_15+80(SP), AX
        0x0251 00593 (range_clause.go:11)    CMPQ    ""..autotmp_14+88(SP), AX
        0x0256 00598 (range_clause.go:11)    JLT     605
        0x0258 00600 (range_clause.go:11)    JMP     816
        0x025d 00605 (range_clause.go:11)    MOVQ    ""..autotmp_14+88(SP), AX
        0x0262 00610 (range_clause.go:11)    SHLQ    $3, AX
        0x0266 00614 (range_clause.go:11)    PCDATA  $0, $1
        0x0266 00614 (range_clause.go:11)    ADDQ    ""..autotmp_6+264(SP), AX
        0x026e 00622 (range_clause.go:11)    MOVQ    (AX), AX
        0x0271 00625 (range_clause.go:11)    MOVQ    AX, ""..autotmp_16+176(SP)
        0x0279 00633 (range_clause.go:11)    MOVQ    AX, "".v+144(SP)
        0x0281 00641 (range_clause.go:12)    TESTB   AL, (AX)
        0x0283 00643 (range_clause.go:12)    PCDATA  $0, $0
        0x0283 00643 (range_clause.go:12)    MOVQ    (AX), AX
        0x0286 00646 (range_clause.go:12)    MOVQ    AX, ""..autotmp_17+72(SP)
        0x028b 00651 (range_clause.go:12)    MOVQ    AX, (SP)
        0x028f 00655 (range_clause.go:12)    CALL    runtime.convT64(SB)
        0x0294 00660 (range_clause.go:12)    PCDATA  $0, $1
        0x0294 00660 (range_clause.go:12)    MOVQ    8(SP), AX
        0x0299 00665 (range_clause.go:12)    PCDATA  $0, $0
        0x0299 00665 (range_clause.go:12)    PCDATA  $1, $12
        0x0299 00665 (range_clause.go:12)    MOVQ    AX, ""..autotmp_18+168(SP)
        0x02a1 00673 (range_clause.go:12)    PCDATA  $1, $13
        0x02a1 00673 (range_clause.go:12)    XORPS   X0, X0
        0x02a4 00676 (range_clause.go:12)    MOVUPS  X0, ""..autotmp_7+200(SP)
        0x02ac 00684 (range_clause.go:12)    PCDATA  $0, $1
        0x02ac 00684 (range_clause.go:12)    PCDATA  $1, $12
        0x02ac 00684 (range_clause.go:12)    LEAQ    ""..autotmp_7+200(SP), AX
        0x02b4 00692 (range_clause.go:12)    MOVQ    AX, ""..autotmp_20+160(SP)
        0x02bc 00700 (range_clause.go:12)    TESTB   AL, (AX)
        0x02be 00702 (range_clause.go:12)    PCDATA  $0, $7
        0x02be 00702 (range_clause.go:12)    PCDATA  $1, $11
        0x02be 00702 (range_clause.go:12)    MOVQ    ""..autotmp_18+168(SP), CX
        0x02c6 00710 (range_clause.go:12)    PCDATA  $0, $8
        0x02c6 00710 (range_clause.go:12)    LEAQ    type.int(SB), DX
        0x02cd 00717 (range_clause.go:12)    PCDATA  $0, $7
        0x02cd 00717 (range_clause.go:12)    MOVQ    DX, ""..autotmp_7+200(SP)
        0x02d5 00725 (range_clause.go:12)    PCDATA  $0, $1
        0x02d5 00725 (range_clause.go:12)    MOVQ    CX, ""..autotmp_7+208(SP)
        0x02dd 00733 (range_clause.go:12)    TESTB   AL, (AX)
        0x02df 00735 (range_clause.go:12)    JMP     737
        0x02e1 00737 (range_clause.go:12)    MOVQ    AX, ""..autotmp_19+312(SP)
        0x02e9 00745 (range_clause.go:12)    MOVQ    $1, ""..autotmp_19+320(SP)
        0x02f5 00757 (range_clause.go:12)    MOVQ    $1, ""..autotmp_19+328(SP)
        0x0301 00769 (range_clause.go:12)    PCDATA  $0, $0
        0x0301 00769 (range_clause.go:12)    MOVQ    AX, (SP)
        0x0305 00773 (range_clause.go:12)    MOVQ    $1, 8(SP)
        0x030e 00782 (range_clause.go:12)    MOVQ    $1, 16(SP)
        0x0317 00791 (range_clause.go:12)    CALL    fmt.Println(SB)
        0x031c 00796 (range_clause.go:12)    JMP     798
        0x031e 00798 (range_clause.go:11)    MOVQ    ""..autotmp_14+88(SP), AX
        0x0323 00803 (range_clause.go:11)    INCQ    AX
        0x0326 00806 (range_clause.go:11)    MOVQ    AX, ""..autotmp_14+88(SP)
        0x032b 00811 (range_clause.go:11)    JMP     588
        0x0330 00816 (<unknown line number>)    PCDATA  $1, $0
        0x0330 00816 (<unknown line number>)    MOVQ    336(SP), BP
        0x0338 00824 (<unknown line number>)    ADDQ    $344, SP
        0x033f 00831 (<unknown line number>)    RET
        0x0340 00832 (<unknown line number>)    NOP
        0x0340 00832 (range_clause.go:5)     PCDATA  $1, $-1
        0x0340 00832 (range_clause.go:5)     PCDATA  $0, $-1
        0x0340 00832 (range_clause.go:5)     CALL    runtime.morestack_noctxt(SB)
        0x0345 00837 (range_clause.go:5)     JMP     0

看着輸出結果,很cool~~~但是看不懂:(

彙編的簡單知識

go使用的彙編叫做 plan9彙編 。最初go是在plan9系統上開發的,後來纔在Linux和Mac上實現。

關於plan9彙編的入門,推薦看這個視頻: plan9彙編入門|go夜讀

寄存器

寄存器是CPU內部用來存放數據的一些小型存儲區域,用來暫時存放參與運算的數據和運算結果。

助記符 名字 用途
AX 累加寄存器(AccumulatorRegister) 用於存放數據,包括算術、操作數、結果和臨時存放地址
BX 基址寄存器(BaseRegister) 用於存放訪問存儲器時的地址
CX 計數寄存器(CountRegister) 用於保存計算值,用作計數器
DX 數據寄存器(DataRegister) 用於數據傳遞,在寄存器間接尋址中的I/O指令中存放I/O端口的地址
SP 堆棧頂指針(StackPointer) 如果是 symbol+offset(SP) 的形式表示go彙編的僞寄存器;如果是 offset(SP) 的形式表示硬件寄存器
BP 堆棧基指針(BasePointer) 保存在進入函數前的棧頂基址
SB 靜態基指針(StaticBasePointer) go彙編的僞寄存器。 foo(SB) 用於表示變量在內存中的地址, foo+4(SB) 表示foo起始地址往後偏移四字節。一般用來聲明函數或全局變量
FP 棧幀指針(FramePointer) go彙編的僞寄存器。引用函數的輸入參數,形式是 symbol+offset(FP) ,例如 arg0+0(FP)
SI 源變址寄存器(SourceIndex) 用於存放源操作數的偏移地址
DI 目的寄存器(DestinationIndex) 用於存放目的操作數的偏移地址

操作指令

用於指導彙編如何進行。以下指令後綴<mark>Q</mark>說明是64位上的彙編指令。

助記符 指令種類 用途 示例
MOVQ 傳送 數據傳送 MOVQ 48, AX 表示把48傳送AX中
LEAQ 傳送 地址傳送 LEAQ AX, BX 表示把AX有效地址傳送到BX中
PUSHQ 傳送 棧壓入 PUSHQ AX 表示先修改棧頂指針,將AX內容送入新的棧頂位置 在go彙編中使用 SUBQ 代替
POPQ 傳送 棧彈出 POPQ AX 表示先彈出棧頂的數據,然後修改棧頂指針 在go彙編中使用 ADDQ 代替
ADDQ 運算 相加並賦值 ADDQ BX, AX 表示BX和AX的值相加並賦值給AX
SUBQ 運算 相減並賦值 略,同上
IMULQ 運算 無符號乘法 略,同上
IDIVQ 運算 無符號除法 IDIVQ CX 除數是CX,被除數是AX,結果存儲到AX中
CMPQ 運算 對兩數相減,比較大小 CMPQ SI CX 表示比較SI和CX的大小。與SUBQ類似,只是不返回相減的結果
CALL 轉移 調用函數 CALL runtime.printnl(SB) 表示通過<mark>printnl</mark>函數的內存地址發起調用
JMP 轉移 無條件轉移指令 JMP 389 無條件轉至 0x0185 地址處(十進制389轉換成十六進制0x0185)
JLS 轉移 條件轉移指令 JLS 389 上一行的比較結果,左邊小於右邊則執行跳到 0x0185 地址處(十進制389轉換成十六進制0x0185)

可以看到,表中的 PUSHQPOPQ 被去掉了,這是因爲在go彙編中,對棧的操作並不是出棧入棧,而是通過對SP進行運算來實現的。

標誌位

助記符 名字 用途
OF 溢出 0爲無溢出 1爲溢出
CF 進位 0爲最高位無進位或錯位 1爲有
PF 奇偶 0表示數據最低8位中1的個數爲奇數,1則表示1的個數爲偶數
AF 輔助進位
ZF 0表示結果不爲0 1表示結果爲0
SF 符號 0表示最高位爲0 1表示最高位爲1

這麼一通信息轟炸下來,作爲初學者可能已經頭暈腦脹記不住了,其實是否記住這並不重要——後面分析用到了再回來查閱意思即可。

分析彙編代碼

從1+1開始

“好了,現在我們已經學會了加減乘除四則運算,接下來我們來解答一下這道微積分的題目”XD

下面內容查看 原文>> yuchanns'Atelier

相關文章