0

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 happen 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

Jason Sill
  • 175
  • 2
  • 9

4 Answers4

8

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);
Matthew Slattery
  • 45,290
  • 8
  • 103
  • 119
1

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

phoxis
  • 60,131
  • 14
  • 81
  • 117
  • That doesn't really help. From the first paragraph you pasted (source?), the most significant bit should have been shifted into the CF flag. yet, apparently this doesn't happen. – Jason Sill Aug 28 '11 at 12:37
  • does the application of `shr` on the `var` result in `01111111` to `11111110` ? All the text are copies from the source, which i have linked below. – phoxis Aug 28 '11 at 12:43
  • I should note I am using high level assembly language, not just assembly. So the carry flag should not be set with 127, but what about with -2? If the bits are 11111110, since the MSB is 1, should the carry flag not be set? If I change the code above to assign -2 to var, this is not the case. No operating I do regardless of if the MSB is 1 is having the carry bit set. – Jason Sill Aug 28 '11 at 13:21
  • 1
    @Jason Sill: the last comment was not clear to me. Check the assembly code which the compiler generates from the high level code, and see whats going on. If the MSB is 1 then a left shift will get that MSB into the carry flag. – phoxis Aug 28 '11 at 13:37
  • HLA is Assembly, just with some slight abstractions : http://webster.cs.ucr.edu/AsmTools/HLA/. Even if I set my variable to -1, which should result in 11111111 CF is not set. Is there perhaps something wrong with the way I am testing CF? – Jason Sill Aug 28 '11 at 13:45
  • Indeed -1 when shifted by 1 becomes -2, or 11111110, but my statement is never printed which indicates CF is not set.... – Jason Sill Aug 28 '11 at 13:47
  • by any chance are you considering the MSB position of the variable and the `CF` are the same ? – phoxis Aug 28 '11 at 13:47
  • @JasonSill let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/2938/discussion-between-phoxis-and-jason-sill) – phoxis Aug 28 '11 at 13:48
1

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
Paul R
  • 208,748
  • 37
  • 389
  • 560
0

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)

WaelJ
  • 2,942
  • 4
  • 22
  • 28