如果我在 x86 AT&T 语法中省略比例因子和索引寻址模式会怎样?

What happens if I omit the scale factor of and indexed addressing mode in x86 AT&T syntax?

我是汇编新手,正在从 Programming from the Ground Up 学习它。在第 41 和 42 页上,该书讨论了索引寻址模式。

The general form of memory address references is this: ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)
All of the fields are optional. To calculate the address, simply perform the following calculation:
FINAL ADDRESS = ADDRESS_OR_OFFSET + %BASE_OR_OFFSET + MULTIPLIER * %INDEX
ADDRESS_OR_OFFSET and MULTIPLIER must both be constants, while the other two must be registers. If any of the pieces is left out, it is just substituted with zero in the equation.

所以我决定尝试一下。我写了下面这段代码:

.code32
.section .data
str:
    .ascii "Hello world[=10=]"

.section .text
.global _start
_start:
    movl , %ecx       # The index register.
    mov str(, %ecx, ), %bl
    movl , %eax
    int [=10=]x80

我希望得到 72(H 的 ASCII 代码)作为程序的退出结果,因为没有任何乘数(根据书本,应该用零代替)。但令人惊讶的是我得到了 108(l 的 ASCII 代码)。我认为这可能是 .ascii 的事情,并尝试查看是否可以使用不同的数据类型获得不同的结果。我也用 .byte 得到了相同的结果。

我尝试使用 AT&T 语法在 x86 程序集中查找索引寻址模式,但我找不到任何有用的东西(可能是因为我不知道要搜索什么)。

我是否遗漏了什么或者书中有误?鉴于我是这个领域的新手,如果您能详细说明,我将不胜感激。

If any of the pieces is left out, it is just substituted with zero in the equation.

这本书的一般规则对于比例因子不是很准确。如果省略,则默认比例因子为 1

x86 索引缩放在机器代码中作为 2 位移位计数工作。
asm 默认是 shift count of << 0, 但 x86 asm 源代码语法(包括 AT&T)使用乘数而不是 shift计数来表示这个,i << 0i * 1.

如果你不想要索引,你需要在你的寻址模式中省略对索引寄存器的提及。


请注意,默认值是汇编程序/语法的 属性,在本例中为 AT&T,而不是 x86 本身。机器代码中不能有“默认”——没有办法在一个字节中省略位,它们必须是 0 或 1。你要么有一个包含所有字段的 SIB 字节(scale-index-base),或者你不这样做(由 ModRM 字节表示)在这种情况下根本没有索引。

有一个 SIB 编码意味着没有索引,所以在机器代码中你仍然可以有一个完全没有索引的 SIB 字节,但你不会将其描述为零的乘数。

一些反汇编器将该编码表示为索引 = %eiz,例如在 nopl 0(%eax, %eiz, 1) 中显示有一个 SIB 字节但没有索引,但通常您只会在 NOPS 中看到它。当那个 SIB-with-no-index ,它被简化为那个。)


x86 机器代码有多种语法。尽管我所知道的所有人都同意没有规模只是意味着 shift=0,例如[str + eax + ecx] 英特尔语法;通常如果有超过 1 个,则选择第一个寄存器作为基数,第二个作为索引。

当然,在 Intel 语法中,要强制 ECX 成为没有基址寄存器的索引,您需要使用 [str + ecx*1] 故意在 SIB 编码上浪费一个字节。
[str + ecx] 在 Intel 中是 AT&T str(%ecx).


还相关: