В синтаксисе AT & T $
означает трактовать то, что следует, как непосредственную константу, а не адрес памяти.Другими словами,
movl $_start, %eax
загружает адрес символа _start
в% eax;
movl _start, %eax
читает 4 байта из памяти по адресу _start
в% eax,Если вы посмотрите на разборку обоих:
0: b8 00 00 00 00 mov $0x0,%eax
1: R_386_32 _start
5: a1 00 00 00 00 mov 0x0,%eax
6: R_386_32 _start
, вы увидите, что единственным отличием является код операции.Удобный, хотя и несколько корыстно названный, Руководство разработчика программного обеспечения для архитектуры Intel® 64 и IA-32 (вам нужен том 2, который является справочником набора команд), говорит, что коды операций от B8 до BF кодируют "немедленно загрузить16/32-битная константа в регистр "(это код, предназначенный для загрузки в 32-битный сегмент кода, так что это 32-битная загрузка; для 16-битной загрузки у вас будет" переопределение размера операнда ")Префиксный байт, 66) и код операции A1 кодируют «загрузку 32-разрядного количества с указанным 32-разрядным смещением от DS (или любого другого сегмента с соответствующим байтом префикса) в EAX».С типичной «плоской» моделью памяти это моральный эквивалент «загрузки 32-битного количества по указанному 32-битному абсолютному адресу», но вы можете видеть, как x86 приобрела свою репутацию смехотворно сложной на машинном уровне.
Если вам интересно, вот как это выглядело бы, если бы вместо этого мы использовали EBX:
a: bb 00 00 00 00 mov $0x0,%ebx
b: R_386_32 _start
f: 8b 1d 00 00 00 00 mov 0x0,%ebx
11: R_386_32 _start
Непосредственную загрузку все еще можно выполнить с помощью однобайтовой инструкции, не считая операнд (это BBвместо B9, как и следовало ожидать, поскольку внутренний порядок регистров AX, CX, DX, BX, SP, BP, SI, DI - серьезно), но адрес загрузки из абсолютного теперь имеет двабайтовая инструкция, 8B 1D;второй байт - это то, что Intel называет байтом «ModRM», который определяет как EBX, так и абсолютный 4-байтовый адрес.