Day 5: 数据传送指令本章介绍汇编语言中最基础的指令——数据传送指令。MOV是使用频率最高的指令之一。1. MOV指令1.1 基本用法; MOV 目标, 源 ; 把源的值复制到目标 mov eax, 100 ; 寄存器 ← 立即数 mov eax, ebx ; 寄存器 ← 寄存器 mov eax, [var] ; 寄存器 ← 内存 mov [var], eax ; 内存 ← 寄存器 mov [var], 100 ; 内存 ← 立即数需要指定大小 mov dword [var], 100 ; 不能直接 内存 ← 内存 ; mov [var1], [var2] ; 错误 ; 正确做法 mov eax, [var2] mov [var1], eax1.2 MOV的限制MOV指令的规则 1. 目标和源大小必须匹配 mov eax, bl ; 错误32位←8位 movzx eax, bl ; 正确零扩展 2. 不能内存到内存 mov [a], [b] ; 错误 3. 段寄存器有特殊规则 mov cs, ax ; 错误CS只读 mov ds, ax ; 正确 4. 不能把立即数直接送入段寄存器 mov ds, 0x10 ; 错误 mov ax, 0x10 mov ds, ax ; 正确2. 数据扩展指令2.1 零扩展 MOVZX; MOVZX - Move with Zero Extend ; 高位补0 mov bl, 0xFF ; BL 255 movzx eax, bl ; EAX 0x000000FF 255 movzx ax, bl ; AX 0x00FF ; 常用于无符号数扩展2.2 符号扩展 MOVSX; MOVSX - Move with Sign Extend ; 高位补符号位 mov bl, 0xFF ; BL -1 (有符号) movsx eax, bl ; EAX 0xFFFFFFFF -1 mov bl, 0x7F ; BL 127 movsx eax, bl ; EAX 0x0000007F 127 ; 常用于有符号数扩展2.3 对比示例mov bl, 0x80 ; 二进制1000 0000 movzx eax, bl ; EAX 0x00000080 128 (无符号) movsx eax, bl ; EAX 0xFFFFFF80 -128 (有符号) ; 同样的位模式解释不同3. 交换指令3.1 XCHG; XCHG - 交换两个操作数的值 xchg eax, ebx ; 交换EAX和EBX xchg ax, cx ; 交换AX和CX xchg [var], eax ; 交换内存和寄存器 ; 等价于 ; temp eax ; eax ebx ; ebx temp ; 但XCHG是原子操作3.2 BSWAP; BSWAP - 字节序反转仅32位/64位寄存器 mov eax, 0x12345678 bswap eax ; EAX 0x78563412 ; 用于大小端转换4. LEA指令4.1 基本用法; LEA - Load Effective Address ; 计算地址但不访问内存 lea eax, [ebx 4] ; EAX EBX 4 lea eax, [ebx ecx*4] ; EAX EBX ECX*4 ; 对比MOV mov eax, [ebx 4] ; EAX 内存[EBX4]的值 lea eax, [ebx 4] ; EAX EBX 4 的地址值4.2 LEA的妙用; 快速计算 lea eax, [ebx ebx*2] ; EAX EBX * 3 lea eax, [ebx*4] ; EAX EBX * 4 lea eax, [ebx ebx*4] ; EAX EBX * 5 lea eax, [eax eax*8] ; EAX EAX * 9 ; 一条指令完成多个操作 lea eax, [ebx ecx 10] ; EAX EBX ECX 10 ; 获取变量地址 lea eax, [myVar] ; 等价于 mov eax, offset myVar5. 栈操作指令5.1 PUSH和POP; PUSH - 压栈 push eax ; ESP - 4, [ESP] EAX push 100 ; 压入立即数 push dword [var] ; 压入内存值 ; POP - 出栈 pop eax ; EAX [ESP], ESP 4 pop dword [var] ; 弹出到内存 ; 栈的增长方向高地址 → 低地址 ; PUSH时ESP减小POP时ESP增大5.2 PUSHA/POPA; 32位模式 pushad ; 压入所有通用寄存器 ; 顺序EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI popad ; 弹出所有通用寄存器 ; 用于函数开头/结尾保存/恢复寄存器 ; x64模式下不可用需要手动push/pop5.3 栈操作示例PUSH EAX 前 PUSH EAX 后 ESP指向 - [???] [???] [???] ESP - [EAX] - 新压入的值 [???] [???] 注意栈向低地址增长PUSH后ESP减小6. 条件传送指令6.1 CMOVcc; CMOVcc - Conditional Move ; 根据标志位条件移动避免分支 cmp eax, ebx cmovg ecx, edx ; if (eax ebx) ecx edx cmovl ecx, edx ; if (eax ebx) ecx edx cmove ecx, edx ; if (eax ebx) ecx edx cmovne ecx, edx ; if (eax ! ebx) ecx edx ; 常用条件 ; cmove/cmovz - 相等/零 ; cmovne/cmovnz - 不等/非零 ; cmovg/cmovnle - 大于(有符号) ; cmovl/cmovnge - 小于(有符号) ; cmova/cmovnbe - 大于(无符号) ; cmovb/cmovnae - 小于(无符号)6.2 CMOVcc vs 分支; 传统分支写法 cmp eax, ebx jle skip mov ecx, edx skip: ; 使用CMOVcc cmp eax, ebx cmovg ecx, edx ; CMOVcc优点 ; - 避免分支预测失败 ; - 更短的代码 ; 缺点 ; - 即使条件不满足也会读取源操作数7. 练习题练习1数据传送难度★★☆☆☆把内存变量var1的值复制到var2。练习2LEA计算难度★★☆☆☆用一条LEA指令计算 EAX * 7。练习3交换变量难度★★☆☆☆不使用XCHG用3条MOV指令交换EAX和EBX。8. 小结[MOV指令] 1. MOV 目标, 源 2. 不能内存到内存 3. 大小必须匹配 [扩展指令] 4. MOVZX - 零扩展 5. MOVSX - 符号扩展 [交换指令] 6. XCHG - 交换 7. BSWAP - 字节序反转 [LEA指令] 8. 计算地址不访问内存 9. 可用于快速乘法 [栈操作] 10. PUSH - 压栈ESP减小 11. POP - 出栈ESP增大 [条件传送] 12. CMOVcc - 避免分支下一篇预告Day 6 - 算术运算指令