将基于索引的模式转换为间接寻址模式(x86 程序集)第 2 部分



我正在努力将示例从复杂的间接寻址模式更改为简单的间接寻址模式片段。但是,我遇到了基于模式的示例,我无法"转换"。

movzbl  string+8, %eax

我试过这个:

addl    $8, string
movzbl  string, %eax

编译此代码后,会弹出错误消息。

string+8

不是基于索引的寻址模式。 它组装到一个没有基本寄存器的disp32绝对地址。 +8 在组装/链接时解析。 (请参阅引用内存位置的内容。(x86 寻址模式((

movzbl string+8, %eax组装成机器代码,具有与movzbl string, %eax相同的寻址模式(ModR/M字节(,只是disp32位移不同。请参阅C++链接在实践中如何工作?,了解有关组装 + 链接如何处理 +8 以便在运行时没有额外工作的一些详细信息。


您可以这样做,因为string+8不是寻址模式,而是可以用作即时操作数的链接时间常量

mov     $string+8, %edx
movzbl  (%edx), %eax

使用mov而不是lea清楚地表明了这一点,IMO。 使用lea将静态地址放入寄存器的唯一原因是在 x86-64 中,您可以将其用于与位置无关的代码(或低 2 GiB 以外的代码,如在 OS X 上(的 RIP 相对寻址。 例如lea string+8(%rip), %rdx.


在运行时而不是组装时做最无用的事情的最复杂的方法是

mov     $string, %edx
add     $8, %edx
movzbl  (%edx), %eax

我想使用lea会更加复杂,或者你可以inc8 次,或者编写一个循环来inc8 次,但这以不同的方式过于复杂。


例如,给定此源:

.globl _start
_start:
mov  $string, %eax
mov  $string+8, %eax
movzbl string+8, %eax
.section .rodata
string:

我用gcc -m32 foo.S -c组装并用objdump -drwC foo.o拆卸(选项-r显示重新定位(:

foo.o:     file format elf32-i386
Disassembly of section .text:
00000000 <_start>:
0:   b8 00 00 00 00          mov    $0x0,%eax        1: R_386_32     .rodata
5:   b8 08 00 00 00          mov    $0x8,%eax        6: R_386_32     .rodata
a:   0f b6 05 08 00 00 00    movzbl 0x8,%eax         d: R_386_32     .rodata

0 和 0x8 占位符不是实际地址,而是该重新定位的符号值的偏移量。 他们反对对象文件的.rodata部分,而不是string,因为我没有使用.globl _string使该符号全局化。

如果我组装+链接gcc -static -m32 -nostdlib foo.S并反汇编,我会得到:

8048098:       b8 a9 80 04 08          mov    $0x80480a9,%eax
804809d:       b8 b1 80 04 08          mov    $0x80480b1,%eax
80480a2:       0f b6 05 b1 80 04 08    movzbl 0x80480b1,%eax

请注意,要从中加载的绝对地址是如何在movzbl的最后 4 个字节(以小端序为单位(中存在的,与b8操作码(mov-imm32-to-eax(的直接 4 字节值相同。

还要注意stringstring+8如何只产生不同的地址字节但相同的操作码。

lea string, %eax
add $8, %eax
movzbl (%eax), %eax

但是 movzbl string+8,%eax 不是"复杂寻址模式",它由汇编器/链接器解析。

最新更新