masm汇编语言常用指令 (上)


注释/说明

L : 字面量

R: 内存变量

M: 寄存器

S: 标号

寄存器

在 masm 汇编中, 一般有以下几种寄存器

通用目的寄存器 段寄存器 指令指针寄存器 标志位寄存器
eax cs eip OF
ebx ds SF
ecx es ZF
edx ss CF
esi AF
edi PF
ebp DF
esp IF
TF

通用目的寄存器

eax : 全称为 Accumulator Register(累加器). 在进行乘法和除法时会将其中一部分操作结果自动放在 eax 中, 调用函数时也需要把返回值保存在 eax 中. 因此在执行这些操作时不要用 eax 存储数据

ebx : 全称为 Base Register(基地址寄存器). 一般没什么专门的用途, 常用来充当临时变量或地址

ecx : 全称为 Counter Register(计数寄存器). 一般用来充当计数器, 在循环中的使用较多.

edx : 全称为 Data Register(数据寄存器). edx 常被 eax 用来扩展数位 (例如进行有符号除法时, edx : eax 共同组成被除数, edx 的最高位充当符号位)

esi 和 edi : 全称为 Source Index (源变址寄存器) / The Destination Index (目的变址寄存器). 这两者的区别不是很大, 不过在 CPU 中往往是 esi 读取数据, 而 edi 写入数据. 一般在字符串操作上面的用途较多, 且往往和循环指令 STOS, MOVSB, SCASB 一起出现来完成大量数据的保存, 加载与扫描工作.

ebp : 全称为 Base Pointer (栈基指针寄存器). 在函数调用时常用来作栈底指向栈中的数据, 在整个函数运行的过程中其内部存放的地址不会发生改变. 该寄存器为特殊寄存器, 不能对其进行修改.

esp : 全称为 Stack Pointer (栈顶指针寄存器). 与 ebp 一样与函数调用有关, 且每一次的 push, pop, ret, call 操作时其内部的地址都会发生改变. 该寄存器为特殊寄存器, 不能对其进行修改.

段寄存器

cs : 全称是Code Segement (代码段寄存器).

ds : 全称是Data Segment (数据段寄存器).

es : 全称是Extra(Data) Segment (扩展数据段寄存器)

ss : 全称是Stack Segment (栈段寄存器)

由于我还没能了解段寄存器的作用, 因此只能将完整的名称写上, 后续会补

指令指针寄存器

eip : 全称是Extend Instruction Pointer (扩展指令指针寄存器). 主要用来指向内存中的地址, 以表示接下来应该获取, 解码并执行的指令. 该寄存器也是一种特殊寄存器, 不能对其进行修改.

标志位寄存器

寄存器 功能 全称 标志形式
OF 溢出标志 overflow flag 溢出置1, 否则置0
SF 符号标志 sign flag 正数置0, 负数置1
ZF 零标志 zero flag 结果为0置1, 否则置0
CF 进位标志 carry flag 无符号数最高有效位进位, 或有符号数最高有效位需要借位, 则置1. 否则置0
AF 辅助进位标志 auxiliary carry flag 用以表示加减法做到一半时有没有形成进位/借位,如果有则置1, 否则置0
PF 奇偶标志 parity flag 若结果为1的二进制位个数是偶数则置1, 为奇数置0
DF 方向标志 direction flag 用以代表esi和edi的增减, 置1递减, 指令递增
IF 中断标志 interrupt flag IF置1,响应外部中断,置0则屏蔽外部中断;
TF 陷进标志 trap flag TF置1时,处理器每次只执行一条指令,即单步执行. 置0反之

mov 和 movl

将源操作数的内容复制到目标操作数, 两者必须有一个是寄存器

mov M/R, L/M/R

xchg

交换两个操作数的内容, 两者必须有一个是寄存器

xchg M/R, M/R

add 和 sub

add 为加法指令, sub 为减法指令. 两个操作数必须有一个是寄存器

add M/R, L/M/R
sub M/R, L/M/R

neg

切换操作数的正负号, 即求补码

neg M/R

inc 和 dec

inc 自加指令, dec 自减指令

inc M/R
dec M/R

mul 和 imul

mul 为无符号乘法, imul 为有符号乘法.

mul 的积存储在 edx : eax 中, 其中eax作被乘数, 只支持单个操作数. imul 的积存储在自定义的寄存器中, 被乘数和乘数也可存储在自定义的寄存器中, 最多支持三个操作数.

mul M/R

imul M/R
imul R, L/M/R
imul R, M/R, L

div 和 idiv

div 为无符号除法, idiv 为有符号除法.

div 计算的被除数存储在 edx : eax 中, 除数为自定义的内存变量或寄存器, 商存储在 eax 中, 余数存储在 edx 中. 只支持单操作数

idiv 与 div 差不多. 不过在进行有关负数除法运算时, 需要将 edx 和 eax 全部求补才可进行运算, 否则会出错.

div M/R

idiv M/R

SHL 和 SHR

SHL 和 SHR 为逻辑左移 / 逻辑右移. 每移动 n 位二进制数, 结果扩大 / 缩小原来的 \(2^{n}\) 倍, 注意如果值为负数, 进行逻辑右移后其可能会出错.

shl M/R, L
shr M/R, L

SAL 和 SAR

SAL 和 SLR 为算数左移 / 算术右移. 每移动 n 位二进制数, 结果扩大 / 缩小原来的 \(2^{n}\) 倍, 负数进行算术右移不会像逻辑右移一样出现错误.

sal M/R, L
sar M/R, L

数位扩展

指令 寄存器 大小 扩展到 寄存器 大小
cwd ax 16 dx : ax 32
cdq eax 32 edx : eax 64
cqo rax 64 rdx : rax 128

有了数位扩展指令, 就可以很方便的进行负数的有符号除法.

xor edx, edx
xor eax, eax
		
mov eax, -1
cdq
		
mov ebx, 1
idiv ebx

寄存器结果

eax = FFFFFFFF
edx = 00000000

lea

加载有效地址, 将源操作数的地址加载到目标操作数中. 由于实际地址要在程序运行时才能知道, 因此涉及这些地址的操作应该用 lea 来完成. 该指令的目标操作数必须是寄存器

lea R, M

ptr

用来将数据移动到与之大小不符的另一个区域所需要使用的指令, 例如一个为 4 个字节的 int 内存变量, 若移动到一个其大小为 2 个字节的 ax 寄存器中, 则需要 ptr 进行转换; 或一个为 2 个字节的 int 内存变量, 若移动到一个其大小为 4 个字节的 eax 寄存器中, 也需要 ptr 进行转换. size 必须与 R 的大小相符, 源操作数必须是内存变量

mov R, size ptr M

int x = -1;

__asm
{
    xor eax, eax
        
    mov ax, word ptr x
}

寄存器结果

;转换前的eax
eax = 00000000

;转换后的eax
eax = 0000FFFF

movzx 和 movsx

与 ptr 指令一样, 用来将数据移动到与之大小不符的另一个区域所需要使用的指令, 但是限制没有 ptr 那么多. 扩展的大小视目标操作数大小而定

movzx 的 zx 表示 Zero eXtend , 用 0 来扩展数位, movsx 的 sx 表示 Sign eXtend, 用符号位来扩展数位

movzx R, M/R
movsx R, M/R

offset

offset 看上去也是和 lea 一样用来获取地址的, 不过与 lea 不同的是, offset 获取的是内存变量或标号到数据段数据段的起始地址的距离. 源操作数只能是内存变量或标号. 且 offset 只能获取编译时已知的地址 (如符号常量等)

mov M/R, offset M/S


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM