Core Assembly Concepts

Application Binary Interface

No matter what language a program was written in, it has to play by the rules to get along with system libraries, operating system services and other code modules it may be linked with when it executes. The Application Binary Interface (ABI) is the rule of the road for binaries and it lays out how registers can be used, how their values must be preserved across function calls, how function parameters are to be passed, and often how memory such as the stack is to be structured. ABIs come in many flavors and some processors support a wide variety of them. x86 and x64 processors have specific rules specified by the architecture itself as to which registers pertain to stack management and which registers are to be preserved across function calls. I will go into detail about the x86 32 bit ABI as used on Windows in a later article outlining function prologues, epilogues, and stack management conventions.

Address Space

Modern processors lay out memory as a long string of bytes starting at address 0 and going out to some large number (4,294,967,295 for 32 bit processors, 18,446,744,073,709,600,000 for 64 bit processors). This long string of bytes is called the address space. This space is cut into two and the top half is called the stack and the bottom half is called the heap. We’ll cover the heap in a later section, we’ll cover the stack here in the section below. I should note that modern processors don’t expose physical memory directly to end user applications. Instead the processor creates a sandbox called virtual memory. Each user application sees its own isolated address space and is prevented from touching memory owned by other processes except through well defined and secured channels. Processors provide address translation machinery to convert a programs memory address (which is an address in its virtual memory) to a physical address in the real memory. For most purposes this magic is unimportant for the application programmer. Where it does merit consideration, I will point it out explicitly.

The Stack

The stack is where function parameters and local variables live. Because the stack starts at the top of the address space, it grows from high address values on down to lower address values. As you make function calls, their parameters and local variables get pushed onto the stack and the stack grows downwards. This is by convention and all modern processors follow this convention. It could have been the other way around but no one does it that way and so today we all think about stacks as growing downwards. Keeping this consistent across processors makes life  a little easier for system and application developers as they move from processor type to processor type.

Structuring the stack like this also makes debugging somewhat easier because debuggers can read the data from the lowest level of the stack on upwards and determine which functions called which other functions and with what parameters (there are some caveats concerning parameters which we’ll cover when we talk about processors that pass most parameters in registers like the X64 does). If you have ever heard of the term “Walking the stack” this is what it means, reading the stack from the bottom up to see who asked for what from whom.

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Your email address will not be published. Required fields are marked *