- Простое использование lea
- Использование lea для арифметики
- Файлик с умножением на 3. Оптимизации - O0, O3
- Стековый калькулятор (switch)
- Инструкция lea
- Сумма цифр в строке: asm, c
- Вектор структур: asm, c++
На самом деле переменной это называть не совсем корректно, так как это просто метка, которая будет заменена на адрес. Но здесь используется слово переменная, из-за того, что работа с метками похожа работу с привычными переменными
lea offset(base, index, mult), reg -> offset + base + index * mult -> reg
mult может быть только 2 4 8 16 для 32 битной системы.
lea
в отличие от mov
не будет пытаться взять значение по получившемуся адресу, поэтому нет требования, чтобы адрес в итоге получится корректным. Поэтому его можно использовать для арифметических операций.
Например, если в %ecx
лежит 5, а в %edx
6, то в результате работы следующего кода в %eax
будет лежать 4 + (5 + 6 * 2)
lea 4(%ecx, %edx, 2), %eax
Если несколько операций сложения/умножения можно заменить одной операцией lea, то лучше так делать, потому что lea не сохраняет промежуточные результаты в регистры. Но lea не выставляет флаги.
Использование lea для арифметических операций
Есть простой код, приведенный в файлике multiply_by_three. Код считывает число и умножает на 3.
Если мы скомпилируем с флагом -S
(чтобы получить код ассемблера) и флагом -O0
(чтобы выключить оптимизации). Получившийся файл с комментариями multiply_by_three_O0.
movl %edx, %eax
addl %eax, %eax
addl %edx, %eax
Обратим внимаение, что не используется инструкция умножения, а используется несколько раз сложение. Это происходит из-за того, что инструкции mul являются трудозатратными и честного умножения числе выгоднее избегать.
Так, например, можно попробовать поменять 3 на 7 в коде. Можно увидеть, что в результате получится тоже что-то отличное от умножения (у меня вышло умножение на 8 с помощью сдвига с последующим вычитанием).
sall $3, %eax
subl %edx, %eax
Если скомпилировать код с флагами -S
, -O3
(третий уровень оптимизации кода), то получится файл multiply_by_three_O3.
В нем можно увидеть, что больше нет операций сложения, вместо них испоользуется конструкция
leal (%eax,%eax,2), %eax
Так как для lea в отличие от mov не требуется, чтобы в результаате выполонения инструкции получился валидный адрес, то можно использовать эту инструкцию для того, чтобы быстро выполнять арифметические операции.
В данном случае происходит следующее: в %eax
будет лежать значение равное %eax
+ %eax * 2
, что как раз и будет умножением на 3.
Умножение на 7 заменилось на следующие инструкции:
leal 0(, %edx, 8), %eax
subl %edx, %eax