Предлагаю в этом топе собирать всевозможные "маленикие хитрости", которые бывают полезны для оптимизации кода по размеру и/или скорости. Для кого-то, возможно, эти вещи очевидны, а для кого-то нет, но обмен опытом imho никому не помешает. _______________________________________________________ Вот элементарный пример: Операция AND позволяет обнулить биты в приёмнике, по источнику "маске" - биты приёмника, соответствующие нулевым битам маски обнуляются. Иногда, нужно обнулить биты приёмника, соответствующие единичным битам маски. очевидный вриант - инвертировать маску: Код (Text): ; eax - приёмник ; edx - "инвертированная" маска not edx and eax, edx А если маска далее нужна в неинвертированном виде? можно делать по-другому: Код (Text): or eax, edx xor eax, edx _______________________________________________________ Часто необходимо сравнить регистр с некоторым числом, и, если значение в регистре меньше, поместить в него (или в другой регистр) одно занчение (value<sub>1</sub>), иначе - другое (value<sub>2</sub>). Без ветвлений это можно делать так: Код (Text): cmp eax, some_number sbb eax, eax ; 0 или FFFFFFFF and eax, value<sub>1</sub> - value<sub>2</sub> add eax, value<sub>2</sub> Частный вариант - value<sub>2</sub> = 0, в этом случае последняя строка не нужна. _______________________________________________________ Для циклов обычно используется отдельная переменная (или регистр). Однако, если в цикле ипользуется операция сдвига, то в качестве "счётчика" можно использовать сам сдвигаемый регистр. Наглядный пример - перевод числа в двоичное представление: Код (Text): ; ecx - число ; edi - адрес буфера, куда поместим ASCII строку stc ; "33й бит" - маркер l00p: mov al, 30 rcl ecx, 1 ; циклически сдвигаем регистр с маркером adc al, "0" stos byte[edi] inc ecx ; маркер выйдет за пределы регистра после 32х итераций и ecx будет равен 0 loop l00p ; inc ecx + loop "короткий" аналог test ecx, ecx + jnz
У меня (почему-то до сих пор, наверное из-за лени ?) нет этой книги =) К тому же, мне кажется, что мой третий пример ^ в ней не рассматривается
Если нужно увеличить/уменьшить число, занимающее биты с H по L: Код (Text): N H L 0 XXNNNXXX rol reg,N-H add/sub reg,(v shl N-H) ror reg,N-H
yureckor этот способ обмена не универсален: в случае, если a и b -- одно и то же, он будет работать неправильно
При вызове WinAPI функций, очень часто нужно передавать адрес переменной размером dword, куда будет записано возвращаемое значение. Обычно для этих целей создаётся отдельная локальная переменная (HLL way) или, того хуже, глобальная. Существует более компактный способ: Код (Text): push ecx ; создаём локальную переменную mov ecx, esp ; её адрес invoke ReadFile, hFile, lpBuffer, nNumberOfBytesToRead, ecx, lpOverlapped pop ecx ; считываем значение
При оптимизации по размеру может быть полезен такой способ загрузки параметров stdcall функции в регистры: Код (Text): foo_proc: push esi ; если нужно, сохраняем esi mov esi, esp lods dword[esi] ; пропускаем сохранённый esi lods dword[esi] ; пропускаем адрес возврата lods dword[esi] ; 1й аргумент xchg eax, ecx ; в ecx lods dword[esi] ; 2й аргумент xchg eax, edx ; в edx lods dword[esi] ; 3й аргумент в eax
S_T_A_S_ есть такая замечательная книжка - "Hackers Delight". там дохрена "маленьких хитростей". в инете встречается крайне редко, проси Володю - она у него есть
tasman блин, внатуре, автор то - Henry S. Warren, а я и не знал но вот перевод названия мягко говоря - вольный
Народ, ну неужели в "Hackers Delight" будут описываться архитектурные особенности x86-32 и / или win ?
Так, хватит тут оффтоп разводить. А что у Володи есть - так нечего об этом публично заявлять Знаток закромов Родины выискался, млин
Код (Text): Уоррен Г. Алгоритмические трюки для программистов: Пер. с англ., Вильямс, 2003 г. - 288 с. «Hacker's Delight» ISBN: 5-8459-0471-4 Не так уж и сложно найти в сети
однажды я ломал игру, так там из начального байта вычитался байт типа 0DEh. так вот через n=(число жизней) вычитаний этот байт обнулялся, и - гейм овер. не совсем асм, и может устарело, но и не очень-то заметно по сравнению с простым dec или sub 1