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_OFFSETMULTIPLIER 需要是常量,而其他元素需要是寄存器。这些似乎是唯一指定的一般规则。

到目前为止,一切都很好。

然后作者讨论了间接寻址方式并举例说明:

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寻址模式下,另外baseindex可以省略为0刻度,0索引; scale 实际上不能被忽略。请注意,当我说“遗漏”时,只有值被遗漏了;逗号留在里面。例如,(,,1) 表示“无位移、无基数、无索引和 1 个刻度的 SIB 操作数。”

在 64 位模式下,还可以使用rip-相对寻址模式:

disp(%rip)                   rip relative  result = MEM[disp + rip]

这种寻址模式对于编写与位置无关的代码很有用。

16 位模式有不同的寻址模式,但它们并不重要,所以我不会详细说明它们。

因此,对于您的示例:这很容易理解,因为它实际上是 间接 寻址模式,而不是 SIB 寻址模式,eax 作为寄存器并且没有位移。

【讨论】:

以上是关于Linux 上 x86 的内存寻址模式解释的主要内容,如果未能解决你的问题,请参考以下文章

操作系统学习80x86保护模式内存管理

Linux从头学02:x86中内存段寻址方式的来龙去脉

基于转换的索引模式到间接寻址模式(x86 汇编)

x86汇编语言

Linux内存管理1

Linux IO模式和select,poll,epoll解释