Поиск…


Вступление

Семейство x86 существует уже давно, и поэтому существует множество трюков и приемов, которые были обнаружены и разработаны, которые являются общедоступными, или, может быть, не столь публичными. Большинство этих трюков используют тот факт, что многие инструкции эффективно выполняют одно и то же, но разные версии быстрее или сохраняют память или не влияют на флаги. Вот несколько трюков, которые были обнаружены. У каждого есть свои «за» и «против», поэтому они должны быть перечислены.

замечания

Если вы сомневаетесь, вы всегда можете обратиться к довольно обширному Справочному руководству по оптимизации архитектуры Intel 64 и IA-32 , которое является отличным ресурсом от компании, стоящей за архитектурой x86.

Обнуление регистра

Очевидным способом нулевого регистра является MOV в 0 например:

B8 00 00 00 00    MOV eax, 0

Обратите внимание, что это 5-байтная инструкция.

Если вы захотите сфотографировать флаги ( MOV никогда не влияет на флаги), вы можете использовать инструкцию XOR для бит-XOR для регистрации:

33 C0             XOR eax, eax

Эта инструкция требует всего 2 байта и выполняется быстрее для всех процессоров .

Перемещение флага переноса в регистр

Фон

Если флаг Carry ( C ) содержит значение, которое вы хотите поместить в регистр, наивный способ - сделать что-то вроде этого:

    mov  al, 1
    jc   NotZero
    mov  al, 0
NotZero:

Используйте 'sbb'

Более прямой путь, избегая прыжка, заключается в использовании «Вычесть с заимствованием»:

    sbb  al,al    ; Move Carry to al

Если C равно нулю, то al будет равным нулю. В противном случае это будет 0xFF ( -1 ). Если вам нужно, чтобы он был 0x01 , добавьте:

    and  al, 0x01 ; Mask down to 1 or 0

Pros

  • Примерно того же размера
  • Два или несколько инструкций
  • Нет дорогих прыжков

Cons

  • Это непрозрачно для читателя, незнакомого с техникой
  • Он изменяет другие флаги

Проверить регистр на 0

Фон

Чтобы узнать, имеет ли регистр нуль, наивная техника заключается в следующем:

    cmp   eax, 0

Но если вы посмотрите на код операции для этого, вы получите следующее:

83 F8 00      cmp   eax, 0

Использовать test

    test   eax, eax      ; Equal to zero?

Изучите код операции:

85 c0         test   eax, eax

Pros

  • Только два байта!

Cons

  • Непрозрачный читатель, незнакомый с техникой

Вы также можете изучить Q & A Question по этой методике .

Системные вызовы Linux с меньшей раздутой

В 32-битном Linux системные вызовы обычно выполняются с помощью команды sysenter (обычно я говорю, потому что старые программы используют устаревший int 0x80 ), однако это может занимать довольно много места в программе, и поэтому есть способы, может сократить углы, чтобы сократить и ускорить работу.
Обычно это компоновка системного вызова на 32-битном Linux:

mov eax, <System call number>
mov ebx, <Argument 1> ;If applicable
mov ecx, <Argument 2> ;If applicable
mov edx, <Argument 3> ;If applicable
push <label to jump to after the syscall>
push ecx
push edx
push ebp
mov ebp, esp
sysenter

Это массивно! Но есть несколько трюков, которые мы можем сделать, чтобы избежать этого беспорядка.
Первое - установить значение ebp на значение esp, уменьшенное на 3 32-битных регистра, то есть 12 байтов. Это здорово, пока вы в порядке с перезаписыванием ebp, edx и ecx с помощью мусора (например, когда вы будете перемещать значение в эти регистры сразу же после этого), мы можем сделать это, используя инструкцию LEA, чтобы нам не понадобилось чтобы повлиять на значение самого ESP.

mov eax, <System call number>
mov ebx, <Argument 1>
mov ecx, <Argument 2>
mov edx, <Argument 3>
push <label to jump to after the syscall>
lea ebp, [esp-12]
sysenter

Однако мы не закончили, если системный вызов sys_exit, мы можем уйти, не нажимая ничего на стек!

mov eax, 1
xor ebx, ebx ;Set the exit status to 0
mov ebp, esp
sysenter

Умножать на 3 или 5

Фон

Чтобы получить продукт регистра и константы и сохранить его в другом регистре, наивный способ заключается в следующем:

    imul ecx, 3      ; Set ecx to 5 times its previous value
    imul edx, eax, 5 ; Store 5 times the contend of eax in edx

Использовать lea

Умножения - это дорогостоящие операции. Быстрее использовать комбинацию сдвигов и добавлений. Для конкретного случая muliplying contend 32 или 64-битного регистра, который не является esp или rsp на 3 или 5, вы можете использовать инструкцию lea. Это использует схему расчета адресов для быстрого вычисления продукта.

    lea ecx, [2*ecx+ecx] ; Load 2*ecx+ecx = 3*ecx into ecx
    lea edx, [4*edx+edx] ; Load 4*edx+edx = 5*edx into edx

Многие ассемблеры также поймут

    lea ecx, [3*ecx]
    lea edx, [5*edx]

Для всех возможных мультипликаций, отличных от ebp или rbp , полученная команда lengh такая же, как с использованием imul .

Pros

  • Выполняется намного быстрее

Cons

  • Если ваш multipicand равен ebp или rbp он принимает по одному байту больше, используя imul
  • Подробнее введите, если ваш ассемблер не поддерживает ярлыки
  • Непрозрачный читатель, незнакомый с техникой


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow