Вычитание с установкой флагов. Инструкция SUBS

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

Инструкция SUBS вычитает одно чиcло из другого и при выполнении устанавливает флаги состояния:

SUBS Xn, Xs, Operand

Из второго операнда вычитается третий и результат помещается в первый операнд. Инструкция SUBS устанавливает флаг нуля Z, если результат равен 0. Флаг знака N устанавливается, если знаковый бит результата равен 1.

Флаг переноса C устанавливается, если результат вычитания положительный, и сбрасывает флаг переноса, если результат операции отрицательный.

Флаг переполнения V устанавливается в следующих ситуациях:

  • Если из положительного числа вычитается отрицательное, а результат отрицательный

  • Если из отрицательного числа вычитается положительное, а результат положительный

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

.global _start

_start:
    mov x0, #1
    mov x1, #2
    subs x0, x0, x1     // x0 = 1 - 2 = -1 или 0xffffffffffffffff

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

Здесь из Х0 (1) вычитаем Х1 (2). В результате получим -1 или 0xffffffffffffffff. На уровне компьютера вычитание предполагает сложение, где второй операнд инвертируется, затем к инвертированному значению прибавляется 1, то есть A – B = A + (~B + 1). В итоге мы получим, что выражение 1-2 или 0000 0001 - 0000 0010 (в двоичной форме) эквивалентно выражению:

0000 0001 - 0000 0010 = 0000 0001 + (~0000 0010) + 1

И в конечном счете получаем:

0000 0001
+
1111 1110
=
1111 1111

Флаги здесь устанавливаются следующим образом:

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

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

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

  • V=0. Переполнения здесь нет - из полодительного числа вычитается положительное, и результат отрицательный, поэтому флаг переполнения V не устанавливается.

Другой пример:

.global _start

_start:
    ldr x0, =0x8000000000000000 
    ldr x1, =0x8000000000000000
    subs x0, x0, x1     // x0 = 0x0

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

Здесь из 0x8000000000000000 вычитаем это же число. То есть получаем:

0x8000000000000000
-
0x8000000000000000
=
0x8000000000000000
+
(~0x8000000000000000)+1  (инверсия с прибавлением 1)
=
0x8000000000000000
+
0x8000000000000000
=
0x1_0000000000000000

Флаги здесь устанавливаются следующим образом:

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

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

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

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

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

.global _start

_start:
    mov x0, #0 
    ldr x1, =0x8000000000000000
    subs x0, x0, x1     // x0 = 0 - 0x8000000000000000 = 0x8000000000000000

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

Здесь из 0 вычитаем 0x8000000000000000. То есть получаем:

0
-
0x8000000000000000
=
0
+
(~0x8000000000000000)+1  (инверсия с прибавлением 1)
=
0
+
0x8000000000000000
=
0x8000000000000000

Флаги здесь устанавливаются следующим образом:

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

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

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

  • V=1. Когда из положительного числа вычитаем отрицательное, то мы ожидаем получить положительное число. Здесь же результат отрицательный, поэтому устанавливается флаг переполнения V.

Можно обратить внимание и заметить, что для беззнаковых чисел выражение A – B устанавливает флаг переноса C, то A больше или равно B. Для чисел со знаком A больше или равно B, если флаги N и V совпадают - одновременно равны 1 или 0.

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