Logical Operations

Just like shifting, there are other opertions on bits such as and, or, xor and not. With those operations, one can manipulate each bit of a data.

OperationUsageDescription
andand eax, edxEach i-th bit in eax and edx will be compared and the i-th bit of eax will be 1 iff both compared bits are 1
oror eax, edxEach i-th bit in eax and edx will be compared and the i-th bit of eax will be 1 if at least one of the compared bits is 1
xorxor eax, edxEach i-th bit in eax and edx will be compared and the i-th bit of eax will be 1 iff one of the compared bits is 1 and the other 0
notnot eaxInverts each bit in eax
testtest eax, edxSame as and eax, edx, changes the FLAGS only, but not the registers

Use

signchanger.asm

segment .text
global changeSign

changeSign:
    mov eax, [esp + 4]  ; get argument
    NOT eax                 ; invert arg
    INC eax                 ; eax++
    ret

This code multiplies any number with -1 much faster than a multiplication operation by just using a bit operation and an increment. So the function changes signs of any number in two's complement.

signChanger-alt.asm

segment .text
global changeSign

changeSign:
    mov eax, [esp + 4]  ; get argument
    NEG eax                 ; negate
    ret

This is the recommended and actually used way to change the sign. The first example was only to show an example for logical operations.

NOTE: All functions in this section do not enter and leave the function. That is not necessary as only EAX is changed and EAX, ECX and EDX may be changed freely anyways.

Bitwise Manipulation

Sometimes it might be necessary to change a specific bit of a value. So let us assume our value is stored in eax.

OperationCode
Turn on bit iOR eax, n where n = 2^i
Turn off bit iAND eax, n where n = NOT (2^i)
Invert bit iXOR eax, n where n = 2^i
Clear registerXOR eax, eax

NOTE: It is recommended to use XOR eax, eax or sub eax, eax for clearing the eax register (or any other) instead of mov eax, 0 as those instructions do not consume much. "Furthermore, they do not consume an issue port or an executon unit. So using zero idioms are preferable than moving 0’s into the register"(Intel® 64 and IA-32 Architectures Optimization Reference Manual, section 3.5.1.8).

Let us take the following function size_t getAbsolute(uint32_t value) which returns the absolute value of the entered value as an example.

absolute.asm

segment .text
global getAbsolute

getAbsolute:
    mov eax, [esp + 4]  ; get argument
    TEST eax, 0x80000000
    JZ  return
    NEG eax
return:
    ret

NOTE: The TEST eax, 0x80000000 instruction does the same as AND eax, 0x80000000 while only changing the flags, but not the registers. This way, it is possible to AND eax,0x80000000 (which keeps only the sign bit turned on) and later check if the result is zero (positive) or not.

Blog Comments powered by Disqus.