Не понимает регистр статуса FLAGS - PullRequest
0 голосов
/ 01 июля 2018

Я помогал своему другу, выполняя некоторые упражнения по теории компьютерной архитектуры. Мы наткнулись на это м.с. упражнение по поводу регистра FLAGS и не знаю, как на него ответить. Это происходит примерно так:

"Предположим, что вы выполнили операцию ADD между двумя целыми числами без знака, и это привело к установке следующих флагов: CF = 0; OF = 1; ZF = 0; SF = 1. Что мы можем сделать из этот параметр и почему? "

Правильный выбор говорит о том, что результат этой операции является правильным, и когда говорит почему, он говорит: «потому что CF равен нулю». Мой вопрос здесь заключается в том, почему нам нужно учитывать флаг переноса, только если для других флагов установлен один? А также, как возможно, чтобы переполнение и флаг со знаком были установлены в единицу, когда мы выполняем операцию добавления между целыми числами без знака?

Заранее спасибо!

Ответы [ 2 ]

0 голосов
/ 02 июля 2018

CF = 0 говорит о том, что ADD не переносится. См. эту статью о Понимании условий переноса и переполнения / флаги .

Можно сказать, что ADD всегда дает правильный результат (a + b) modulo 2^32, если только у вас не сломан компьютер. Если ADD обернут, результат не совпадает с математической суммой двух входов с бесконечной точностью, но это правильная арифметика по модулю (выполнение операции модуля бесплатно). Поэтому вы должны быть осторожны, что вы подразумеваете под «правильным»! (Очевидно, что в этом случае ваше назначение означает математическую целую сумму.)

Терминология здесь сбивает с толку, потому что «арифметическое переполнение» как общая концепция (когда математически точный результат не может вписаться в место назначения) включает в себя целые числа со знаком и без знака. На x86 (как и на всех нормальных процессорах) поведение меняется. Но беззнаковый перенос называется переносом, а подписанный перенос - переполнением.

С плавающей точкой нормальное поведение переполнения - насыщение до +/- Бесконечность. Это иллюстрирует разницу между переполнением как общей концепцией и переносом как специфическим поведением целочисленного переполнения.

В некоторых архитектурах есть инструкция насыщения-добавления с насыщением в качестве поведения целочисленного переполнения. В x86 есть инструкция paddusw (и версия со знаком) для целочисленного SIMD, но не для скалярных регистров GP, таких как EAX.

В C переполнение без знака определено для обхода, но переполнение со знаком является неопределенным поведением (и компиляторы могут оптимизировать, предполагая, что этого не происходит).

MIPS имеет инструкцию add, которая перехватывает переполнение со знаком. (Компиляторы C обычно используют addu для всего, хотя, потому что MIPS - машина дополнения 2, поэтому это та же самая двоичная операция, только другое поведение перехвата. Они могли только безопасно использовать add, чтобы перехватить UB со знаком переполнения, когда вещи, которые они добавляли совпадающие значения переменных, которые будут происходить на абстрактной машине C., а не после оптимизации. И некоторый битовый код небезопасно полагается на циклический перенос со знаком в C, поэтому пользователи обычно хотят переносить вместо перехвата. MIPS не имеет регистра FLAGS любого добрый, вот как они решили предоставить аппаратную поддержку для проверки переполнения.)


Остальные флаги дают вам больше информации о вашем результате

Часть этого редко / никогда не полезна, но вот мой ответ на вопрос «что вы можете сделать?».

ZF = 0 говорит вам, что результат ненулевой . Если бы вы реализовывали что-то вроде if (a + b != 0), вы могли бы разветвляться (или cmov или setcc) на флаги, установленные ADD, вместо того, чтобы делать отдельный test eax,eax. Нередко ZF используется после инструкций, отличных от cmp или test.

SF = 1 говорит вам, что результат равен> = половине максимального значения . то есть, что для неподписанного результата установлен старший бит. Для 8-битного ADD SF = 1 означает, что результат> = 128. Это иногда может сэкономить вам тест или сравнить инструкцию. Если вы добавляете в себя регистр как сдвиг влево, то CF сдвигает бит, а SF имеет текущий старший бит. Я думаю, OF говорит вам кое-что о

OF = 1 (с SF = 1 и CF = 0) говорит о том, что оба входа были меньше половины максимального значения без знака . (т. е. если они интерпретируются как числа со знаком, они были положительными. Интерпретация результата со знаком является отрицательной, поэтому интерпретация результата со знаком - это pos + pos = neg, что может произойти только через переполнение).

Я ни разу не воспользовался этим последним в любой написанной мной ассм, и кажется маловероятным, что это будет полезно. Ни у одной архитектуры, о которой я знаю, нет ветвящихся условий, которые смотрят как на CF, так и на OF. Так что было бы полезно, если вы уже были в ветке CF = 0. x86 подписал большие / меньшие ветви , которые проверяют SF! = OF , но вы все равно не можете проверить SF == 1 и OF == 1 с одной инструкцией. Поэтому, возможно, если вы захотите проверить это условие, вы OR сделаете два входа и проверите SF этого.

0 голосов
/ 01 июля 2018

Флаг переноса отражает генерацию переноса из наиболее значимых битов операции. Для операндов без знака такой перенос будет отражать переполнение.

Что касается других флагов, флаг Sign применим только для подписанных операндов. То же самое верно для флага переполнения, поскольку он устанавливается, когда знак изменяется неправильно из-за переполнения подписанной операции.

Финальный флаг Zero устанавливается, когда результат равен нулю и не имеет отношения к обнаружению переполнения.

В представленном вами примере операнды не подписаны, а флаг Carry сброшен. Таким образом, переполнения не произошло.

...