Прошел год или около того с тех пор, как я в последний раз посещал занятия по сборке. В этом классе мы использовали MASM с библиотеками Irvine, чтобы упростить программирование.
После того, как мы просмотрели большинство инструкций, он сказал, что инструкция NOP, по сути, ничего не делает и не стоит беспокоиться об ее использовании. Во всяком случае, это было около середины, и у него есть пример кода, который не будет работать должным образом, поэтому он сказал нам добавить инструкцию NOP, и она работала нормально. Я спросил, что я после уроков, почему и что он на самом деле сделал, и он сказал, что не знает.
Кто-нибудь знает?
Ответы:
Часто время
NOP
используется для выравнивания адресов команд. Это обычно встречается, например, при написании Shellcode для использования уязвимости переполнения буфера или форматной строки .Скажем, у вас есть относительный переход на 100 байтов вперед и внесите некоторые изменения в код. Скорее всего, ваши модификации испортят адрес цели прыжка, и вам также придется изменить вышеупомянутый относительный переход. Здесь вы можете добавить
NOP
s для продвижения целевого адреса вперед. Если у вас есть несколькоNOP
s между целевым адресом и инструкцией перехода, вы можете удалитьNOP
s, чтобы вернуть целевой адрес назад.Это не будет проблемой, если вы работаете с ассемблером, который поддерживает метки. Вы можете просто сделать
JXX someLabel
(где JXX - некоторый условный переход), и ассемблер заменитsomeLabel
адрес этой меткой. Однако, если вы просто измените собранный машинный код (фактические коды операций) вручную (как это иногда происходит при написании шелл-кода), вам также придется изменить инструкцию перехода вручную. Либо вы измените его, либо затем переместите целевой адрес кода с помощьюNOP
s.Другим вариантом использования для
NOP
инструкций будет то, что называется сани NOP . По сути, идея состоит в том, чтобы создать достаточно большой массив инструкций, которые не вызывают побочных эффектов (таких какNOP
или увеличивая, а затем уменьшая регистр), но увеличивая указатель инструкции. Это полезно, например, когда нужно перейти к определенному коду, адрес которого неизвестен. Хитрость заключается в том, чтобы поместить указанные салазки NOP перед целевым кодом, а затем прыгнуть куда-нибудь к указанным салазкам. То, что происходит, - то, что выполнение, мы надеемся, продолжается от массива, у которого нет никаких побочных эффектов, и это переходит вперед команду за инструкцией, пока это не достигает желаемого фрагмента кода. Этот метод обычно используется в вышеупомянутых уязвимостях переполнения буфера и особенно для противодействия мерам безопасности, таким как ASLR .Еще одно конкретное использование
NOP
инструкции - когда кто-то модифицирует код какой-либо программы. Например, вы можете заменить части условных переходов наNOP
s и, таким образом, обойти это условие. Это часто используемый метод при « взломе » защиты от копирования программного обеспечения. Самое простое - это просто удалить конструкцию ассемблерного кода дляif(genuineCopy) ...
строки кода и заменить инструкции наNOP
s и .. Вуаля! Никакие проверки не сделаны, и не подлинная копия работает!Обратите внимание, что по сути оба примера шелл-кода и взлома делают одно и то же; изменить существующий код без обновления относительных адресов операций, которые основаны на относительной адресации.
источник
Nop может использоваться в интервале задержки, когда никакая другая инструкция не может быть переупорядочена для размещения в ней.
В MIPS это было бы ошибкой, потому что в то время, когда младший считывал регистр v0, регистр v0 еще не был загружен значением из предыдущей инструкции.
Способ исправить это будет:
Это заполняет временные интервалы после слов загрузки и инструкций регистра перехода с помощью nop, так что инструкция слова загрузки завершается до выполнения команды регистра перехода.
Дальнейшее чтение - немного о SPARC заполнении слотов задержки . Из этого документа:
Обратите внимание на третий вариант в поле «Задержка». Вероятно, ошибка, которую вы увидели, связана с тем, что кто-то заполняет одну из вещей, которую нельзя помещать в отсек задержки. Поместив nop в это место, вы исправите ошибку.
Примечание: после повторного чтения вопроса это было для x86, у которого нет слотов задержки (вместо этого ветвление просто останавливает конвейер). Так что это не будет причиной / решением проблемы. В системах RISC это могло быть ответом.
источник
по крайней мере, одной из причин использования NOP является выравнивание. Процессоры x86 считывают данные из основной памяти довольно большими блоками, и начало считываемого блока всегда выравнивается, поэтому, если у вас есть блок кода, который будет много читаться, этот блок должен быть выровнен. Это приведет к небольшому ускорению.
источник
0x1002
, потому что в выровненном блоке из 16B все еще есть 14 байтов инструкций, которые содержат целевой адрес, но не подходят для перехода0x099D
.Одна из целей NOP (в общем случае сборки, а не только x86) - ввести временные задержки. Например, вы хотите запрограммировать микроконтроллер, который должен выводить на некоторые светодиоды с задержкой 1 с. Эта задержка может быть реализована с помощью NOP (и ответвлений). Конечно, вы можете использовать некоторые ADD или что-то еще, но это сделает код более нечитаемым; или, может быть, вам нужны все регистры.
источник
loop
инструкции для петель задержки , а не NOPS.Обычно для 80x86 инструкции NOP не требуются для корректности программы, хотя иногда на некоторых машинах стратегически размещенные NOP могут приводить к более быстрому выполнению кода. Например, на 8086 код должен быть выбран в виде двухбайтовых блоков, а процессор имеет внутренний буфер «предварительной выборки», который может содержать три таких блока. Некоторые инструкции будут выполняться быстрее, чем они могут быть получены, в то время как другие инструкции будут выполняться некоторое время. Во время медленных инструкций процессор будет пытаться заполнить буфер предварительной выборки, чтобы, если бы следующие несколько инструкций были быстрыми, они могли быть выполнены быстро. Если инструкция, следующая за медленной инструкцией, начинается с четной границы слова, инструкции из следующих шести байтов будут предварительно выбраны; если он начинается на границе нечетного байта, только пять байтов будут предварительно выбраны.
Такие проблемы с выравниванием памяти могут повлиять на скорость работы программы, но, как правило, они не влияют на корректность. С другой стороны, на старых процессорах есть некоторые проблемы, связанные с предварительной выборкой, когда NOP может повлиять на корректность. Если инструкция изменяет кодовый байт, который уже был предварительно выбран, 8086 (и я думаю, что 80286 и 80386) выполнит предварительно выбранную инструкцию, даже если она больше не соответствует тому, что находится в памяти. Добавление одного или двух NOP между инструкцией, которая изменяет память, и измененным байтом кода, может препятствовать извлечению байта кода до тех пор, пока он не будет записан. Заметьте, кстати, что многие схемы защиты от копирования использовали такого рода поведение; обратите внимание, однако, что это поведение не гарантируется. Различные варианты процессора могут обрабатывать предварительную выборку по-разному, некоторые могут сделать недействительными предварительно выбранные байты, если изменена память, из которой они были прочитаны, и прерывания, как правило, делают недействительным буфер предварительной выборки; код будет получен заново, когда прервутся возвраты.
источник
Существует особый случай x86, который еще не описан в других ответах: обработка прерываний. Для некоторых его стилей могут быть разделы кода, когда прерывания отключены, потому что основной код работает с некоторыми данными, совместно используемыми обработчиками прерываний, но разумно разрешать прерывания между такими разделами. Если один наивно пишет
это не будет обрабатывать ожидающие прерывания, потому что, ссылаясь на Intel:
так что это должно быть переписано как минимум:
Во втором варианте все ожидающие прерывания будут обрабатываться только между NOP и CLI. (Конечно, может быть много альтернативных вариантов, например, удвоение инструкции STI. Но явный NOP более очевиден, по крайней мере, для меня.)
источник
NOP означает отсутствие операции
Обычно он используется для вставки или удаления машинного кода или для задержки выполнения определенного кода.
Также используется взломщиками и отладчиками для установки точек останова.
Так что, вероятно, делать что-то вроде: XCHG BX, BX также приведет к тому же.
Звучит так, как будто было несколько операций, которые все еще выполнялись, и, следовательно, это вызвало ошибку.
Если вы знакомы с VB, я могу привести пример:
Если вы создаете систему входа в систему в VB и загружаете 3 страницы вместе - Facebook, YouTube и Twitter в 3 разных вкладках.
И использовать 1 кнопку входа для всех. Это может привести к ошибке, если ваше интернет-соединение работает медленно. Это означает, что одна из страниц еще не загружена. Поэтому мы добавили Application.DoEvents, чтобы преодолеть это. Таким же образом в сборке можно использовать NOP.
источник