We have already done bit operations in Chapter 9 on integer arithmetic: shift arithmetic sar and sal are bit operations, shifting bits right or left. Also, the and instruction for aligning the stack covered in the previous chapter is a bit operation.
Basics
In the following example program, we are building a custom C function called printb to print a string of bits. For convenience, it separates the string of 64 bits into 8 bytes, with 8 bits each. As an exercise, after you finish this chapter, take a look at the C code, and you should be able to write an assembler program to build a string of bits.
bits1.asm
printb.c
makefile for bits1 and printb
Build and run the program and study the output. If you are using SASM, do not forget to compile the printb.c file first and then add the object file in the Linking Options, as mentioned when discussing external functions in Chapter 14.
First note the binary representation of number1 (-72); the 1 in the most significant bit indicates a negative number.
The instructions xor, or, and, and not are pretty simple; they work as explained in Chapter 5. Experiment with different values to see how it works.
For shl , shr , sal , and sar , we use the lower byte of rax to illustrate what is going on. With shl, bits are shifted to the left and zeros are added to the right of al; the bits are moved to the left, and the bits that move to the left of the 8th bit are simply discarded. With shr, bits are shifted to the right and zeros are added to the left of al. All bits are moved to the right, and bits that move to the right of the least significant bit are dropped. When you are stepping through the program, keep an eye on the flag registers, especially the sign register and the overflow register.
The arithmetic left shift, sal, is exactly the same as shl; it multiplies the value. The arithmetic shift right, sar, division, is different from shr. Here we have what is called sign extension. If the leftmost bit in al is a 1, al contains a negative value. To do the arithmetic correctly, when shifting right, 1s instead of 0s are added to the left in case of a negative value. This is called sign extension.
Rotate left, rol , removes the leftmost bit, shifts left, and adds the removed bits to the right. Rotate right, ror , works in a similar way.
Arithmetic
Let’s do some deep dive into shifting arithmetic. Why are there two types of shift left and two types of shift right? When doing arithmetic with negative values, shift instructions can give you wrong results, because sign extension needs to be taken into account. That is why there are arithmetic shift instructions and logical shift instructions.
bits2.asm
Notice that shl and sal give the same results, also with negative numbers. But be careful; if shl would put a 1 in the leftmost bit instead of a 0, the result would become negative and wrong.
The instructions shr and sar give the same result only when the numbers are positive. The arithmetic result when using shr with negative numbers is simply wrong; that is because there is no sign extension with shr.
Conclusion: when you are doing arithmetic, use sal and sar.
Why would you need shifting when there are straightforward instructions such as multiply and divide? It turns out the shifting is much faster than the multiplying or dividing instructions. In general, bit instructions are very fast; for example, xor rax, rax is faster than mov rax,0.
Summary
Assembly instructions for bit operations
Difference between logical and arithmetic shift instructions