Действительно ли это всего лишь два способа достичь одного и того же?
Да, у сборки есть множество способов сделать что-то.
C эквивалент будет
char *p = array;
, затем с использованием p[0]
, p[1]
et c. по сравнению с использованием array[0]
, array[1]
, et c.
Преимущество размещения указателя в регистре состоит в том, что он сохраняет некоторый размер кода при повторном его использовании; 2-байтовая инструкция mov
с просто кодом операции + ModRM вместо кодирования абсолютного адреса в каждой инструкции отдельно для режима адресации [disp32]
.
Другое преимущество заключается в том, что вы можете увеличить указатель с inc esi
. В других случаях, когда вы не развернули полностью oop, вам нужен либо указатель, либо индекс в регистре.
Простой указатель обычно лучше, чем [array + ecx]
, особенно лучше, чем [array + ecx*4]
потому что индексированные режимы адресации имеют некоторые недостатки. ([array + ecx]
технически не проиндексирован; он [base + disp32]
и ему не требуется байт SIB, и он не считается индексированным для Режимы микросинтеза и адресации ).
You однако можно использовать смещения байтов (например, add ecx, TYPE array
), чтобы разрешить режим адресации [base + disp32]
в массиве stati c из int
вместо [disp32 + idx*scale]
.
с использованием [disp32]
каждый раз избегает необходимости в дополнительной инструкции для помещения адреса в регистр. mov reg, imm32
- это всего лишь 5-байтовая одиночная команда, но она все еще может не стоить производительности до того, как пара получит доступ к массиву c. Это может зависеть от того, как часто ваш код уже перегрет в кэше UOP, и от того, как часто он должен извлекать / декодировать. (Сохранение размера кода повышает частоту обращений L1 I $ или, по крайней мере, означает, что в одной строке кэша помещается больше инструкций, поэтому может быть целесообразно использовать больше инструкций / больше мопов, если он сохраняет размер кода в чем-то, что находится не в самой горячей внутренней области. oop.)
Перед тем, как al oop (не полностью развернутый), вам, как правило, потребуется инструкция обнуления счетчика / индекса al oop, например, xor ecx, ecx
. Использование mov reg, imm32
только на 3 байта больше, и никаких дополнительных мопов. Если вы сохраняете 4 или 5 байтов каждый раз, когда используете указатель вместо режима индексированной адресации, вы уже опередили всего одну ссылку на массив за итерацию. И без дополнительных затрат. (Игнорирование любых незначительных различий между внешними затратами на выполнение инструкции xor-zeroing и mov-немедленного.)
Обратите внимание, что для x86-64 вы обычно ставите c адрес в регистре с 7-байтовым RIP-относительным LEA. А для того, чтобы ваш код был LargeAddressAware, вы не можете использовать [array + rcx]
, потому что он работает только с [disp32 + reg]
режимом адресации, а не [RIP + rel32]
.
И, кстати, для согласованности I я рекомендую это более mov al, array
mov al, [array + 0]
mov al, [array + 1]
...
Первый комментарий по вашему вопросу от кого-то, кого вы запутали, выполнив mov al, array
, а затем mov al, [array + 1]
, используя 2 разных синтаксиса для похожих адресов; Я думаю, что Шут думал, что вы намеревались что-то вроде mov al, OFFSET array
. Кстати, вместо этого вы могли бы написать это так (я думаю)
mov al, array
mov al, array + 1
, но я всегда рекомендую использовать квадратные скобки вокруг операнда памяти для ясности. Особенно, если вы когда-либо смотрите на синтаксис NASM где это всегда обязательно, но некоторые люди рекомендуют это соглашение, даже если вы используете только MASM. (Но имейте в виду, что MASM игнорирует скобки в некоторых случаях, когда нет регистра: Запутанные скобки в MASM32 , поэтому не думайте, что использование скобок в MASM делает его работающим как NASM.)
Кстати, эффективный способ загрузки одного байта заключается в расширении нуля до полного регистра, вместо слияния с младшим байтом полного регистра. movzx eax, byte ptr [esi]
Кстати, да, mov esi, OFFSET array
(5 байт) - наиболее эффективный способ помещения адреса stati c в регистр ( размер и производительность кода). lea esi, array
имеет размер 6 байт (код операции + modrm + [disp32]
режим адресации) и может работать на меньшем количестве исполнительных портов; никогда не используйте LEA без регистра в 32-битном режиме.
В 64-битном режиме вы хотите lea rsi, array
, потому что MASM автоматически использует RIP-относительную адресацию для того, что вы хотите. В противном случае по-прежнему используйте mov esi, OFFSET array
(да, ESI, а не RSI) для кода, который не является LargeAddressAware и может по-прежнему использовать компактный код с использованием 32-разрядных абсолютных адресов.