MOD_RM字节中Disp8与Disp32的区别及相关指令疑问解析
关于x86 MOD/RM字节与位移寻址的问题解答
1. Disp8 和 Disp32 的核心区别
Disp(Displacement,位移量)就是在寄存器寻址基础上额外加上的偏移值,两者的核心区别体现在两点:
- 数值范围:Disp8是8位有符号整数,覆盖范围是
-128 ~ 127;Disp32是32位有符号整数,范围能到-2^31 ~ 2^31-1,可以支持大得多的偏移需求。 - 指令编码长度:Disp8在机器码里只占1个字节,Disp32要占4个字节。编译器通常会优先用Disp8来缩短指令长度,只有当偏移量超出Disp8范围时才会切换到Disp32。
2. 各ATT语法mov指令的位移类型解析
先明确ATT语法中内存操作数的格式:位移(%基址寄存器, %变址寄存器, 比例因子),我们逐个拆解:
movb $1, (%eax):没有位移量,对应MOD字段的00模式,属于无位移的寄存器间接寻址,不涉及Disp8或Disp32。movw $1, 2(%eax):位移量2在Disp8的范围内,编译器会用**Disp8(MOD=01)**来编码这个位移。movl $1, (%eax, %eax):无位移量,是基址+变址的寻址模式,对应MOD字段00,不涉及Disp8/Disp32。movq $1, 2(%eax, %eax):位移量2在Disp8范围内,对应Disp8(MOD=01)。movq $1, 2(%rax, %rdi):位移量2在Disp8范围内,对应Disp8(MOD=01)。movq $1, 2(%rax, %rdi, 4):位移量2在Disp8范围内,对应Disp8(MOD=01)。这里的4是比例因子,只负责缩放变址寄存器的取值,和MOD字段的位移类型无关。
补充:如果位移量超出Disp8范围(比如写
200(%eax)),编译器会自动切换为Disp32(MOD=10)模式。
3. Disp8/Disp32与寄存器大小的关系,以及为何没有16/64位位移
- 首先明确:Disp8和Disp32不是指第二个寄存器的大小,而是指位移量本身的编码长度,和寄存器的位数完全无关。比如在64位模式下使用
%rax(64位寄存器),依然可以搭配Disp8或Disp32的位移。 - 关于16/64位位移的问题:
- 16位位移是16位x86实模式下的产物,在32位和64位保护模式下,架构设计时选择了Disp8+Disp32的组合——既满足小偏移场景下的指令长度优化,又能覆盖绝大多数大偏移需求,因此不再保留16位位移的选项。
- 64位位移没有被加入的核心原因是:它会占用8个字节的指令空间,大幅增加指令长度,而实际编程中几乎不需要这么大的直接位移。通过基址+变址+比例的寻址方式,或者先把大偏移存入寄存器再做间接寻址,已经能满足所有场景需求。另外64位模式下,Disp32会被自动符号扩展为64位使用,足够覆盖绝大多数场景。
内容的提问来源于stack exchange,提问作者samuelbrody1249
相关产品推荐
相关产品推荐

