Memory

Introduction

You've already learned about memory, how you can access it with addresses, and how programs often live in memory with other memory segments like the Heap and Stack. Surprise, surprise, the programs we can write with instructions live in memory as well. With our new knowledge of instructions, you can use this memory to store things that may be very large or of an unknown length.

Memory and Lists

Using instructions like mov you can access the data at some memory location. Say another part of the program provided you with the memory address to a writeable place in memory. You could write to it like so:

// rax = memory addr

mov [rax], 0x1337

Now, let's say we wanted to make a list of numbers. We say this list would be 4 numbers large and look like:

my_list = [2, 4, 8, 16]

Assuming the memory at my_list label has enough space, we could set up the list like so:

// my_list is a label to some free data we can write too
mov rax, my_list
mov [rax], 0x2
mov [rax+4], 0x4
mov [rax+8], 0x8
mov [rax+0xc], 0x10

In this example, we assumed that the number will be at a max of 4 bytes large. This is important and changes the way we could get the memory back. Say we now wanted to use the data we stored in memory. We would now need to use 4 byte versions of our registers to assure we get the right number (since its only 4 bytes, not 8):

// my_list is a label to data with numbers of size 4 bytes
mov rax, my_list
mov edi, [rax]
mov esi, [rax+4]
mov edx, [rax+8]
mov ecx, [rax+0xc]

Stack

You may remember from the memory-segments section that we have two special writeable locations in memory: the Stack and the Heap. For the purpose of simplicity, we don't go over how to access and use the Heap in this module since it requires using more complicated instructions. For now, we can just use writeable program memory as we would the Heap since we can consider the case where all we get is an address to a writeable location.

The Stack is very similar to normal writeable locations. It has addresses and it can be directly dereferenced like a normal address. The Stack is special though because it works like a literal stack (think stacking pancakes), and it has a dedicated register (rsp), to tell you where the top of the stack currently is.

Working with the Pancake Stack

Say your mom places 3 pancakes on your plate: pancake 1, 2, and 3.

Pancake Stack:

  #######################
  |      pancake 1      |
  #######################
  ~~~~~~~~~~~~~~~~~~~~~~~
  #######################
  |      pancake 2      |
  #######################
  ~~~~~~~~~~~~~~~~~~~~~~~
  #######################
  |      pancake 3      |
  #######################
|=========================|

You can't just access pancake 3, that would destroy the stack (and make your mom mad). You need to access pancake 1 first, then 2, then 3. When you access the pancake on the top, we call it a pop. Yes, you literally pop the pancake into your mouth. We represent that with the instruction:

pop mouth

Which results in the new pancake stack:

Pancake Stack:

  #######################
  |      pancake 2      |
  #######################
  ~~~~~~~~~~~~~~~~~~~~~~~
  #######################
  |      pancake 3      |
  #######################
|=========================|

Now, the top of the stack is pancake 2. We would say the pancake stack pointer is pointing at the location where the second pancake is located now. It was originally pointing at the location of pancake 1, but we poped the stack.

So you pop mouth another pancake:

Pancake Stack:

  #######################
  |      pancake 3      |
  #######################
|=========================|

Before you can do another pop, your mom pushes a fresh new pancake on your plate with the instruction:

push pancake_4

Now the stack looks like:

Pancake Stack:

  #######################
  |      pancake 4      |
  #######################
  ~~~~~~~~~~~~~~~~~~~~~~~
  #######################
  |      pancake 3      |
  #######################
|=========================|

Now the top of the stack points to pancake 4.

Working with the Real Stack

Now you understand how the stack works. You can save stuff there temporarily with push and retrieve with pop. The special register rsp points to the top of the stack. When you do a push it results in rsp -= 8. When you pop it results in rsp += 8.

Recall: the stack grows down by making the stack address smaller as you need more space. If you need to expand 8 bytes, you would subtract 8 from the rsp.