string+8
не является режимом адресации на основе индекса. Он собирается по абсолютному адресу disp32 без базового регистра. +8 разрешается во время сборки / соединения. (См. Ссылка на содержимое ячейки памяти. (Режимы адресации x86) )
movzbl string+8, %eax
собирается в машинный код с тем же режимом адресации (байт ModR / M), что и movzbl string, %eax
, только с другим смещением disp32
. См. Как работает связывание C ++ на практике? для получения подробной информации о том, как сборка + связывание заботятся о +8, поэтому во время выполнения нет дополнительной работы.
Вы можете сделать это, потому что string+8
не режим адресации, это константа времени соединения, которую вы можете использовать в качестве непосредственного операнда .
mov $string+8, %edx
movzbl (%edx), %eax
Использование mov
вместо lea
проясняет этот момент, IMO. Единственная причина использовать lea
для помещения статического адреса в регистр кроется в x86-64, когда вы можете использовать его для относительной RIP-адресации для кода, не зависящего от позиции (или для кода за пределами младших 2 ГБ, как в 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
Обратите внимание, что абсолютный адрес для загрузки находится прямо в последних 4 байтах movzbl
(в младшем порядке), того же 4-байтового значения, которое является непосредственным для кода операции b8
(mov-imm32 -в-EAX).
Также обратите внимание, что string
и string+8
просто приводят к разным адресным байтам, но с одинаковым кодом операции.