I’ve always been interested in how things work under the hood. Unfortunately, computer science courses I’ve taken in the university haven’t covered low-level details of how a computer works. And the last Uncle Bob’s blog post “Make the Magic go away” convinced me that it’s time to play a little bit at a low level. At first I was thinking about reading a book on IL written by Serge Lidin (as far as I’m a C#-programmer), but then I decided to take a look at the lowest level a programmer can dive into – Assembler. So I made a couple of queries on amazon and found an interesting book named “Assembly Language Step-by-Step: Programming with Linux” by Jeff Duntemann. This book has a pretty high rating and good reviews.
Now, I’m on 117-th page and… there hasn’t been any assembler practice yet… surprise 🙂 Actually, this is not so surprising as I thought at first. The primary audience of this book are newcomers to the low-level world. In case you are a newbie in this field, it would be quite silly to start learning assembler beginning with processor instructions. As the author says, “Nearly all books on assembly start by introducing the concept of an instruction set, and then begin describing machine instructions, one by one. This is moronic, and the authors of such books should be hung. Even if you’ve learned every single instruction in an instruction set, you haven’t learned assembly language.” The thing is that the most important part of working within the low level is memory addressing. The author says about this, “Any idiot can learn machine instructions. Many do. The skill of assembly language consists of a deep comprehension of memory addressing. Everything else is details – and easy details at that.”
There are two essential parts in learning memory addressing:
- Understanding how to convert values between binary and hexadecimal representations. Moreover, you have to learn how to do it fast using your own brain, not a calculator.
- Understanding of some details about how the PC’s hardware work: what is data bus, addressing lines, memory models and some other things.
It seems we can’t calculate in hex and binary as fast as we can in decimals. Hex and binary are just not so convenient. We can’t achieve the same speed of calculating not because we are just not accustomed to calc in hex and binary, but because those systems are really harder to calculate in. That’s it, we can’t do much about that. Of course, there is something we can do to speed up a little our abilities to calculate in hex and binary.
Converting between hex and binary is simple, indeed. We can divide a binary value into 4-bit parts (referred as nibbles, half-bytes, etc) and then convert them into hex-values independently, which is a simple task after some practice. Hex into bin can be converted the same way, only vice-versa. So, binary and hex bases are like siblings, they are quite close to each other, hex is just more convenient for people, because hex-values are much shorter. For example, lets convert 1101111110010010 into hex.
1101 1111 1001 0010
D F 9 2
Quite simple. For addition we have to memorize the following table:
This is the first part of a long journey in the low-level world. I think, I’ll write about the whole bunch of stuff, such as memory models, stacks, heaps, main parts of an operating system (such as Linux) and much more.