注释/说明
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