Unfortunately we’re going to have to be a little theoretical in this post. We’ll be covering how we use memory in our assembly programs, in particular how the stack works.
When we execute our code, it is loaded into a nice big block of contiguous memory. The very first address in this block, address 0, is kept inaccessible from our program. If you have programmed in C before you will be familiar with null pointers. A null pointer is a pointer that points to memory address 0. The fact that this address is inaccessible to our program is why we can define a pointer with numeric value 0 to be null.
After address 0, there are various other things loaded into memory. Our instructions and data is loaded at address 0x0804800. After this there is a big empty space, the last address before this empty space is called the system break. If you try to access either the memory before 0x0804800 or inside the empty space after our instructions you will get a segmentation fault.
At the very top of the memory, is the stack. This is a special region of expandable memory that our code can use to store values on the fly. Reading and writing to the stack is slower than reading and writing to registers, but sometimes we need to use it. We typically use the stack for two different reasons, we don’t have enough space in the registers or we are changing context and want to save the current registers.
When we add new values to the stack it grows downwards into the empty space after our instructions and data. There really is a lot of space there so you shouldn’t worry too much about filling it up. We maintain the stack with a special register rsp
, this should always contain the memory address of the top of the stack. We can access the contents of the stack using the rsp
pointer directly. When we do this we have to be careful to maintain the value in the register so that it always points to the top of the stack.
We can also access the stack with the popq
and pushq
instructions. The popq
instruction copies the value that the stack pointer currently points at into the register supplied and moves the stack pointer up to the next memory address. Similarly pushq
copies the value in the named register into the next address after the current top of the stack and moves the stack pointer forward to this new address.
The stack doesn’t start off empty. When our programs begins the stack will contain the following in order:
- Various environment variables
- Command line arguments
- The name of the program
- The number of command line arguments
So when our program begins executing, the stack register, rsp
, will be pointing at the topmost value in the stack, that is, the memory location containing the number of command line arguments passed.
In our next post we will see how to read command line arguments off the stack.