go plan9汇编入门

语言: CN / TW / HK

原文地址: 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

分享到: