Masm64:加法、减法、自增自减指令

1. 基本加法指令:ADD Dest, Src

功能:执行两个操作数的加法运算。操作数可以是寄存器与寄存器、寄存器与内存单元或者立即数与寄存器/内存单元之间的操作。

寄存器+寄存器:add rax, rbx,将RBX寄存器的值加到RAX寄存器的值上,结果保存在RAX寄存器中。

寄存器+内存:add rax, myVar指令会把变量myVar的值加到RAX寄存器的值上,结果保存在RAX寄存器中。

寄存器+立即数add rax, 10,把十进制数10加到RAX寄存器的值上,结果保存在RAX寄存器中。

对标志寄存器的影响:

零标志(ZF):如果加法运算的结果为0,则ZF被置为1,否则为0。例如,执行add rax, - rax后,若结果为0,ZF标志将被设置为1。

符号标志(SF):如果结果为负数(对于有符号数运算),则SF被置为1,否则为0。例如,执行add rax, rbx(假设rax和rbx的值使得结果为负数),如果将其视为有符号数运算,SF标志将根据结果的符号进行设置。

进位标志(CF):在无符号数加法运算中,如果相加结果产生进位(超出操作数的无符号数表示范围),则CF被置为1,否则为0。例如,对于8位无符号数,范围是0 - 255,如果两个数相加结果超过255,CF标志将被设置为1。

溢出标志(OF):在有符号数加法运算中,如果结果超出了有符号数的表示范围,则OF被置为1。例如,对于8位有符号数,范围是 - 128到127,如果两个正数相加结果超过127或者两个负数相加结果小于 - 128,OF标志将被设置为1。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    result QWORD ?
.CODE
main PROC
    mov rax, 50
    mov rbx, 30
    add rax, rbx ; 将rbx的值加到rax上,结果保存在rax中
    mov result, rax
    xor rax, rax
    inc rax
    call ExitProcess
main ENDP
END main

2. 带进位加法指令:ADC Dest, Src

功能:与ADD指令类似,但在执行加法运算时要考虑进位标志CF的值,即执行加法操作时加上CF的值。

adc rax, rbx,它相当于rax = rax + rbx+CF。该指令主要用于多字节或多字的加法运算,在计算高字节或高字部分时,需要考虑低字节或低字部分加法运算产生的进位情况。

对标志寄存器的影响:

对标志寄存器的影响与ADD指令类似,会根据运算结果设置ZF、SF、CF和OF等标志位。例如,在多字节加法运算中,如果低字节相加产生进位(CF = 1),在高字节相加时执行adc指令,会将这个进位考虑进去,并且根据高字节相加的结果设置相应的标志位。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    num1 QWORD 0FFFF0000h
    num2 QWORD 0FFFFh
    result QWORD ?
.CODE
main PROC
    mov rax, num1
    mov rbx, num2
    add rax, rbx ; 先进行低32位加法
    mov rcx, 0
    adc rcx, 0 ; 考虑进位进行高32位加法
    mov result, rcx
    shl result, 32
    or result, rax
    xor rax, rax
    inc rax
    call ExitProcess
main ENDP
END main

3. 自加1指令:INC指令(类似C++)

功能:用于将操作数的值加1。操作数可以是寄存器或者内存单元。

寄存器+1:inc rax,将RAX寄存器的值加1。

内存单元+1:inc myCounter指令将变量myCounter的值加1。

对标志寄存器的影响:

零标志(ZF):如果加1后的结果为0,则ZF被置为1,否则为0。例如,执行inc rax(假设rax初始值为 - 1)后,若结果为0,ZF标志将被设置为1。

符号标志(SF):根据加1后的结果符号(对于有符号数)设置SF标志。例如,如果RAX寄存器初始值为127,执行inc rax后,结果为128(对于8位有符号数超出范围),SF标志将被设置为1。

不影响进位标志CF,因为它不是普通的加法操作,而是固定的加1操作。

溢出标志OF:在有符号数加1操作中,如果结果超出有符号数的表示范围,则OF被置为1。例如,对于8位有符号数,范围是 - 128到127,如果初始值为127,执行inc指令后,结果超出范围,OF标志将被设置为1。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    myVar QWORD 10
    result QWORD ?
.CODE
main PROC
    mov rax, myVar
    inc rax ; 将rax的值加1
    mov result, rax
    xor rax, rax
    inc rax
    call ExitProcess
main ENDP
END main

4. 基本减法指令:SUB Dest, Src

功能:用于执行两个操作数的减法运算。操作数可以是寄存器与寄存器、寄存器与内存单元或者立即数与寄存器/内存单元之间的操作。

寄存器与寄存器相减:sub rax, rbx,该指令将RBX寄存器的值从RAX寄存器的值中减去,结果保存在RAX寄存器中。

寄存器与内存相减:假设在数据段中定义了变量myVar QWORD ?,可以使用sub rax, myVar指令将变量myVar的值从RAX寄存器的值中减去,结果保存在RAX寄存器中。

立即数与寄存器相减:sub rax, 10,将十进制数10从RAX寄存器的值中减去,结果保存在RAX寄存器中。

对标志寄存器的影响:

零标志(ZF):如果减法运算的结果为0,则ZF被置为1,否则为0。例如,执行sub rax, rax后,ZF标志将被设置为1。

符号标志(SF):如果结果为负数(对于有符号数运算),则SF被置为1,否则为0。例如,执行sub rax, rbx(假设rax小于rbx),如果将其视为有符号数运算,SF标志将根据结果的符号进行设置。

进位标志(CF):在无符号数减法运算中,如果被减数小于减数(产生借位),则CF被置为1,否则为0。例如,执行sub al, bl(假设al小于bl且将其视为无符号数),CF标志将被设置为1。

