不同宽度的 MOV
本课属于 Coddy Assembly 学习旅程的“基础知识”单元。第 20 课,共 45 课。
你已经使用过 al(8 位)和 rax(64 位)。不过还有其他大小的寄存器。不同的寄存器可以存储不同数量的数据。
x86-64 寄存器系列:
| 寄存器 | 大小 | 位数 | 使用场景 |
|---|---|---|---|
rax | 8 字节 | 64 位 | 完整数值、地址、系统调用编号 |
eax | 4 字节 | 32 位 | rax 的低半部分 |
ax | 2 字节 | 16 位 | eax 的低半部分 |
al | 1 字节 | 8 位 | ax 的低半部分(位 0-7) |
ah | 1 字节 | 8 位 | ax 的高半部分(位 8-15) |
其他寄存器也遵循相同的模式:
| 64 位 | 32 位 | 16 位 | 8 位(低位) |
|---|---|---|---|
rbx | ebx | bx | bl |
rcx | ecx | cx | cl |
rdx | edx | dx | dl |
rsi | esi | si | sil |
rdi | edi | di | dil |
为什么大小很重要:
移动数据时,源和目标的大小应当匹配。如果大小不匹配,CPU 可能会:
- 只复制部分数据
- 从未知内存中复制额外的字节
- 导致错误
大小匹配示例:
mov rax, 1000 ; 64 位到 64 位(没问题)
mov eax, 1000 ; 32 位到 32 位(没问题)
mov ax, 1000 ; 16 位到 16 位(没问题)
mov al, 5 ; 8 位到 8 位(没问题)大小不匹配时会发生什么:
mov rax, 0x123456789ABC ; 64 位值
mov al, 0xFF ; al 变为 0xFF,rax 的其他位保持不变写入 8 位或 16 位寄存器(al、ah、ax)只会更改这些位,完整寄存器的其余部分保持不变。写入 32 位寄存器则不同:mov eax, 0xFF 会清除第 32 至 63 位,因此 rax 会变成 0xFF。这可能会导致意料之外的结果。
安全规则:
到目前为止,在这门课程中,内存中的所有数据都是 1 字节。这就是为什么你使用 al(而不是 rax)。
移动数据时,寄存器大小必须与内存大小匹配:
- 1 字节内存 → 使用
al、bl、cl等。 - 8 字节内存 → 使用
rax、rbx、rcx等。
你将在第 3 章学习不同的内存大小。
挑战
你已经创建了以下数据地址:
source:包含一个 1 字节的值(5)destination:空闲空间(1 字节)
编写两行汇编代码来完成以下操作:
- 将
source中的值加载到al中 - 将
al中的值存入destination
亲手试试
section .data
msg db 'destination = '
msg_len equ $ - msg
section .bss
digit resb 1
section .text
global _start
_start:
; 学生的代码先运行(从 source 加载,再存入 destination)
%include "solution.asm"
; 从 destination 加载已存储的值
mov al, [destination]
; 保存这个值
mov r12, rax
; 打印 "destination = "
mov rax, 1
mov rdi, 1
mov rsi, msg
mov rdx, msg_len
syscall
; 打印这个值
mov rax, r12
add rax, 48
mov [digit], al
mov rax, 1
mov rdi, 1
mov rsi, digit
mov rdx, 1
syscall
; 退出
mov rax, 60
mov rdi, 0
syscall这节课包含一个小测验。开始学习即可作答,并记录你的进度。
基础知识中的所有课
自己练习: Assembly 在线编辑器