Intel x86 Assembly Language & Microarchitecture
оптимизация
Поиск…
Вступление
замечания
Если вы сомневаетесь, вы всегда можете обратиться к довольно обширному Справочному руководству по оптимизации архитектуры 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 - Подробнее введите, если ваш ассемблер не поддерживает ярлыки
- Непрозрачный читатель, незнакомый с техникой