关于寻址模式的困惑 - () 之外的寄存器本身如何作为 ADDRESS_OR_OFFSET 常量工作?

问题描述 投票:0回答:1

从头开始编程,在第 3 章中我读到了

内存地址引用的一般形式是这样的:

ADDRESS_OR_OFFSET(%BASE_OR_OFFSET, %INDEX, MULTIPLIER)

所有字段都是可选的。要计算地址,只需执行以下计算:

FINAL ADDRESS = ADDRESS_OR_OFFSET + %BASE_OR_OFFSET + MULTIPLIER * %INDEX

ADDRESS_OR_OFFSET
MULTIPLIER
必须都是常量,而另外两个必须是寄存器。如果遗漏其中一个,则只需在方程中用零代替即可。

现在,我假设用零替换是一个拼写错误,因为如果

MULTIPLIER
的默认值为0,那么
%INDEX
的值将是无关紧要的,因为无论如何产品总是为零(确实) 。我猜其他 3 个默认为 0?

尽管如此,最让我困惑的是,从上面的描述中我了解到括号和逗号的功能是确定我们编写的内容的哪些部分映射到寻址的 4 个“操作数”。

但是,在接下来的章节中我读到了

例如,以下代码将堆栈顶部的所有内容移动到

%eax
中:

movl (%esp), %eax

如果我们只是这样做

movl %esp, %eax

%eax
只会保存指向堆栈顶部的指针,而不是顶部的值。

但我不明白为什么。我的意思是,

  • 鉴于上面的

    FINAL ADDRESS
    表达式,我会这么说

    • 如果我们把
      %esp
      放在括号里,它将起到
      %BASE_OR_OFFSET
      的作用,
      ADDRESS_OR_OFFSET
      %INDEX
      默认为0,
      MULTIPLIER
      默认为1,
    • 如果我们不把
      %esp
      放在括号中,它将起到
      ADDRESS_OR_OFFSET
      的作用,
      %BASE_OR_OFFSET
      %INDEX
      默认为0,
      MULTIPLIER
      默认为1,

    总和仍然是一样的。

  • 此外,

    %esp
    如何保持不变?

    • 也许我错误地认为它不是恒定的,因为我想到了%esp
      内容
    • 如果是这种情况,并且
      %esp
      是常数,因为它是物理固定寄存器的名称,那么在这种情况下什么是非常量?
assembly x86 terminology att addressing-mode
1个回答
3
投票

正确,默认乘数是

1


movl %esp, %eax
根本不使用内存寻址模式 它是寄存器直接操作数,因此在语法上与
mov symbol_name, %eax
(从绝对地址加载)不同。

有一个寄存器,但它不在

()
内部,因此
disp(base,idx,scale)
语法不适用。

在机器代码中,ModRM 字节的 2 位“模式”字段使用

0b11
来编码它是寄存器操作数而不是内存。 (其他 3 种编码选择无位移内存、disp8 与 disp32:https://wiki.osdev.org/X86-64_Instruction_Encoding#ModR.2FM_and_SIB_bytes。另请参阅rbp 不允许作为 SIB 基础? 对于有趣的特殊情况,允许
disp32
没有寄存器,并使 SIB 字节可选,以保存简单寻址模式的机器代码大小。)对于 ModR/M.mode =
11
,该字段只是一个简单的寄存器号。类似地,在汇编语言中,当您使用裸寄存器名称时,您只是直接获取寄存器操作数,而不是将其用作访问内存的地址。

(我不确定这是一个有用的类比,但我认为有用的一点是,即使在 x86 机器代码中,寄存器操作数与内存操作数也是不同的。它们有质的不同,需要区分。)


还有相关:

© www.soinside.com 2019 - 2024. All rights reserved.