Директивы ассемблера
.global main // экспортировать символ main
main:
movl $42, %eax
.intel_syntax noprefix
mov eax, 42 // код в синтаксисе Intel
.att_syntax noprefix
movl $42, eax // noprefix — без символа %
// перед операндами-регистрами
.att_syntax prefix
.set answer, 4 * 10
movl $answer + 2, %eax
nop
.byte 0x90
.skip 5, 0x90
call finish
.word 1, 2, 3 // или .short 1, 2, 3
.int 4, 5, 6
.quad 7, 8, 9
Переходы и метки
.global main
main:
xor %eax, %eax
xor %ebx, %ebx
loop:
inc %eax
inc %ebx
jmp loop
Флаги
Большинство арифметических инструкций в результате вычисления результата инструкции устанавливают арифметические флаги слова состояния процесса.
Флаг ZF (zero) устанавливается, если в результате операции был получен нуль.
Флаг SF (sign) устанавливается, если в результате операции было получено отрицательное число.
Флаг CF (carry) устанавливается, если в результате выполнения операции произошел перенос из старшего бита результата. Например, для сложения CF устанавливается если результат сложения двух беззнаковых чисел не может быть представлен 32-битным беззнаковым числом.
Флаг OF (overflow) устанавливается, если в результате выполняния операции произошло переполнение знакового результата. Например, при сложении OF устанавливается, если результат сложения двух знаковых чисел не может быть представлен 32-битным знаковым числом.
Обратите внимание, что и сложение addl, и вычитание subl устанавливают одновременно и флаг CF, и флаг OF. Сложение и вычитание знаковых и беззнаковых чисел выполняется совершенно одинаково, и поэтому используется одна инструкция и для знаковой, и для беззнаковой операции.
stc // установить CF
clc // сбросить CF
setc %al // установить %al в 0 или 1 в зависимости от флага
// seto, setz, ...
Условные переходы
jz label /* переход, если равно (нуль), ZF == 1 */
jnz label /* переход, если не равно (не нуль), ZF == 0 */
jc label /* переход, если CF == 1 */
jnc label /* переход, если CF == 0 */
jo label /* переход, если OF == 1 */
jno label /* переход, если OF == 0 */
jg label /* переход, если больше для знаковых чисел */
jge label /* переход, если >= для знаковых чисел */
jl label /* переход, если < для знаковых чисел */
jle label /* переход, если <= для знаковых чисел */
ja label /* переход, если > для беззнаковых чисел */
jae label /* переход, если >= (беззнаковый) */
jb label /* переход, если < (беззнаковый) */
jbe label /* переход, если <= (беззнаковый) */
Посчитаем до 20:
main:
xor %eax, %eax
loop:
add $3, %eax
call writei32
mov %eax, %ecx
subl $20, %ecx
jl loop
// тут чего-то не хватает
.globl main
cmp src, dst // недеструктивная версия sub
test src, dst // недеструктивная версия and
Длинная арифметика
Сложим 64-разрядные числа в edx:eax и edi:esi:
add %esi, %eax // сложили младшие половины
jnc 1f
inc %edx // если был перенос, добавляем 1
1:
add %edi, %edx // сложили старшие половины
Чтобы не выписывать такую последовательность инструкций, есть инструкция adc
(add with carry),
которая прибавляет ко второму операнду не только первый операнд, но и значение
флага CF:
add %esi, %eax
adc %edi, %edx
Аналог для вычитания — sbb
(subtract with borrow).
Условные инструкции
Инструкция cmovz
(conditional move if ZF) работает как mov
,
если ZF выставлен, или как nop
, если сброшен. Аналогично
с другими условиями.