Управление состоянием и переходы

Флаги состояния

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

Регистр состояния PSTATE хранит флаги состояния, которые могут устанавливаться в зависимости от выполняемых инструкций и их результатов.

Регистр состояния PSTATE в ARM64

В данном регистре нас будет инстересовать прежде всего старшие 4 бита - флаги состояния NZCV:

  • N (Negative): флаг знака. Равен 1, если результат операции представляет отрицательное число. Равен 0, если результат - положительное число или 0.

  • Z (Zero): флаг нуля. Равен 1, если результат операции равен нулю. Равен 0, если результат операции НЕ равен нулю.

  • C (Carry): флаг переноса. Установка этого флага зависит от констекста.

    Обычно он устанавливается, если при выполнении арифметической операции произошел перенос. Подобное состояние еще называют беззнаковым переполнением (unsigned integer overflow). Например, возьмем операцию сложения двух 64-разрядных чисел

    0xffffffffffffffff
    +
    0x0000000000000003
    =
    0x0000000000000002 (результат)
    1 (флаг переноса)
    

    Результат такого сложения 0xffffffffffffffff + 0x3 явно превысит размер 64 бит. Формально он будет равен 65-разрядному числу 0x10000000000000002. Однако регистры общего назначения X0-X30 не позволяют хранить 65-разрядные значения. Таким образом, фактический результат будет равен 0x0000000000000002 (или просто 0x2), а старший бит переходит во флаг переноса. И далее, проверив, флаг переноса, мы можем узнать, было ли переполнение результата или нет.

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

    Стоит отметить, что есть арифметические инструкции, которые позволяют использовать бит переноса при сложении (ADC) и вычитании (SBC).

    Некоторые другие ситуации, где может устанавливаться данный флаг:

    • Инструкции RDNR и RNDRRS архитектуры Armv8.5-RNG устанавливают флаг переноса в 1, если аппаратная часть не смогла сгенерировать случайное число в за определенное время.

    • Некоторые операционные системы устанавливают флаг переноса в 1, чтобы указать, что запрошенный системный вызов завершился ошибкой.

    • При сравнениях чисел с плавающей точкой флаг переноса устанавливается в 1, если одно или оба числа представляют NaN (Not a Number - не число).

  • V (oVerflow): флаг переполнения, устанавливается, если при выполнении арифметической операции произошло переполнение со знаком (signed integer overflow). При сложении этот флаг устанавливается в следующих случаях:

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

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

    При вычитании флаг устанавливается в следующих случаях:

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

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

    Для вычисления значения флага можно применять следующие формулы

    Сложение: V = X63 & Operand63 & R63 | X63 & Operand63 & R63
    Вычитание: V = X63 & Operand63 & R63 | X63 &  Operand63 & R63
    

    Где X63 означает знаковый бит первого операнда (регистра), Operand63 - знаковый бит второго операнда, а R63 - знаковый бит результата. Стрелка над операндами означает инверсию.

    Например, возьмем сложение двух 64-разрядных чисел со знаком. Число +9223372036854775807 в 16-ричной системе равно 0x7fffffffffffffff. Сложим это число с самим собой:

    0x7fffffffffffffff
    +
    0x7fffffffffffffff
    =
    0xfffffffffffffffe (результат)
    1 (флаг переполнения)
    

    Результатом сложения является число 0xfffffffffffffffe. Если мы рассматриваем данное сложение как сложение чисел со знаком, то десятичным результатом является число -2 - отрицательное число. И в принципе мы по десятичному результату можем увидеть, что знаковый бит операндов изменился на противоположный - с 0 на 1. Поэтому устанавливается флаг переполнения V. Собственно поэтому в данном случае мы говорим о переполнении со знаком или переполнении знака, так как знак меняется.

    Если мы посмотрим внимательно процесс сложения, то мы можем увидеть, что установка флага переполнения зависит от бита переноса, который подается при сложении знаковых разрядов чисел, и от финального бита переноса:

    Установка флагов в ассемблере ARM64

    Здесь мы видим, что флаг переполнения фактически равен результату операции XOR входного бита переноса (который образовался после сложения предыдущих разрядов) и выходного бита переноса (того, который собственно и помещается во флаг переноса C).

Инструкции, меняющие флаги

Арифметические и логические инструкции

Многие стандартные инструкции ассемблера, например, MOV, ADD, SUB, AND и многие другие, никак не влияют на установку флагов. Но архитектура ARM64 также предоставляет ряд специальных инструкций, которые меняют флаги. Подобные инструкции обычно имеют в названии суффикс S. Прежде всего это следующие арифметические инструкции:

  • ADDS (сложение с установкой флага переноса при переполнении результата)

  • ADCS (сложение со флагом переноса с установкой знака переноса при переполнении результата)

  • SUBS (вычитание с установкой флага переноса при переполнении результата)

  • SBCS (вычитание бита переноса с установкой флага переноса при переполнении результата)

  • NEGS (умножает число на -1 и устанавливает флаги)

  • NGCS (использует флаг переноса для получения отрицательного значения и устанавливает флаги)

Эти инструкции устанавливают флаг N, если результат инструкии отрицательный; устанавливают флаг нуля, если результат равен 0; и также устанавливают флаги переноса и переполнения, если возникают беззнаковое переполнение и переполнение знака соответственно.

Кроме того, есть две логические инструкции:

  • ANDS: аналог инструкции AND с добавлением установки флагов

  • BICS: аналог инструкции BIC с установкой флагов

Они устанавливают от флаг N, если результат отрицательный, и флаг нуля, если результат равен нулю. Флаги переноса и переполнения всегда сброшены.

Инструкции сравнения

Также ARM64 предоставляет еще три инструкции сравнения, которые устанавливают флаги, но которые базируются на вышеуказанных инструкциях:

  • CMP A, B: сравнивает A в отношении B. Фактически эквивалентна инструкции SUBS XZR, A, B

  • CMN A, B: сравнивает A в отношении -B. Фактически эквивалентна инструкции ADDS XZR, A, B

  • TST A, B: проверяет, установлены или биты B внутри A. Эквивалентена инструкции ANDS XZR, A, B

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