如何解决如果我在 x86 AT&T 语法中省略了比例因子和索引寻址模式,会发生什么?
我是组装新手,正在从 Programming from the Ground Up 那里学习。这本书在第 41 页和第 42 页讨论了索引寻址模式。
内存地址引用的一般形式是这样的:
ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)
所有字段都是可选的。要计算地址,只需执行以下计算:FINAL ADDRESS = ADDRESS_OR_OFFSET + %BASE_OR_OFFSET + MULTIPLIER * %INDEX
ADDRESS_OR_OFFSET 和 MULTIPLIER 都必须是常量,而另外两个必须是寄存器。 如果有任何部分被遗漏,它只是在等式中用零代替。
所以我决定稍微尝试一下。我写了以下一段代码:
.code32
.section .data
str:
.ascii "Hello world\0"
.section .text
.global _start
_start:
movl $2,%ecx # The index register.
mov str(,%ecx,),%bl
movl $1,%eax
int $0x80
我希望得到 72(H 的 ASCII 代码)作为程序的退出结果,因为没有任何乘数(根据这本书,应该用零代替)。但令人惊讶的是,我得到了 108(l 的 ASCII 代码)。我认为这可能是 .ascii
的事情,并尝试查看是否可以使用不同的数据类型获得不同的结果。我用 .byte
也得到了相同的结果。
我尝试使用 AT&T 语法在 x86 程序集中查找索引寻址模式,但找不到任何有用的信息(可能是因为我不知道要搜索什么)。
有什么我遗漏的地方还是书中的错误?鉴于我是该领域的新手,如果您能详细说明,我真的很感激。
解决方法
如果有任何部分被遗漏,它只是在等式中用零代替。
这本书的一般规则对于比例因子不是很准确。如果省略,则默认比例因子为 1
。
x86 索引缩放在机器代码中用作 2 位移位计数。
该 asm 默认值是 << 0
的 移位计数,但 x86 asm 源代码语法(包括 AT&T)使用乘数而不是移位计数来表示这一点,并且i << 0
是 i * 1
。
如果你不想要索引,你需要在你的寻址模式中省略索引寄存器的提及。
请注意,默认值是汇编器/语法的属性,在这种情况下是 AT&T,而不是 x86 本身的属性。机器代码中不能有“默认值”——没有办法在一个字节中省略位,它们必须是 0 或 1。你要么有一个包含所有字段的 SIB 字节(scale-index-base),或者你没有(由 ModRM 字节表示)在这种情况下根本没有索引。
有一个 SIB 编码意味着没有索引,因此在机器代码中,您仍然可以拥有一个完全没有索引的 SIB 字节,但您不会将其描述为乘数为零。
一些反汇编程序将该编码表示为 index = %eiz
,例如在 nopl 0(%eax,%eiz,1)
中显示有一个 SIB 字节但没有索引,但通常您只会看到 NOPS。当那个 SIB-with-no-index is necessary to encode (%esp)
时,它被简化为那个。)
x86 机器码有多种语法。尽管我所知道的所有人都同意没有比例只是意味着 shift=0,例如[str + eax + ecx]
在 Intel 语法中;通常选择第一个寄存器作为基址,如果大于 1,则选择第二个作为索引。
当然在 Intel 语法中,要强制 ECX 成为没有基址寄存器的索引,您需要使用 [str + ecx*1]
故意在 SIB 编码上浪费一个字节。
英特尔的 [str + ecx]
是 AT&T str(%ecx)
。
还相关:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。