Individual bit manipulation techniques in assembly

The unit of information is the bit. It takes only one binary digit, either the value 0 or the value 1. A byte is comprised of 8 bits.

People created the byte as an ordered set of 8 bits. And they used the byte as the unit of addressable information. By that, I mean that each memory address in a computer points to a byte, not a bit.

So, memory address number 0 points to the first byte in memory. Memory address number 1 points to the second byte in memory. And so on. And the same holds true for storage. In storage, whole bytes are stored and retrieved, not individual bits.

This is for efficiency. Thus, a byte is treated as the smallest bundle of information. I guess, when people first created the bundles of information that they would use, they made an ingenious decision.

The unit of information was the bit, but to use a small ordered bundle of bits to hold an encoding of a letter or number or punctuation symbol, they would need more than four bits. This is because 4 bits correspond to 2^4=16 different permutations. And the English alphabet alone is 26 letters. Add 10 for the individual digits of the numbers (0 to 9) and add more for the punctuation symbols and other control characters that they needed for the operation of the computer (line feeds, etc.), people saw that 2^7=128 permutations were needed, which correspond to 7 bits per byte, since one byte would correspond to a letter or number or punctuation symbol or control character.

Electronic components were scarce the days those decisions were made. So 7 bits per byte would be perfectly adequate. But people made the ingenious decision to use 8 bits per byte. 8 is a power of 2, so people could calculate sizes in either bits or bytes and use the same base (2). Also, a byte could represent more symbols of information (2^8=256 permutations). Another huge reason that a byte was made to comprise of 8 bits was that in this way a byte could be represented with two hexadecimal numbers. Let me give you an example. The byte 10011110 can be represented as 9E in hexadecimal notation, since 1001 in binary is 9 in hexadecimal, and 1110 in binary is E in hexadecimal.

So, people used the concept of the byte as an ordered set of 8 bits to hold the smallest amount of information that they would address or store. A byte (which is comprised of 8 bits) would represent a character or a number from 0 to 9 or a punctuation symbol or a computer control character or another graphical symbol from a small set of predefined symbols. And of course, if a single byte would be considered to contain a purely numeric value, this would be from 00000000 in binary or 0 in decimal to 11111111 in binary or 255 in decimal.

According to all the above, it will be no surprise to learn that assembly commands also operate on full bytes. So, how will you be able to manipulate a byte’s individual bits, if the need arises?

In this blog post, I will teach you exactly that. I will show you how to use assembly commands to manipulate each individual bit of a byte. All we need in order to understand the concepts, is to study the truth tables of AND, OR, and XOR.

AND

```Truth table for AND
-------------------------------------
Input bit   Input bit   Resulting bit
0           0           0
0           1           0
1           0           0
1           1           1```

From the above table, we can gather the following:

If you AND any bit with 0, the result is 0.

If you AND any bit with 1, the result is the bit.

Therefore, AND can be used to set any bit of a byte to 0, regardless of the bit’s previous value.

Here is how: Suppose we have a byte and we want to set one or more of its bits to 0. All we need to do is to AND the byte with a byte that has 0’s in the bit positions that we want to set to 0 and 1’s in the bit positions that we want to remain unchanged.

Example question: Given the byte 10110010, set both the second bit from the right and the fourth bit from the right to 0.

```MOV AL, 10110010b
AND AL, 11110101b```

The result is in AL (and it should be equal to 10110000).

(In the two assembly commands above, please note the suffix b, which stands for “binary”, and is used to denote that the byte is given in its 8 binary bits form.)

OR

```Truth table for OR
-------------------------------------
Input bit   Input bit   Resulting bit
0           0           0
0           1           1
1           0           1
1           1           1```

From the above table, we can gather the following:

If you OR any bit with 0, the result is the bit.

If you OR any bit with 1, the result is 1.

Therefore, OR can be used to set any bit of a byte to 1, regardless of the bit’s previous value.

Here is how: Suppose we have a byte and we want to set one or more of its bits to 1. All we need to do is to OR the byte with a byte that has 1’s in the bit positions that we want to set to 1 and 0’s in the bit positions that we want to remain unchanged.

Example question: Given the byte 10110010, set both the second bit from the right and the fourth bit from the right to 1.

```MOV AL, 10110010b
OR AL, 00001010b```

The result is in AL (and it should be equal to 10111010).

XOR

```Truth table for XOR
-------------------------------------
Input bit   Input bit   Resulting bit
0           0           0
0           1           1
1           0           1
1           1           0```

From the above table, we can gather the following:

If you XOR any bit with 0, the result is the bit.

If you XOR any bit with 1, the result is the bit flipped.

Therefore, XOR can be used to flip any bit of a byte.

Here is how: Suppose we have a byte and we want to flip one or more of its bits. All we need to do is to XOR the byte with a byte that has 1’s in the bit positions that we want to flip and 0’s in the bit positions that we want to remain unchanged.

Example question: Given the byte 10110010, flip both the second bit from the right and the fourth bit from the right.

```MOV AL, 10110010b
AND AL, 00001010b```

The result is in AL (and it should be equal to 10111000).

Conclusion

With AND, OR, and XOR, we can manipulate individual bits, even though these commands (as all assembly commands) operate on full bytes.

All you have to remember is these six facts:

• AND a bit with 0 and the result is 0.
• OR a bit with 1 and the result is 1.
• XOR a bit with 1 and the bit is flipped.
• AND a bit with 1 and the result is the original bit.
• OR a bit with 0 and the result is the original bit.
• XOR a bit with 0 and the result is the original bit.

I cannot let you leave like this. Here is one more example for the road:

Example question: Write a program that transforms the byte stored in the AL register. The byte should be transformed as follows: Its first bit from the right must be set to 0. Its second bit from the right must be set to 1. Its third bit from the right must be flipped. That’s it. Let’s roll. And let’s be careful out there.

Answer: These transformations cannot be performed with one operation. We will need three distinct operations. Here they are:

```AND AL, 11111110b
OR AL, 00000010b
XOR AL, 00000100b```

And I hope that you find obvious the fact that these operations (assembly commands) can be performed in any order. After all three operations are performed, the result will be in the AL register.