我正在努力将复杂的间接寻址模式中的示例更改为简单的间接寻址模式。但是,我从基础模式中看到了一个例子,我无法“转换”。
movzbl string+8, %eax
我试过这个:
addl $8, string
movzbl string, %eax
编译此代码后,错误消息弹出。
答案 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)。
另请注意b8
和string
只会导致不同的地址字节但操作码相同。
答案 1 :(得分:1)
{{1}}
但是movzbl string + 8,%eax不是“复杂寻址模式”,它由汇编器/链接器解析。