Overview of Modern x86_64 Assembly Language
Modern x86_64 Assembly Language allows us to write programs on your computer.. Assembly is a low level language. In other words, you are basically writing machine code directly. This forces you to have a good understanding of how the processor and memory work together. The main difference between Assembly and Machine Language is that you don’t have to remember the machine codes. In Assembly, you just need to remember mnemonics that represent instructions.
Another important advantage of Assembly is that you use labels for certain blocks of code. These labels represent starting addresses for blocks of code. As you make changes to your program, the starting address of various blocks of code will change. In Assembly language, we don’t need to update all of these addresses as you would in machine code. The Assembler will automatically find the address of these labels, and update all references accordingly.
For example, let’s say you have a block of logic to terminate your program at address 2000h. You need to call this block of logic many times throughout your program. By adding 1 instruction above this block, you might move the address of the block to 2002h. If all of your addresses were hard-coded to 2000h, then you would have to update all of those references in your program.
On the other hand, if you have a label on this block such as _endProgram: and reference that label throughout your project, it’s OK if the address this label represents changes. The assembler will automatically find the address when you assemble your code. Really, addresses are a bit more complicated on a modern machine, but that concept gives you a good idea as to why we need labels.
Instructions, Registers, and Memory
When you begin writing assembly language, it’s important to understand the difference between instructions, registers, and memory. Instructions are actions the processor takes. These instructions read and write data. This data can reside either in registers, or in memory.
REGISTERS store data on board the processor. Registers operate much more quickly than memory. Think of registers as a workspace that are immediately on your desktop. All of the data is directly in front of you, and is fast and easy to get to. You have a limited number of registers available. There are 32 bit registers available for a 32 bit system. For a 64 bit system, these registers have 64 bits available to them, and you have an additional registers on top of that. In other words, 64 bit systems give you a bigger desktop to work with.
On the other hand, you can think of MEMORY as information that is in a file cabinet. It takes longer to access at first, but once you load the data from memory into a register, we can work with it much more quickly. For all practical purposes, there is more memory on the computer that one person could probably ever use. That is to say, unless you are working with very large arrays of data.
Assembling and Linking your Code
After you write your code, you need to assemble your code to create what’s called an “Object File”. This converts your code to machine language. After that, we run a “Linker” on this object file to generate your program. The Linker simply ties different object files together to create your entire program. This might include libraries that allow your code to interact with the operating system.
There are several assemblers available such as TASM, NASM, and GAS. In this case, I’m using Debian Linux, and I’ll be running the GNU Assembler (GAS) in future posts. Generally, a compiled Linux program will not run on a Windows machine, and vice versa. To install GAS on Debian (or Debian-based distributions such as Ubuntu), simply install build-essential:
sudo apt-get install build-essential
In future posts, we’ll be writing and building assembly language projects. Once your project is complete, we’ll simply build the object code using GAS (as command), and then run the Linker (ld) to create our executable program. In the example below, we’ll compile an assembly language file called “maximum.s”. As you can see, I’m running the linker after that to create an executable file.
As I said before, this is the first post in a series of posts that will guide us through writing assembly language projects. To view other posts, visit the Information Technology Category Page!
— Ricky Bryce