Я хотел бы знать, в чем разница между этими инструкциями:
MOV AX, [TABLE-ADDR]
и
LEA AX, [TABLE-ADDR]
assembly
x86
instruction-set
Нэвин
источник
источник
Ответы:
LEA
означает загрузить эффективный адресMOV
означает значение нагрузкиКороче говоря,
LEA
загружает указатель на элемент, к которому вы обращаетесь, тогда как MOV загружает фактическое значение по этому адресу.Цель
LEA
состоит в том, чтобы позволить человеку выполнить нетривиальный расчет адреса и сохранить результат [для дальнейшего использования]Там, где задействованы только константы,
MOV
(с помощью константных вычислений ассемблера) иногда может совпасть с простейшими случаями использованияLEA
. Это полезно, если у вас есть расчеты из нескольких частей с несколькими базовыми адресами и т. Д.источник
LAHF
это: загрузить флаги в регистр AH . В CIL CLR (который является абстрактной машиной на основе стека более высокого уровня, термин load относится к размещению значения в условном стеке и обычноl
..., аs
эквивалент ... делает обратное). Эти примечания: cs.umd.edu/class/sum2003/cmsc311/Notes/Mips/load.html ) предполагают, что действительно существуют архитектуры, к которым относится ваше различие.В синтаксисе NASM:
В синтаксисе MASM используйте
OFFSET var
для получения mov-немедленного вместо загрузки.источник
mov eax, var
- это загрузка, такая же, какmov eax, [var]
и вы должны использовать,mov eax, OFFSET var
чтобы использовать метку в качестве непосредственной константы.lea
это худший выбор, за исключением 64-битного режима для относительной RIP-адресации.mov r32, imm32
работает на нескольких портах.lea eax, [edx*4]
является копией и сдвигом, который не может быть выполнен в одной инструкции иначе, но в том же регистре LEA просто требует больше байтов для кодирования, потому что[eax*4]
требует adisp32=0
. (Однако он работает на портах, отличных от сменных .) См. Agner.org/optimize и stackoverflow.com/tags/x86/info .Инструкция MOV reg, addr означает чтение переменной, хранящейся по адресу addr, в регистр reg. Инструкция LEA reg, addr означает чтение адреса (а не переменной, хранящейся по адресу) в регистр reg.
Другой формой инструкции MOV является MOV reg, immdata, что означает считывание непосредственных данных (т.е. постоянных) immdata в регистр reg. Обратите внимание, что если addr в reg LEA, addr является просто константой (то есть с фиксированным смещением), то эта инструкция LEA по существу точно такая же, что и эквивалентная команда MOV reg, immdata, которая загружает ту же константу, что и непосредственные данные.
источник
Если вы укажете только литерал, разницы нет. У LEA больше способностей, и вы можете прочитать о них здесь:
http://www.oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-1.html#HEADING1-136
источник
leal TextLabel, LabelFromBssSegment
когда получишь что-то. как.bss .lcomm LabelFromBssSegment, 4
бы тебе пришлосьmovl $TextLabel, LabelFromBssSegment
, не так ли?lea
требует назначения регистра, ноmov
может иметьimm32
источник и назначение памяти. Это ограничение, конечно, не специфично для ассемблера GNU.MOV AX, [TABLE-ADDR]
, что является нагрузкой. Так что есть большая разница. Эквивалентная инструкцияmov ax, OFFSET table_addr
Это зависит от используемого ассемблера, потому что
в MASM работает как
Таким образом, он загружает первые байты из,
table_addr
а не смещение вtable_addr
. Вы должны использовать вместоили
который работает так же.
lea
версия также отлично работает, еслиtable_addr
локальная переменная, напримеристочник
Ни один из предыдущих ответов не дошел до сути моей путаницы, поэтому я хотел бы добавить свой собственный.
Чего мне не хватало, так это того, что
lea
операции трактуют использование скобок иначе, чем какmov
.Подумайте о С. Допустим, у меня есть массив,
long
который я называюarray
. Теперь выражениеarray[i]
выполняет разыменование, загружая значение из памяти по адресуarray + i * sizeof(long)
[1].С другой стороны, рассмотрим выражение
&array[i]
. Это все еще содержит подвыражениеarray[i]
, но разыменование не выполняется! Значениеarray[i]
изменилось. Это больше не означает выполнение запроса, а действует как своего рода спецификация , сообщающая,&
какой адрес памяти мы ищем. Если хотите, вы можете думать о том, что вы можете&
«отменить» разыменование.Поскольку два варианта использования во многом похожи, они имеют общий синтаксис
array[i]
, но наличие или отсутствие&
изменений в интерпретации этого синтаксиса. Без&
, это разыменование и фактически читает из массива. С&
этим нет. Значениеarray + i * sizeof(long)
по-прежнему рассчитывается, но оно не разыменовывается.Ситуация очень похожа с
mov
иlea
. Сmov
, происходит разыменование, которое не происходит сlea
. Это несмотря на использование скобок, которые встречаются в обоих. Например,movq (%r8), %r9
иleaq (%r8), %r9
. Сmov
эти круглые скобки означают «разыменования»; сlea
, они не делают. Это похоже на то, какarray[i]
означает «разыменование» только тогда, когда нет&
.Пример в порядке.
Рассмотрим код
Это загружает значение в ячейке памяти
%rdi + %rsi * 8
в регистр%rbp
. То есть: получить значение в регистре%rdi
и значение в регистре%rsi
. Умножьте последнее на 8, а затем добавьте его к первому. Найдите значение в этом месте и поместите его в реестр%rbp
.Этот код соответствует строке C
x = array[i];
, гдеarray
становится%rdi
иi
становится%rsi
иx
становится%rbp
.8
Длина типа данных , содержащихся в массиве.Теперь рассмотрим похожий код, который использует
lea
:Так же, как использование
movq
соответствует разыменованию, использованиеleaq
здесь соответствует не разыменованию. Эта линия сборки соответствует линии Cx = &array[i];
. Напомним, что&
значениеarray[i]
разыменования меняется с простого указания местоположения. Аналогично, использованиеleaq
изменяет значение(%rdi, %rsi, 8)
разыменования на указание местоположения.Семантика этой строки кода следующая: получить значение в регистре
%rdi
и значение в регистре%rsi
. Умножьте последнее на 8, а затем добавьте его к первому. Поместите это значение в реестр%rbp
. Никакой нагрузки из памяти не происходит, только арифметические операции [2].Обратите внимание, что единственное различие между моими описаниями
leaq
иmovq
заключается в томmovq
, что разыменование происходит, аleaq
не -. Фактически, чтобы написатьleaq
описание, я в основном скопировал + вставил описаниеmovq
, а затем удалил «Найти значение в этом месте».Подводя итог:
movq
противleaq
это сложно, потому что они по- разному относятся к использованию скобок, как в(%rsi)
и(%rdi, %rsi, 8)
. Вmovq
(и во всех других инструкциях, кромеlea
) эти скобки обозначают подлинное разыменование, тогда как вleaq
них нет и есть чисто удобный синтаксис.[1] Я сказал, что когда
array
это массивlong
, выражениеarray[i]
загружает значение из адресаarray + i * sizeof(long)
. Это правда, но есть тонкость, которая должна быть решена. Если я напишу код Cэто не то же самое, что печатать
Кажется, это должно быть основано на моих предыдущих заявлениях, но это не так.
То, что происходит, заключается в том, что добавление указателя С имеет хитрость. Скажем, у меня есть указатель,
p
указывающий на значения типаT
. Выражениеp + i
же не среднее «положение вp
плюсi
байт». Вместо этого выражение наp + i
самом деле означает «позиция вp
плюсi * sizeof(T)
байты».Удобство в том, что для получения «следующего значения» нам просто нужно написать
p + 1
вместоp + 1 * sizeof(T)
.Это означает, что код C на
long x = array[5];
самом деле эквивалентенпотому что C автоматически Умножьте
5
наsizeof(long)
.Итак, в контексте этого вопроса StackOverflow, как это все относится? Это означает, что когда я говорю «адрес
array + i * sizeof(long)
», я не имею в виду, что «array + i * sizeof(long)
» следует интерпретировать как выражение C. Я делаю умножениеsizeof(long)
самостоятельно, чтобы сделать мой ответ более явным, но понимаю, что из-за этого это выражение не должно читаться как C. Так же, как обычная математика, использующая синтаксис C.[2] Примечание: поскольку все
lea
это арифметические операции, его аргументы не обязательно должны ссылаться на действительные адреса. По этой причине он часто используется для выполнения чистой арифметики со значениями, которые не могут быть разыменованы. Например,cc
с-O2
оптимизацией переводитв следующее (ненужные строки удалены):
источник
&
оператор Си - хорошая аналогия. Возможно, стоит отметить, что LEA является особым случаем, в то время как MOV подобен любой другой инструкции, которая может занять память или зарегистрировать операнд. например,add (%rdi), %eax
просто использует режим адресации для адресации памяти, такой же, как MOV. Также связано: использование LEA для значений, которые не являются адресами / указателями? далее это объяснение: LEA - это то, как вы можете использовать поддержку HW CPU для математики адресов для выполнения произвольных вычислений.%rdi
» - это странно сформулировано. Вы имеете в виду, что значение в реестреrdi
должно быть использовано. Использование «at», кажется, означает разыменование памяти там, где его нет.%rdi
» или «значения в%rdi
». Ваше «значение в регистре%rdi
» длинное, но хорошее и, возможно, может помочь кому-то изо всех сил пытаться понять регистры и память.В основном ... "Перейдите в REG ... после вычисления ...", это также хорошо для других целей :)
если вы просто забудете, что значение является указателем, вы можете использовать его для оптимизации / минимизации кода ... что угодно ..
EAX = 8
Первоначально это было бы:
источник
lea
это инструкция сдвига и добавления, которая использует машинное кодирование и синтаксис с операндом памяти, потому что аппаратное обеспечение уже знает, как декодировать ModR / M + SIB + disp0 / 8/32.Как указано в других ответах:
MOV
захватит данные по адресу в скобках и поместит эти данные в операнд-адресат.LEA
выполнит вычисление адреса в скобках и поместит этот вычисленный адрес в операнд назначения. Это происходит без фактического выхода в память и получения данных. Проделанная работаLEA
заключается в расчете «эффективного адреса».Поскольку память может быть адресована несколькими различными способами (см. Примеры ниже),
LEA
иногда используется для добавления или умножения регистров вместе без использования явногоADD
илиMUL
инструкции (или эквивалентной).Поскольку все показывают примеры в синтаксисе Intel, вот некоторые из них в синтаксисе AT & T:
источник
lea label, %eax
абсолютный[disp32]
режим адресации. Используйтеmov $label, %eax
вместо этого. Да, это работает, но это менее эффективно (больший машинный код и работает на меньшем количестве исполнительных блоков). Поскольку вы упоминаете AT & T, использовать LEA для значений, которые не являются адресами / указателями? использует AT & T, и в моем ответе есть несколько других примеров AT & T.Давайте разберемся с примером.
mov eax, [ebx] и
lea eax, [ebx] Предположим, что значение в ebx равно 0x400000. Затем mov перейдет по адресу 0x400000 и скопирует 4 байта данных, представленных в eax-регистр. В то время как lea скопирует адрес 0x400000 в eax. Итак, после выполнения каждой инструкции значение eax в каждом случае будет (при условии, что в памяти 0x400000 содержится 30).
eax = 30 (в случае mov) eax = 0x400000 (в случае lea) Для определения mov скопируйте данные из rm32 в место назначения (mov dest rm32), а lea (загрузите эффективный адрес) скопирует адрес в пункт назначения (mov dest rm32) ).
источник
LEA (Load Effective Address) является инструкцией сдвига и добавления. Он был добавлен в 8086, потому что там есть оборудование для декодирования и расчета режимов адресации.
источник
MOV может делать то же самое, что и LEA [метка], но инструкция MOV содержит эффективный адрес внутри самой инструкции как непосредственную константу (вычисляемую заранее ассемблером). LEA использует PC-относительный для вычисления эффективного адреса во время выполнения инструкции.
источник
lea [label
это бессмысленная трата байтов против более компактныхmov
, поэтому вы должны указать условия, о которых вы говорите. Кроме того, для некоторых ассемблеров[label]
неправильный синтаксис для режима RIP-относительной адресации. Но да, это точно. Как загрузить адрес функции или метки в регистр в GNU Assembler, объясняется более подробно.Разница тонкая, но важная. Инструкция MOV является «MOVe», по сути, копией адреса, обозначаемого меткой TABLE-ADDR. Инструкция LEA - это «Эффективный адрес загрузки», который является косвенной инструкцией, что означает, что TABLE-ADDR указывает на область памяти, в которой находится адрес для загрузки.
Эффективное использование LEA эквивалентно использованию указателей на таких языках, как C, поэтому это мощная инструкция.
источник