Linux 上 x86 的内存寻址模式解释
Posted
技术标签:
【中文标题】Linux 上 x86 的内存寻址模式解释【英文标题】:Memory addressing mode interpretation for x86 on Linux 【发布时间】:2019-01-06 11:01:28 【问题描述】:我正在阅读Programming from the ground up by Jonathan Bartlett。作者讨论了内存寻址模式,并指出内存地址引用的一般形式是这样的:
ADDRESS_OR_OFFSET (%BASE_OR_OFFSET, %INDEX, MULTIPLIER)
最终地址是这样计算的:
FINAL_ADDRESS = ADDRESS_OR_OFFSET + %BASE_OR_OFFSET + MULTIPLIER * %INDEX
.
还指出,如果遗漏了任何部分,则在等式中将其替换为零。 ADDRESS_OR_OFFSET
和MULTIPLIER
需要是常量,而其他元素需要是寄存器。这些似乎是唯一指定的一般规则。
到目前为止,一切都很好。
然后作者讨论了间接寻址方式并举例说明:
movl (%eax), %ebx
将eax
寄存器中存储的地址处的值移动到ebx
寄存器中。
为此,(%eax)
应解释为 0(%eax,0,0)
,而不是 0(0,%eax,0)
。是否有其他规则强制执行这种解释?
【问题讨论】:
乘数不能为 0。 1,2,4 或 8 @MichaelPetch 嗯..so,那么“如果遗漏任何部分,则在等式中将其替换为 0”的规则并不完全正确。 我认为您的书试图建立与实际情况不同的规则。我很确定您的 MOV 将转换为 [%eax(0,0,0)]。英特尔指令参考将是寻找此类规则的更好地方。 相关:Referencing the contents of a memory location. (x86 addressing modes) 列出了 x86 支持的寻址模式的所有变体。 【参考方案1】:书中的解释并非100%正确。 x86架构有以下32位寻址模式:
$imm immediate result = imm
%reg register result = reg
disp(%reg) indirect result = MEM[disp + reg]
disp direct result = MEM[disp]
disp(%base, %index, %scale) SIB result = MEM[disp + base + index * scale]
在 SIB(标度/索引/基址)和间接寻址模式中,disp
可以省略 0 字节位移。在SIB寻址模式下,另外base
和index
可以省略为0刻度,0索引; scale 实际上不能被忽略。请注意,当我说“遗漏”时,只有值被遗漏了;逗号留在里面。例如,(,,1)
表示“无位移、无基数、无索引和 1 个刻度的 SIB 操作数。”
在 64 位模式下,还可以使用rip
-相对寻址模式:
disp(%rip) rip relative result = MEM[disp + rip]
这种寻址模式对于编写与位置无关的代码很有用。
16 位模式有不同的寻址模式,但它们并不重要,所以我不会详细说明它们。
因此,对于您的示例:这很容易理解,因为它实际上是 间接 寻址模式,而不是 SIB 寻址模式,eax
作为寄存器并且没有位移。
【讨论】:
以上是关于Linux 上 x86 的内存寻址模式解释的主要内容,如果未能解决你的问题,请参考以下文章