仅用于个人复习计算机基础一、核心概览这份文档的核心是讲解如何在不同位置寄存器、内存之间移动数据以及移动时如何处理数据的大小和符号问题。关键在于理解“数据大小”和“符号扩展/零扩展”这两个概念。二、通用数据传送指令详解1. MOV 指令族基本传送功能将数据从源操作数S复制到目的操作数D。关键规则大小必须匹配指令后缀b-字节,w-字/2字节,l-双字/4字节,q-四字/8字节必须与操作数尤其是寄存器部分的大小匹配。例如%eax是32位寄存器必须用movl。两个操作数不能同时是内存地址数据不能直接从内存的一个位置复制到另一个位置必须通过寄存器中转。movl的特殊行为当目的操作数是寄存器时movl不仅会写入低32位还会自动将该寄存器的高32位清零。这是x86-64架构的规定确保32位操作的结果在64位环境中是干净的。示例分析movabsq $0x0011223344556677, %rax # 初始化 rax 0x0011223344556677 movb $0xFF, %al # 只改变 al (最低1字节)。rax 0x00112233445566FF movw $0xFFFF, %ax # 只改变 ax (低2字节)。rax 0x001122334455FFFF movl $0xFFFFFFFF, %eax # 改变 eax (低4字节)并清零高32位。rax 0x00000000FFFFFFFF movq $0xFFFFFFFF, %rax # 改变整个rax (8字节)。注意立即数0xFFFFFFFF会被符号扩展为0xFFFFFFFFFFFFFFFFmovabsq这是movq的一个特例用于传送任意的64位立即数到寄存器。普通的movq指令只能传送可以表示为32位补码的立即数然后符号扩展为64位。2. MOVZ 指令族零扩展传送功能将较小的源操作数复制到较大的目的寄存器并用0填充目的寄存器中剩余的高位。适用场景处理无符号数的类型提升例如C语言中将unsigned char赋值给unsigned int。命名规则movzxy其中x是源大小y是目的大小。例如movzbw零扩展字节(b)到字(w)。movzwl零扩展字(w)到双字(l)。movzbq零扩展字节(b)到四字(q)。movzwq零扩展字(w)到四字(q)。注意没有movzlq32位零扩展到64位指令因为movl指令在以寄存器为目的时其“清零高32位”的行为已经等效于零扩展。3. MOVS 指令族符号扩展传送功能将较小的源操作数复制到较大的目的寄存器并用源操作数的符号位最高位的副本填充目的寄存器中剩余的高位。适用场景处理有符号数的类型提升例如C语言中将signed char赋值给int。命名规则movsxy规则同MOVZ。例如movsbq符号扩展字节(b)到四字(q)。movslq符号扩展双字(l)到四字(q)。特殊指令cltq这是一个无操作数的专用指令功能等同于movslq %eax, %rax。它将%eax32位中的有符号整数符号扩展到%rax64位中。对比示例movabsq $0x0011223344556677, %rax # rax 0x0011223344556677 movb $0xAA, %dl # dl 0xAA (二进制10101010最高位为1是负数) movb %dl, %al # 仅复制字节不改变高位。rax 0x00112233445566AA movsbq %dl, %rax # 符号扩展源字节最高位是1高位全补1。rax 0xFFFFFFFFFFFFFFAA movzbq %dl, %rax # 零扩展无论源值是什么高位全补0。rax 0x00000000000000AA三、指针操作在汇编中的体现文档通过一个exchange函数的例子展示了C语言指针操作如何对应到汇编指令。C代码long exchange(long *xp, long y) { long x *xp; // 指针解引用读内存 *xp y; // 指针解引用写内存 return x; }对应汇编代码exchange: movq (%rdi), %rax # 1. 从 xp (%rdi) 指向的内存地址读取8字节到 %rax (实现 x *xp) movq %rsi, (%rdi) # 2. 将 y (%rsi) 的值写入 xp (%rdi) 指向的内存地址 (实现 *xp y) ret # 3. 返回返回值已放在 %rax 中 (即 x)关键理解指针就是地址指针变量xp的值一个内存地址被存放在寄存器%rdi中。解引用就是内存访问C语言中的*xp操作在汇编中体现为使用括号的间接寻址(%rdi)。局部变量常驻寄存器为了提高效率像x这样的局部变量通常保存在寄存器这里是%rax中而不是内存中。四、栈操作指令PUSH/POP文档末尾提到了栈操作虽然未展开但这是数据传送的重要应用场景。栈程序运行时管理函数调用和局部变量的一块内存区域特点是“后进先出”(LIFO)。栈指针寄存器%rsp始终指向栈顶。pushq S将数据S压入栈。等效操作%rsp %rsp - 8; *(%rsp) S;先下移栈指针开辟空间再存入数据。popq D从栈顶弹出数据到D。等效操作D *(%rsp); %rsp %rsp 8;先取出数据再上移栈指针释放空间。五、文档中的练习与要点类型转换与指令选择文档中的表格练习要求根据源类型和目的类型选择正确的mov、movs或movz指令。核心原则是先处理大小变化再根据源类型的符号性有符号/无符号决定使用符号扩展(MOVS)还是零扩展(MOVZ)。movl的隐含零扩展这是x86-64的关键特性。当你在C语言中将一个32位int赋值给64位long时编译器生成的movl指令会自动保证高32位为0符合无符号扩展的语义如果源是无符号整数则结果正确如果是有符号整数则相当于先进行了符号扩展到32位再零扩展到64位需要注意符号位在32位以内已正确表示。总结这份文档系统地阐述了x86-64中数据移动的机制MOV用于等尺寸数据移动注意movl会清零高位。MOVZ用于无符号数的小转大高位补0。MOVS用于有符号数的小转大高位补符号位。指针操作在机器级就是地址加载和内存访问。栈操作是特殊的内存读写由%rsp管理。