Почему флаг переноса не установлен? - PullRequest
0 голосов
/ 28 августа 2011

У меня есть простая программа сборки высокого уровня, где я изучаю все тонкости сдвига и вращения битов. У меня есть эта простая программа для перемещения со сдвигом битов в одном байте.

static
var: int8 := 127;

begin test1;

stdout.put(var, nl);
shl(1, var);
stdout.put(var, nl);
if (@C) then stdout.put("carry set"); endif;
end test1;

Поскольку байт установлен в 127, он должен быть 01111111.

Конечно, сдвинув влево один раз, флаг переноса должен быть поднят, так как последний бит зарезервирован для подписи?

Однако это не то, что происходит, действительно, все байты сдвигаются влево один раз, поэтому байт теперь 11111110, или -2.

Если это происходит каждый раз, какие условия могут привести к установке флага переноса?

Платформа является выигрышной 7 64 бит

Ответы [ 4 ]

8 голосов
/ 28 августа 2011

Как уже отмечалось другими, вам нужно сместить 127 на 2 места, чтобы флаг переноса был фактически установлен. Но вы говорите, что это все еще не работает; вот мое лучшее предположение относительно того, почему:

Я не знаком с HLA и его библиотечными функциями, но, как правило, при написании ассемблера вы всегда должны предполагать, что вызов библиотечной функции может изменить флаги произвольным образом, если только нет какой-либо документации, в которой говорится иначе. Многие инструкции могут изменять флаги, поэтому, если функция библиотеки Explicity не сохранит флаги при входе и не восстановит их при выходе (например, сохраняя их в стеке с помощью инструкций pushf и popf), они могут оказаться в любом состоянии.

В вашем коде у вас есть вызов библиотечной процедуры stdout.put между shl и проверкой флага переноса:

shl(2, var);  /* I'm assuming you've already changed 1 to 2 here */
stdout.put(var, nl);
if (@C) then stdout.put("carry set"); endif;

Я бы предположил, что stdout.put очищает флаг.

Так что попробуйте поставить тест сразу после смены:

shl(2, var);
if (@C) then stdout.put("carry set", nl); endif;
stdout.put(var, nl);
1 голос
/ 28 августа 2011

Команды арифметического сдвига влево (SAL) и логического сдвига влево (SHL) выполняют та же операция; они сдвигают биты в операнде-адресате влево (в направлении более значимые битовые локации). Для каждой смены наиболее значимый бит целевой операнд смещается в флаг CF, а младший бит очищается

и

Команды арифметического сдвига вправо (SAR) и логического сдвига вправо (SHR) сдвигают биты операнда назначения справа (к менее значимым битовым позициям). Для каждого сдвиг счетчика, младший значащий бит операнда назначения сдвигается в CF флаг, и самый старший бит устанавливается или сбрасывается в зависимости от инструкции тип. Инструкция SHR очищает самый значащий бит (см. Рисунок 7-8 в Intel® Руководство разработчика программного обеспечения 64 и IA-32, том 1); САР устанавливает или сбрасывает наиболее значимый бит, соответствующий знаку (наиболее значащий бит) исходного значения в целевом операнде. По сути, SAR инструкция заполняет смещенное значение пустой битовой позиции знаком нешифрованного значение

Флаг OF влияет только на 1-битные сдвиги. Для сдвигов влево флаг OF устанавливается в 0, если старший значащий бит результата совпадает с флагом CF (то есть, верхние два бита из оригинального операнда были одинаковыми); в противном случае он равен 1. Для инструкций SAR В этом случае флаг OF сбрасывается для всех 1-битных сдвигов. Для инструкции SHR флаг OF установить на самый значащий бит исходного операнда.

также

Флаг CF содержит значение последнего бита, сдвинутого из операнда назначения; Это не определено для команд SHL и SHR, где число больше или равно размер (в битах) целевого операнда. На флаг OF влияют только сдвиги в 1 бит (см. «Описание» выше); в противном случае он не определен. Флаги SF, ZF и PF устанавливаются в соответствии с результатом. Если количество равно 0, флаги не затрагиваются. Для не ноль, флаг AF не определен.

UPDATE Вот что говорит руководство. Отображается только тело цикла для установки CF и операции переключения:

IF instruction is SAL or SHL
  THEN
      CF ← MSB(DEST);

  ELSE (* Instruction is SAR or SHR *)
      CF ← LSB(DEST);
FI;
IF instruction is SAL or SHL
  THEN
      DEST ← DEST ∗ 2;
  ELSE
      IF instruction is SAR
            THEN
                 DEST ← DEST / 2; (* Signed divide, rounding toward negative infinity *)
            ELSE (* Instruction is SHR *)
                 DEST ← DEST / 2 ; (* Unsigned divide *)
      FI;
FI;
tempCOUNT ← tempCOUNT – 1;

В соответствии с вышеизложенным с DEST = 01111111 и SHL составляет CF = MSB (DEST) = 0 и DEST = DEST * 2, что составляет DEST = 127 * 2 = 254, что составляет 11111110 в двоичном и в интерпретации представления комплимента 2, это -2 в десятичном виде. *

Источник: Руководство по разработке программного обеспечения для архитектуры Intel 64 и IA32, том 2

1 голос
/ 28 августа 2011

Самый старший бит равен 0 - если вы хотите вставить 1 в флаг переноса, то нужно будет сдвинуть влево на 2 бита, т.е.

shl(2, var); // [X] 01111111 -> [1] 11111100
0 голосов
/ 28 августа 2011

Кажется, что используемая вами команда сдвига является логическим сдвигом битов, то есть она не оставляет знаковый бит как есть.Попробуйте найти инструкцию арифметического сдвига (sar и sar в инструкции x86)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...