为什么没有设置进位标志?

时间:2011-08-28 12:13:06

标签: assembly x86

我有一个简单的高级装配程序,我正在学习位移和旋转的细节。我有这个简单的程序可以在一个字节中移位这些位。

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 个答案:

答案 0 :(得分:8)

正如其他人已经指出的那样,你需要将127移位2位,以便实际设置进位标志。但是你说它仍然不起作用;这是我最好的猜测原因:

我不熟悉HLA及其库函数,但是,作为编写程序集时的一般规则,您应该始终假设调用库函数可能会以任意方式更改标志,除非有一些文档指出除此以外。许多指令可以更改标志,因此除非库函数明确保存条目上的标志并在退出时恢复它们(例如通过使用pushfpopf指令将它们保存在堆栈中),它们可能会结束在任何州。

在您的代码中,您可以在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 :(得分:1)

  

移位算术左(SAL)和移位逻辑左(SHL)指令执行   同样的操作;他们将目标操作数中的位向左移动(朝向   更重要的位位置)。对于每个班次计数,最重要的一点   目标操作数移入CF标志,最低有效位清零

  

移位算术右(SAR)和移位逻辑右(SHR)指令移位这些位   右侧的目标操作数(朝向不太重要的位位置)对于每一个   移位计数,目标操作数的最低有效位被移入CF   标志,根据指令设置或清除最高有效位   类型。 SHR指令清除最重要的位(请参见英特尔®中的图7-8)   64和IA-32架构软件开发人员手册,第1卷);特区   指令设置或清除最重要的位以对应符号(大多数   目标操作数中原始值的有效位。实际上,SAR   指令用未移位的符号填充空位位置的移位值   值

     

OF标志仅在1位移位时受影响。对于左移,如果结果的最高有效位与CF标志相同(即前两位),则OF标志设置为0   原来的操作数是一样的);否则,设置为1.对于SAR指令 -   对于所有1位移位,OF标志清零。对于SHR指令,OF标志是   设置为原始操作数的最高位。

  

CF标志包含从目标操作数移出的最后一位的值;它   对于计数大于或等于的SHL和SHR指令,未定义   目标操作数的大小(以位为单位)。 OF标志仅受1位移位的影响(参见上面的“描述”);否则,它是未定义的。 SF,ZF和PF标志   根据结果​​设置。如果计数为0,则标志不受影响。对于非   零计数,AF标志未定义。

<强>更新 这是手册所说的内容。仅显示用于设置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 = 01111111SHL使CF = MSB (DEST) = 0DEST = DEST * 2成为DEST = 127 * 2 = 254,其中11111110为二进制和2的赞美表示解释是十进制的-2

来源:Intel 64 and IA32 Architectures Software Developer Manual Volume 2

答案 2 :(得分:1)

最重要的位是0 - 如果你想让1进入进位标志,则需要向左移2位,即

shl(2, var); // [X] 01111111 -> [1] 11111100

答案 3 :(得分:0)

您正在使用的移位指令似乎是一个逻辑位移位器,即它不会保留符号位。尝试寻找算术移位指令(x86指令中的sar和sar)