Skip to content

Latest commit

 

History

History

0x02

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

0x02

[dec] [home] [inc]

[See this riddle on the book]

neg      rax
sbb      rax,rax
neg      rax
See explanation

Double negation

Double negation is a common practice in C to force non-zero numbers to be always 1. It is typically used when doing boolean operations with integers, where it is desirable to have 0 to mean false, and 1 to mean true, in case of direct comparison to possible defines of TRUE and FALSE. Whether this is a good practice or not is out of scope here.

The double negation looks like this:

!!x;

If x is 0, it will stay 0. If x is 1, 2, 3 or any other non-zero number, it will be come 1.

This assembly snippet does exactly that. How?

NEG calculates the two's complement of its operand, and sets the carry flag (CF) to 0 if the operand is 0, or 1 otherwise. For example, NEG of 0 is 0, and CF is set to 0. NEG of 1 is 0xffffffff (assuming 32 bits) and CF is 1. NEG of 2 is 0xfffffffe and CF is 1. And so on.

Then SBB subtracts the operands with borrow: the carry flag from the previous operation is added to the source operand (the rightmost in this example, which is rax anyway), then it is subtracted from the destination operand (the leftmost, rax again). At this point, after NEG and SBB:

  • 0 became 0
  • 1 became 0xffffffff (assuming 32 bits)
  • 2 became 0xfffffffe (assuming 32 bits)
  • etc (just keep decrementing)

Last but not least, NEG is applied again as at the first step. At the end of the process:

  • 0 becomes 0
  • 1 becomes 1
  • 2 becomes 1
  • 3 becomes 1

and so on.

[dec] [home] [inc]