8

Here is some C, found in a textbook I'm learning:

...
do {
    ...
    n--;
} while (n > 0)
...

I assume n is at %edx.

The assembly code produced is:

testl %edx, %edx 
jle .L5

I understand that jle tests for less than or equal to (SF ^ OF) | ZF. However I am unsure how this instruction corresponds to n > 0. Can anyone explain this?

phuclv
  • 37,963
  • 15
  • 156
  • 475
dgamma3
  • 2,333
  • 4
  • 26
  • 47

2 Answers2

15

Some of this has been covered, but I'll fill in a little more detail.

The general purpose of the test reg,mask instruction tests a register value against a mask (register value is internally ANDed with mask) and then sets the status flags SF, ZF, and PF according to the result. [EDIT per comment from @ChrisDodd] It also unconditionally clears the O (overflow) and C (carry) status bits.[/EDIT]

SF = sign flag (1 if sign bit is set (a 2's complement negative value))
ZF = zero flag (1 if result is 0)
PF = parity flag (1 if result has an even number of 1 bits)

In this specific example (test eax,eax), the instruction is taking eax AND eax. When this is done, the bits will be:

SF = 1 if EAX has a negative value (since sign bit will not change when ANDed with itself)
ZF = 1 if EAX is zero (the only value that yields a zero when ANDed with itself is zero)
PF = 1 if EAX has an even number of 1 bits

In other words, it's a simple test for zero or negative. It's a very common pattern in compiler code generation.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • 2
    A critical additional fact is that the `test` instruction unconditionally clears the O and C flags. Without that it would not be useful for comparisons against zero. – Chris Dodd Jun 30 '13 at 19:57
  • @ChrisDodd good info (+1). Thanks. If you don't mind, I shall add that to my answer for completeness. – lurker Jun 30 '13 at 20:16
1

TEST "sets the SF, ZF, and PF status flags according to the result." (Intel manual, about TEST).

So SF will reflect whether n was negative, and ZF will reflect whether n was zero.

It sets OF to zero.

So (SF ^ OF)|ZF simplifies to SF | ZF, so in conclusion, the jump will be taken if n <= 0. That seems the wrong way around, so hopefully .L5 is the label after the loop, not the label in front of the loop.

harold
  • 61,398
  • 6
  • 86
  • 164