基于索引模式的转换为间接寻址模式(x86汇编)第2部分

时间:2018-04-30 12:29:51

标签: assembly x86

我正在努力将复杂的间接寻址模式中的示例更改为简单的间接寻址模式。但是,我从基础模式中看到了一个例子,我无法“转换”。

movzbl  string+8, %eax

我试过这个:

addl    $8, string
movzbl  string, %eax

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

2 个答案:

答案 0 :(得分:2)

string+8不是基于索引的寻址模式。它汇编到没有基址寄存器的disp32绝对地址。 +8在汇编/链接时解决。 (见Referencing the contents of a memory location. (x86 addressing modes)

movzbl string+8, %eax汇编为使用与movzbl string, %eax相同的寻址模式(ModR / M字节)加工代码,只是一个不同的disp32位移。 请参阅How does C++ linking work in practice?了解有关汇总+链接如何处理+8的一些详细信息,因此在运行时没有额外的工作。

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

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

使用mov代替lea可以明确指出这一点,IMO。使用lea将静态地址放入寄存器的唯一原因是x86-64,当你可以将它用于与位置无关的代码的RIP相对寻址时(或者对于低2 GiB以外的代码,如同OS X)。例如lea string+8(%rip), %rdx

在运行时而不是组装时间做最无用的东西的最复杂的方法是

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

我想使用lea会更复杂,或者你可以inc 8次,或者写一个循环到inc 8次,但那已经结束了 - 以不同的方式复杂化。

例如,鉴于此来源:

.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个字节中(在小端),同样的4字节值,即{{1}的立即数。 1}}操作码(mov-imm32-to-eax)。

另请注意b8string只会导致不同的地址字节但操作码相同。

答案 1 :(得分:1)

{{1}}

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