Section 2.6 Memory Segmentation
When the user starts the program, the operating system loads it into the memory. Each section of the binary (code, data) will be put at specific addresses in the address space of the program. When running MIPS programs and tracing their execution on the lowest level, it is important to know where in memory which part of the program is located. Note that modern machines provide the abstraction of virtual memory which makes it possible that the each program that runs on the machine uses its own address space. The processor, in cooperation with the operating system, takes care of mapping these virtual addresses to the physical ones by a technique called address translation. Virtual memory is beyond the scope of this book. Here, we do not make the distinction of virtual vs. physical memory and only consider a single program at the time.
In our setting, code starts at address 0x00400000 and the data segment starts at 0x10000000. The addresses above 0x10000000 + \(n\text{,}\) where \(n\) is the size of the static data, is called the heap. The heap can be used freely by the program (see below). The upper 2GB of the address space (starting from address 0x80000000) are reserved for the operating system. Right below starts the stack. The stack is used to hold stack frames which are used to keep temporary values during a functions call. Essentially, the stack is also an area where memory is allocated dynamically, however with a specific policy that we will discuss in further detail in Section 2.8. Note that the stack grows downwards.
Memory Management on the Heap.
When executing machine code that has been produced by a compiler from a higher-level programming language, the heap is usually managed by the runtime system of the language. The runtime system of a language implements some of the abstractions the language provides, for example dynamic memory allocation. When programming machine code directly, there is no runtime system and we have to manage the heap ourselves.
Note that because of virtual memory, we cannot just access memory on the heap because initially there are no physical memory pages mapped into our virtual address space beyond this point. We need to tell the operating system before that we want to do so. The operating system then takes care of providing us with enough (if available) physical memory in our virtual address space. Again, this is beyond the scope of this text and we will just ignore heap memory for the rest of this chapter.
A simple memory management system typically provides two functions: One to allocate memory and one to free previously allocated memory. In C they are called
malloc
and free
. Calling malloc
, the program can obtain a fresh chunk of memory of a size that the program can specify. malloc
guarantees that it never returns the address of a chunk that has been malloc'ed before and not been freed yet. Internally, malloc
organizes the heap in such a way that these guarantees are fulfilled. It also deals with the operating system to map enough physical memory into the heap's address space. We will talk more about dynamic memory allocation in Section 4.12. One thing that is important to understand is that from the perspective of the processor, dynamic memory allocation does not exist and neither is there a difference between static data or data in dynamically-allocated memory. These are just abstractions that we conceived to better align the organization of the flat address space with the way we want to program our computer.