Why is the carry flag not being set?
I have a simple high level assembly program, where I am learning the ins and outs of bit shifting and rotation. I have this simple program to play around with shifting the bits in a single byte.
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;
As the byte is set to 127, it should be 01111111.
Surely by shifting left once, the carry flag should be raised as the last bit is reserved for signing?
This is not what appears to ha开发者_运维百科ppen however, indeed all the bytes shift left once so the byte is now 11111110, or -2.
If this happens every time, what conditions would cause the carry flag to be set?
Platform is win 7 64bit
As already noted by others, you do need to shift 127 by 2 places for the carry flag to actually be set. But you're saying that it still doesn't work; here's my best guess as to why:
I'm not familiar with HLA and its library functions, but, as a general rule when writing assembly, you should always assume that calling a library function may change the flags in an arbitrary way, unless there is some documentation which states otherwise. Many instructions can change flags, so unless the library function explicity saves the flags on entry and restores them on exit (e.g. by saving them on the stack with the pushf
and popf
instructions), they could end up in any state.
In your code, you have a call to the stdout.put
library routine between the shl
and the test of the carry flag:
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;
I would guess that stdout.put
is clearing the flag.
So try putting the test immediately after the shift:
shl(2, var);
if (@C) then stdout.put("carry set", nl); endif;
stdout.put(var, nl);
The most significant bit is 0 - if you want to get a 1 into the carry flag then would need to shift left by 2 bits, i.e.
shl(2, var); // [X] 01111111 -> [1] 11111100
The shift arithmetic left (SAL) and shift logical left (SHL) instructions perform the same operation; they shift the bits in the destination operand to the left (toward more significant bit locations). For each shift count, the most significant bit of the destination operand is shifted into the CF flag, and the least significant bit is cleared
and
The shift arithmetic right (SAR) and shift logical right (SHR) instructions shift the bits of the destination operand to the right (toward less significant bit locations). For each shift count, the least significant bit of the destination operand is shifted into the CF flag, and the most significant bit is either set or cleared depending on the instruction type. The SHR instruction clears the most significant bit (see Figure 7-8 in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1); the SAR instruction sets or clears the most significant bit to correspond to the sign (most significant bit) of the original value in the destination operand. In effect, the SAR instruction fills the empty bit position’s shifted value with the sign of the unshifted value
The OF flag is affected only on 1-bit shifts. For left shifts, the OF flag is set to 0 if the most-significant bit of the result is the same as the CF flag (that is, the top two bits of the original operand were the same); otherwise, it is set to 1. For the SAR instruc- tion, the OF flag is cleared for all 1-bit shifts. For the SHR instruction, the OF flag is set to the most-significant bit of the original operand.
also
The CF flag contains the value of the last bit shifted out of the destination operand; it is undefined for SHL and SHR instructions where the count is greater than or equal to the size (in bits) of the destination operand. The OF flag is affected only for 1-bit shifts (see “Description” above); otherwise, it is undefined. The SF, ZF, and PF flags are set according to the result. If the count is 0, the flags are not affected. For a non- zero count, the AF flag is undefined.
UPDATE
Here is what the manual tells. Only the loop body for setting CF
and shifting operation is shown:
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;
According to above with DEST = 01111111
and SHL
makes CF = MSB (DEST) = 0
and DEST = DEST * 2
which is DEST = 127 * 2 = 254
which is 11111110
in binary and in 2's compliment representation interpretation it is -2
in decimal.
Source: Intel 64 and IA32 Architectures Software Developer Manual Volume 2
It seems that the shift instruction you are using is a logical bit shifter, that is it does not leave the sign bit as is. Try looking for an arithmetic shift instruction (sar and sar in x86 instruction)
精彩评论