溢出标志(OF):在有符号数减法运算中,如果结果超出了有符号数的表示范围,则OF被置为1,例如,对于8位有符号数,范围是 - 128到127,如果两个数相减的结果超出这个范围,OF标志将被设置为1。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    result QWORD ?
.CODE
main PROC
    mov rax, 100
    mov rbx, 30
    sub rax, rbx ; 将rbx的值从rax中减去,结果保存在rax中
    mov result, rax
    xor rax, rax
    inc rax
    call ExitProcess
main ENDP
END main

5. 带借位减法指令:SBB Dest, Src

功能:与SUB指令类似,但在执行减法运算时要考虑进位标志CF的值,即执行减法操作时减去CF的值。

sbb rax, rbx,它相当于rax = rax - rbx - CF。该指令主要用于多字节或多字的减法运算,在计算高字节或高字部分时,需要考虑低字节或低字部分减法运算产生的借位情况。

对标志寄存器的影响:

对标志寄存器的影响与SUB指令类似,会根据运算结果设置ZF、SF、CF和OF等标志位。例如,在多字节减法运算中,如果低字节相减产生借位(CF = 1),在高字节相减时执行sbb指令,会将这个借位考虑进去,并且根据高字节相减的结果设置相应的标志位。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    num1 QWORD 0FFFF0000h
    num2 QWORD 0FFFFh
    result QWORD ?
.CODE
main PROC
    mov rax, num1
    mov rbx, num2
    sub rax, rbx ; 先进行低32位减法
    mov rcx, 0
    sbb rcx, 0 ; 考虑借位进行高32位减法
    mov result, rcx
    shl result, 32
    or result, rax
    xor rax, rax
    inc rax
    call ExitProcess
main ENDP
END main

6. 自减1指令:DEC指令(类似C--)

功能:用于将操作数的值减1。操作数可以是寄存器或者内存单元。

寄存器减1:dec rax,将RAX寄存器的值减1。

内存单元减1:假设存在变量myCounter QWORD ?,可以使用dec myCounter指令将变量myCounter的值减1。

对标志寄存器的影响

零标志(ZF):如果减1后的结果为0,则ZF被置为1,否则为0。例如,执行dec rax(假设rax初始值为1)后,ZF标志将被设置为1。

符号标志(SF):根据减1后的结果符号(对于有符号数)设置SF标志。例如,如果RAX寄存器初始值为0,执行dec rax后,结果为 - 1(对于有符号数),SF标志将被设置为1。

不影响进位标志CF,因为它不是普通的减法操作,而是固定的减1操作。

溢出标志OF:在有符号数减1操作中,如果结果超出有符号数的表示范围,则OF被置为1。例如,对于8位有符号数,范围是 - 128到127,如果初始值为 - 128,执行dec指令后,结果超出范围,OF标志将被设置为1。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    myVar QWORD 10
    result QWORD ?
.CODE
main PROC
    mov rax, myVar
    dec rax ; 将rax的值减1
    mov result, rax
    xor rax, rax
    inc rax
    call ExitProcess
main ENDP
END main

7. NEG求补运算指令

功能:用于对操作数进行求补运算。求补运算的本质是用0减去操作数,这等同于将操作数按位取反后再加1。例如,如果操作数是8位的01000000(十进制64),按位取反得到10111111,再加1变为11000000(十进制 - 64)。

操作数可以是寄存器或者内存单元。

对于寄存器操作:neg rax,该指令将对RAX寄存器中的值进行求补运算,结果仍保存在RAX寄存器中。

对于内存操作:neg myVar指令会对变量myVar的值进行求补运算,结果存储回myVar变量中。

对标志位的影响

进位标志(CF):如果操作数为0,执行NEG指令后,CF被清为0。因为0的求补运算结果还是0,没有产生进位。

如果操作数不为0,执行NEG指令后,CF被置为1。这是因为求补运算相当于0减去一个非零数,必然会产生借位(在无符号数的概念下相当于进位)。

溢出标志(OF):当操作数为最小的负数(例如8位有符号数中的 - 128,16位有符号数中的 - 32768等)时,执行NEG指令会产生溢出,OF被置为1。因为最小负数的绝对值已经超出了该数据类型所能表示的正数范围。

在其他情况下,如果求补运算结果没有超出有符号数的表示范围,OF被清为0。

零标志(ZF):如果求补运算的结果为0,ZF被置为1。例如,对0执行NEG指令,结果还是0,此时ZF = 1。

如果结果不为0,ZF被清为0。

符号标志(SF):求补运算后,结果的符号位会反映在SF标志上。如果结果为负数(最高位为1),SF被置为1;如果结果为正数(最高位为0),SF被清为0。

辅助进位标志(AF):在8位或16位的求补运算中,如果低4位向高4位产生借位(在求补运算相当于0减去操作数的过程中),AF被置为1。

如果没有这种低4位向高4位的借位情况,AF被清为0。

奇偶标志(PF):根据求补运算结果中1的个数的奇偶性来设置。如果结果中1的个数为偶数,PF被置为1;如果结果中1的个数为奇数,PF被清为0。

.686p
.MODEL flat, stdcall
.STACK 4096
include windows.inc
include kernel32.inc
includelib kernel32.lib
.DATA
    myVar QWORD 10
    result QWORD?
.CODE
main PROC
    mov rax, myVar
    neg rax ; 对rax中的值(10)求补,结果为 - 10,保存在rax中
    mov result, rax
    xor rax, rax
    inc rax
    call ExitProcess
    main ENDP
END main

在这个示例中,首先将变量myVar的值(10)赋给RAX寄存器,然后使用NEG指令对RAX中的值求补,得到 - 10,最后将结果存储到result变量中。

64位汇编语言基础