Как точно работает инструкция x86 LOOP?
mov ecx, 16 looptop: . . . loop looptop
Сколько раз будет выполняться этот цикл?
Что произойдет, если ecx = 0
для начала? В этом случае происходит прыжок или провал loop
?
- как загрузить все сборки из вашего каталога / bin
- Возможно ли «декомпилировать» Windows .exe? Или, по крайней мере, рассмотреть Ассамблею?
- Размер сборки .NET влияет на производительность?
- Почему медленная инструкция цикла? Не удалось ли Intel эффективно внедрить его?
- Сколько циклов процессора требуется для каждой инструкции сборки?
- Сделать муравей тихий без флага -q?
- Безопасно ли читать конец конца буфера на одной странице на x86 и x64?
- Динамически заменить содержимое метода C #?
- x86_64 - Условия сборки и выход из строя
- Как я могу просмотреть MSIL / CIL, сгенерированный компилятором C #? Почему это называется сборкой?
- Дополнительная информация о макете памяти исполняемой программы (процесса)
- Инициализировать библиотеку при загрузке сборки
- Maven: добавьте зависимость к банке относительным путем
loop
точно так же, как dec ecx / jnz
, за исключением того, что он не устанавливает флаги .
Это похоже на нижнюю часть do{} while(--ecx != 0);
в C. Если выполнение входит в цикл с ecx = 0
, обертка означает, что цикл будет выполняться 2 ^ 32 раза. (Или 2 ^ 64 раза в 64-битном режиме, потому что он использует RCX).
В отличие от rep movsb/stosb/etc.
, он не проверяет ECX = 0 до декремента, только после.
Размер адреса определяет, использует ли он CX, ECX или RCX. Таким образом, в 64-битном коде addr32 loop
похож на dec ecx / jnz
, тогда как регулярный loop
похож на dec rcx / jnz
. Или в 16-битном коде он обычно использует CX, но префикс размера адреса ( 0x67
) заставит его использовать ecx
. Как сказано в руководстве Intel, он игнорирует REX.W, потому что он устанавливает размер операнда, а не размер адреса.
Связано: Почему циклы всегда скомпилированы так? для получения дополнительной информации о структуре цикла в asm, while(){}
vs. do{}while()
и как их выложить.
Дополнительные советы по отладке
Если вы когда-нибудь захотите узнать подробности инструкции, ознакомьтесь с руководством: либо официальным справочником по учебнику для учебных пособий Intel, либо справочником html с каждой записью на другой странице ( http://felixcloutier.com/x86/ ). Но учтите, что HTML не содержит интро и приложения, в которых есть подробности о том, как интерпретировать вещи, например, когда говорится, что «флаги установлены в соответствии с результатом» для инструкций, например add
.
И вы можете (и должны) также просто попробовать вещи в отладчике: меняются одношаговые и наблюдательные регистры. Используйте меньшее начальное значение для ecx
чтобы быстрее добраться до интересной ecx=1
. См. Также вики-файлы x86 для ссылок на руководства, руководства и советы по отладке asm внизу.
И BTW, если инструкции, которые не показаны, изменяют ecx
, он может зацикливаться сколько угодно раз. Чтобы вопрос имел простой и уникальный ответ, вам нужна гарантия того, что инструкции между меткой и инструкцией loop
не изменяют ecx
. (Они могли бы сохранить / восстановить его, но если вы собираетесь это делать, обычно лучше просто использовать другой регистр в качестве счетчика циклов. push
/ pop
внутри цикла делает ваш код трудным для чтения.)
Предъявляйте чрезмерное использование LOOP
даже когда вам уже нужно увеличивать что-то еще в цикле. LOOP
– это не единственный способ петли, и обычно это самое худшее.
Обычно вы никогда не должны использовать инструкцию цикла, если не оптимизировать размер кода за счет скорости, потому что она медленная . Компиляторы не используют его. (Так что производители процессоров не утруждают себя быстрым, поймать 22.) Используйте dec / jnz
или совсем другое условие цикла. (См. Также http://agner.org/optimize/, чтобы узнать больше о том, что эффективно.)
Циклы даже не должны использовать счетчик; часто бывает так же хорошо, если не лучше сравнивать указатель с конечным адресом или проверять какое-то другое условие. (Бесцельное использование loop
– одно из моих любимых мотивов, особенно когда у вас уже есть что-то в другом регистре, который работал бы как счетчик циклов.) Использование cx
в качестве счетчика циклов часто просто связывает один из ваших драгоценных немногих регистров, когда вы могли бы использовал cmp
/ jcc
в другом регистре, который вы все равно увеличивали.
IMO, loop
следует рассматривать как одну из тех неясных инструкций x86, с которыми новички не должны отвлекаться. Как stosd
(без префикса rep
), aam
или xlatb
. Тем не менее, он действительно использует их при оптимизации размера кода. (Это иногда полезно в реальной жизни для машинного кода (например, для загрузочных секторов), а не только для таких вещей, как кодовый гольф .)
ИМО, просто учите / учите, как работают условные ветви, и как создавать петли из них. Тогда вы не застрянете в мысли, что есть что-то особенное в цикле, который использует loop
. Я видел SO-вопрос или комментарий, который сказал что-то вроде «Я думал, что вам нужно объявлять циклы», и не понимал, что loop
– это всего лишь инструкция.
. Как я уже сказал,
loop
– одно из моих любимых раздражителей. Это ненавязчивая инструкция для игры в гольф, если вы не оптимизируете фактический 8086.