перенос / переполнение и вычитание в x86

Я пытаюсь осознать флаги переполнения и переноса в x86.

Насколько я понимаю, для добавления дополнительных чисел со знаком 2 флаги могут быть сгенерированы только одним из четырех способов (мои примеры - 4-битные числа):

  1. pos+pos = neg (overflow)
    • 0111 + 0001 = 1000 (7 + 1 = -8)
  2. pos+neg = pos (carry)
    • 0011 + 1110 = 0001 (3 + -2 = 1)
  3. neg+neg = neg (carry)
    • 1111 + 1111 = 1110 (-1 + -1 = -2)
  4. neg+neg = pos (overflow & carry)
    • 1000 + 1001 = 0001 (-8 + -7 = 1)

Итак, в сборке x86 вычитание B из A генерирует те же флаги, что и добавление A и -B?


person Robz    schedule 23.01.2012    source источник


Ответы (2)


Вот справочная таблица, которая может помочь. Здесь показан пример каждой возможной комбинации 4 арифметических флагов, которые могут возникнуть в результате выполнения инструкций ADD и SUB на x86. 'h' 'ud' и 'd' означают шестнадцатеричное, десятичное и знаковое десятичное представление каждого значения. Например, в первой строке для SUB указано 0xFF - 0xFE = 0x1 без установленных флагов.

Но я думаю, что вкратце: ответ Алекса правильный.

 ADD
       A                   B                   A + B              Flags  
 ---------------     ----------------    ---------------      -----------------
 h  |  ud  |   d   | h  |  ud  |   d   | h  |  ud  |   d   | OF | SF | ZF | CF
 ---+------+-------+----+------+-------+----+------+-------+----+----+----+---
 7F | 127  |  127  | 0  |  0   |   0   | 7F | 127  |  127  | 0  | 0  | 0  | 0
 FF | 255  |  -1   | 7F | 127  |  127  | 7E | 126  |  126  | 0  | 0  | 0  | 1
 0  |  0   |   0   | 0  |  0   |   0   | 0  |  0   |   0   | 0  | 0  | 1  | 0
 FF | 255  |  -1   | 1  |  1   |   1   | 0  |  0   |   0   | 0  | 0  | 1  | 1
 FF | 255  |  -1   | 0  |  0   |   0   | FF | 255  |  -1   | 0  | 1  | 0  | 0
 FF | 255  |  -1   | FF | 255  |  -1   | FE | 254  |  -2   | 0  | 1  | 0  | 1
 FF | 255  |  -1   | 80 | 128  | -128  | 7F | 127  |  127  | 1  | 0  | 0  | 1
 80 | 128  | -128  | 80 | 128  | -128  | 0  |  0   |   0   | 1  | 0  | 1  | 1
 7F | 127  |  127  | 7F | 127  |  127  | FE | 254  |  -2   | 1  | 1  | 0  | 0


 SUB
       A                   B                   A - B              Flags  
 ---------------     ----------------    ---------------      -----------------
 h  |  ud  |   d   | h  |  ud  |   d   | h  |  ud  |   d   || OF | SF | ZF | CF
----+------+-------+----+------+-------+----+------+-------++----+----+----+----
 FF | 255  |  -1   | FE | 254  |  -2   | 1  |  1   |   1   || 0  | 0  | 0  | 0
 7E | 126  |  126  | FF | 255  |  -1   | 7F | 127  |  127  || 0  | 0  | 0  | 1
 FF | 255  |  -1   | FF | 255  |  -1   | 0  |  0   |   0   || 0  | 0  | 1  | 0
 FF | 255  |  -1   | 7F | 127  |  127  | 80 | 128  | -128  || 0  | 1  | 0  | 0
 FE | 254  |  -2   | FF | 255  |  -1   | FF | 255  |  -1   || 0  | 1  | 0  | 1
 FE | 254  |  -2   | 7F | 127  |  127  | 7F | 127  |  127  || 1  | 0  | 0  | 0
 7F | 127  |  127  | FF | 255  |  -1   | 80 | 128  | -128  || 1  | 1  | 0  | 1
person srking    schedule 24.01.2012
comment
Ваша таблица полезна, но 127 - -1 это 128, а не -128. - person James Black; 27.02.2013
comment
@James - Нет, цитирую справочник программиста x86. Целочисленные значения находятся в диапазоне от –128 до +127 для целого байта. - person srking; 28.02.2013
comment
doc.ic.ac.uk/~eedwards/compsys/arithmetic Хорошее объяснение того, как систематически определять перенос и переполнение. И для сложения, и для вычитания. - person Cubi73; 04.04.2015
comment
8-битное дополнение до двоек 128 (0x80) = -128 (0x80), правильная форма будет -128, если будет отображаться как число со знаком, поскольку в таблице показаны числа со знаком, а не беззнаковые. Это переполнение, как показано: 127 - - 1 = -128, если бы оно не было переполнено, то результат был бы +128. (для этого нужно 9 бит) - person old_timer; 15.11.2019

При сложении или вычитании возможны все 4 комбинации значений переноса и переполнения. Вы можете увидеть больше примеров в этом ответе.

Этот ответ содержит доказательство того факта, что перенос, который вы получаете от A-B, является обратным переносу, который вы получаете от A+(-B) . Код по первой ссылке использует это свойство для превращения ADC в SBB.

Однако значение подписанного флага переполнения должно быть одинаковым для A-B и A+(-B), потому что оно зависит от того, имеет ли результат правильный знаковый бит, и в обоих случаях знаковый бит будет одинаковым.

person Alexey Frunze    schedule 23.01.2012
comment
Полезное замечание на случай, если кто-то реализует семантику x86 для SBB в терминах АЦП: SBB {входы (a, b, cf), выходы (out, of, sf, zf, af, pf, cf)} = ADC {входы ( a, NOT (b), NOT (cf)), выходы (out, of, sf, zf, NOT (af), pf, NOT (cf))} - person mrexodia; 20.06.2018