masm 汇编常用指令 (中)

时间:2024-03-01 21:43:47

注释/说明

masm 汇编语言常用指令 (上) : https://www.cnblogs.com/ICeVe/p/14589519.html

L: 立即数

M: 内存变量

R: 寄存器

S: 标号

not

按位进行非运算, 操作数只有一个

not M/R

and

按位与运算

and M/R, L/M/R

or

按位或运算

or M/R, L/M/R

xor

按位异或运算

xor M/R, L/M/R

test 和 cmp

test 和 cmp 都是比较指令. 不过实现方式不同

test 是将两个操作数进行 and 运算, 结果将由标志位寄存器 (如 pf, sf, zf 等) 来判断. test 不会修改两个操作数的值, 也不会让其中一个操作数保存计算结果

cmp 是用目标操作数减去源操作数, 结果将由标志位寄存器 (如 pf, sf, zf 等) 来判断. cmp 同样不会修改两个操作数的值, 也不会让其中一个操作数保存计算结果

test M/R, L/M/R
cmp M/R, L/M/R

跳转指令

无条件跳转 : jmp

即直接跳转, 没有条件

jmp S

有条件跳转

有条件跳转比较绕, 因此判断是否跳转一定要看准标志位寄存器和比较指令, 比较指令决定标志寄存器的状态, 既而决定跳转结果

有符号数与无符号数

标志 指令 描述
of = 1 jo 如果溢出, 则跳转
of = 0 jno 如果不溢出, 则跳转
pf = 1 jp 如果奇偶校验位置1, 则跳转
pf = 0 jnp 如果奇偶校验位置 0, 则跳转
sf = 1 js 如果符号位置 1, 则跳转
sf = 0 jns 如果符号位置 0, 则跳转
zf = 1 je

jz
如果相等, 则跳转

如果为 0, 则跳转
zf = 0 jne

jnz
如果不想等, 则跳转

如果不为 0, 则跳转

有符号数

标志 指令 描述
sf != of jl

jnge
如果小于, 则跳转

如果不大于等于, 则跳转
sf = of jge

jnl
如果大于等于, 则跳转

如果不小于, 则跳转
zf = 1 or sf != of jle

jng
如果小于等于, 则跳转

如果不大于, 则跳转
zf = 0 and sf != of jg

jnle
如果大于, 则跳转

如果不小于或不等于, 则跳转

无符号数

标志 指令 描述
cf = 1 jb

jc

jnae
如果低于, 则跳转

如果进位标志位置 1, 则跳转

如果不高于或不等于, 则跳转
cf = 0 jae

jnb

jnc
如果高于或等于, 则跳转

如果不低于, 则跳转

如果标志不置 1, 则跳转
cf = 1 or zf = 1 jbe

jna
如果低于或等于, 则跳转

如果不高于, 则跳转
cf = 0 and zf = 0 ja

jnbe
如果高于, 则跳转

如果不低于或不等于, 则跳转

loop

即循环指令, ecx 作为计数器, 每执行一次 loop 指令, ecx 都会减 1, 当 ecx 为 0 时跳过 loop 指令, 继续执行下一条指令

loop S

push

将内存变量或寄存器的值压入栈中进行保存, 同时 esp - n. 其中 n 为压栈的字节数

push L/M/R

pop

将压入栈中的内存变量或寄存器的值弹出到指定的 寄存器/内存变量

pop M/R

call

call 可看作是一种跳转指令, 执行 call 指令后会自动跳转到操作数 (一般为标号) 所在的地址上. 同时还会将 call 下方的一条指令的地址压入栈中, 以确保函数执行完毕后能正常运行.

call S

ret

栈顶的值弹出至 eip, 以便函数执行完毕后能正常运行. 该指令不需要操作数 (仅在 stdcall 调用约定下)

ret 

nop

空操作, 不做任何行为

nop

cld

方向标志 (df) 清零, 使程序在执行字符串操作时按从左到右的顺序读取字符 ( 即先从地址较低的位置上读取 ). 该指令不需要操作数

cld

std

方向标志 (df) 置 1, 使程序在执行字符串操作时按从右到左的顺序读取字符 ( 即先从地址较搞的位置上读取 ). 该指令不需要操作数

std

rep

性质和 loop 类似, 也是一种循环指令, ecx 作为 计数器, 当 ecx 为 0 时 rep 结束指令. 常和字符串指令配合使用. rep 后面跟字符串指令.

每执行一次指令, edi / esi 会 + 4

rep opreate

repz / repe

与 rep 相同, 不过需要对标志位寄存器 zf 作判断. 如果 zf 或 ecx 为 0 时 结束指令. 常和字符串指令配合使用. repz / repe 后面跟字符串指令

每执行一次指令, edi 或 esi 会 + 4

repz opreate
repe opreate

repnz / repne

与 repz / repe 相同, 如果 zf 置 1 或 ecx 为 0 时 结束指令. 常和字符串指令配合使用. repz / repne 后面跟字符串指令

每执行一次指令, edi 或 esi 会 + 4

repnz opreate
repne opreate

movs

和 mov 类似, 不过它专门用来将字符从一个地方复制到另一个地方. movs 通常有后缀 (如 b, 字节; w, 字; d, 双字; q, 四字), 用来表示每次复制字符的字节大小. movs 默认由 esi 作为源操作数, edi 为目标操作数, 因此不需要写操作数. esi 和 edi 一般获取的都是字符串的首或字符的地址

movsb
movsw
movsd
movsq

cmps

字符比较指令, 与 cmp 类似, 用目标操作时减去源操作数的字符来判断, 如果在执行 cmps 时若两个字符串中发现字符不同时则结束指令. 由于每次只能比较一个字符, 因此通常和 repnz / repne 配合使用. 默认由 esi 作为源操作数, edi 为目标操作数, 因此不需要写操作数.

cmps 可以像 movs 一样添加后缀 ( 如 b, 字节; w, 字; d, 双字; q, 四字 )

cmpsb
cmpsw
cmpsd
cmpsq

scas

scas 的作用与 cmps 差不多, 不同的是 scas 在执行 scas 时若两个字符串中发现字符相同时则结束指令. 由于每次只能比较一个字符, 因此通常和 repnz / repne 配合使用. 默认由 esi 作为源操作数, edi 为目标操作数, 因此不需要写操作数.

scasb
scasw
scasd
scasq

stos

用来将 eax 中的值复制到由 edi 所表示的内存地址上. 可以与 rep 配合起来用, 实现多个位置的初始化. stos 可以添加后缀 ( 如 b, 字节; w, 字; d, 双字; q, 四字 ) . 默认由 edi 操作数, 因此不需要写操作数.

stosb
stosw
stosd
Stosq

lods

与 stos 相反, 将 esi 所表示的内存地址上的值复制到 eax 中, 不需要与 rep 配合起来用, 因为这样会使 eax 频繁遭到复写. lods 可以添加后缀 ( 如 b, 字节; w, 字; d, 双字; q, 四字 ) . 默认由 esi 操作数, 因此不需要写操作数.

lodsb
lodsw
lodsd
lodsq