Сложение и установка флагов. Инструкция ADDS

Последнее обновление: 16.07.2023

Стандартная инструкция сложения ADD никак не изменяет флаги. Однако установка флагов может быть необходима, особенно если мы работаем с большими числами и хотим избежать некорректных результатом. И для сложения с установкой флагов архитектура ARM64 предоставляет дополнительную инструкцию - ADDS

ADDS Xn, Xs, Operand

Эта инструкция, аналогично инструкции ADD, вычисляет сумму Xs + Operand и помещает результат в регистр Xs. Но при этом также устанавливает флаги.

Рассмотрим пример

.global _start

_start:
    ldr x0, =0xffffffffffffffff
    mov x1, #2
    adds x0, x0, x1     // x0 = 0xffffffffffffffff + 2 = 0x00000000000000001
    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Итак, в регистр Х0 загружается число 0xffffffffffffffff. Данное число рассматривается можно рассматривать как беззнаковое число 18446744073709551615, либо как число со знаком -1. В Х1 помещаем число 2. Затем складываем оба числа и помещаем результат в Х0. Как будет происходить сложение

0xffffffffffffffff + 0x0000000000000002 = 0x1_0000000000000001 (результат)

Или для большей наглядности в бинарном виде:

  1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
+
  0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010
=
1 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0001

Формально результатом бы было 65-разрядное число 0x1_0000000000000001, однако регистр Х0 у нас 64-разрядный, поэтому фактическим результатом является число 0x0000000000000001 или просто 1. В итоге в результате сложения образуется перенос. В итоге флаги устанавливаются следующим образом:

  • Z=0. Результат не равен 0, флаг нуля Z не устанавливается.

  • N=0. Поскольку старший (знаковый) бит результата не равен 1, то флаг знака N не устанавливается.

  • C=1. Поскольку в результате операции имеется перенос, устанавливается флаг переноса C.

  • V=0. Переполнения знака тут нет, как минимум потому, что знаковые биты у обоих операндов разные, поэтому флаг переполнения V не устанавливается.

Рассмотрим другой пример:

.global _start

_start:
    ldr x0, =0x7fffffffffffffff   // 9223372036854775807
    ldr x1, =0x7fffffffffffffff
    adds x0, x0, x1     // x0 = 0xfffffffffffffffe

    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Здесь в регистры Х0 и Х1 загружается одно и то же число 0x7fffffffffffffff или 9223372036854775807 в десятичной системе. Инструкция ADDS выполняет сложение этих чисел и помещает их в Х0. В результате сложения мы получим число 0xfffffffffffffffe. Для наглядности процесс сложения в бинарной форме

0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
+
0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
=
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1110

В данном случае происходит следующая установка флагов:

  • Z=0. Результат не равен 0, флаг нуля Z не устанавливается.

  • N=1. Старший (знаковый) бит результата равен 1, поэтому устанавливается флаг знака N.

  • C=0. В результате операции нет переноса, поэтому флаг переноса C не установлен.

  • V=1. Операнды инструкции имеют один и тот же знаковый бит. Результат имеет другой знаковый бит, поэтому устанавливается флаг переполнения V.

Третий пример:

.global _start

_start:
    ldr x0, =0x8000000000000000   // 9223372036854775808
    ldr x1, =0x8000000000000000
    adds x0, x0, x1     // x0 = 0x0

    mov x8, #93         // номер функции Linux для выхода из программы - 93
    svc 0               // вызываем функцию и выходим из программы

Здесь складываются два числа 0x8000000000000000 (9223372036854775808 в десятичной системе). То есть мы получим следующую операцию:

  1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+
  1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
=
1_0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

Здесь опять же образуется перенос, а фактический результат равен 0. В итоге состояние флагов будет следующим:

  • Z=1. Результат равен 0, поэтому устанавливается флаг нуля Z.

  • N=0. Старший (знаковый) бит результата равен 0, поэтому флаг знака N не устанавливается.

  • C=1. В результате операции произошел перенос, поэтому устанавливается флаг переноса C.

  • V=1. Операнды инструкции имеют один и тот же знаковый бит. Результат имеет другой знаковый бит, поэтому устанавливается флаг переполнения V.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850