labtask11
labtask11
1 Introduction
Up until now, we have shown how to translate short high-level code snippets into assembly
and machine code. This section describes how to compile and assemble a complete high-level
program and how to load the program into memory for execution. We begin by introducing
the MIPS memory map, which defines where code, data, and stack memory are located. We
then show the steps of code execution for a sample program.
1
Figure 1: MIPS memory map
2
data segment (0x7FFFFFFC) and is accessed in last-in-first-out (LIFO) order. The heap stores
data that is allocated by the program during runtime. The heap grows upward from the bottom
of the dynamic data segment.
If the stack and heap ever grow into each other, the program’s data can become corrupted. The
memory allocator tries to ensure that this never happens by returning an out-of-memory error
if there is insufficient space to allocate more dynamic data.
3
1.2.1 Step 1: Compilation
A compiler translates high-level code into assembly language. Code Example shows a simple
high-level program with three global variables and two procedures, along with the assembly
code produced by a typical compiler. The .data and .text keywords are assembler directives
that indicate where the text and data segments begin. Labels are used for global variables f, g,
and y. Their storage location will be determined by the assembler; for now, they are left as
symbols in the code.
The names and addresses of the symbols are kept in a symbol table, as shown in Figure 4
for this code. The symbol addresses are filled in after the first pass, when the addresses of
4
labels are known. Global variables are assigned storage locations in the global data segment
of memory, starting at memory address 0x10000000. On the second pass through the code,
the assembler produces the machine language code. Addresses for the global variables and
labels are taken from the symbol table. The machine language code and symbol table are
stored in the object file.
Most large programs contain more than one file. If the programmer changes only one of the
files, it would be wasteful to recompile and reassemble the other files. In particular, programs
often call procedures in library files; these library files almost never change. If a file of
highlevel code is not changed, the associated object file need not be updated. The job of the
linker is to combine all of the object files i nto o ne m achine l anguage file called the
executable. The linker relocates the data and instructions in the object files so that they are
not all on top of each other. It uses the information in the symbol tables to adjust the addresses
of global variables and of labels that are relocated.
In our example, there is only one object file, so no relocation is necessary. Figure 5 shows the
executable file. It has three sections: the executable file header, the text segment, and the data
segment. The executable file header reports the text size (code size) and data size (amount of
globally declared data). Both are given in units of bytes. The text segment gives the
instructions and the addresses where they are to be stored.
The figure shows the instructions in human-readable format next to the machine code for
ease of interpretation, but the executable file includes only machine i nstructions. The data
segment gives the address of each global variable. The global variables are addressed with
respect to the base address given by the global pointer, $gp.
5
Figure 5: Executable The first store instruction, sw $a0,
0x8000($gp), stores the value 2 to the global variable f, which is located at memory address
0x10000000. Remember that the offset, 0x8000, is a 16-bit signed number that is sign-
extended and added to the base address, $gp. So, $gp + 0x8000 = 0x10008000 + 0xFFFF8000
= 0x10000000, the memory address of variable f.
1.2.4 Step 4: Loading
The operating system loads a program by reading the text segment of the executable file from
a storage device (usually the hard disk) into the text segment of memory. The operating system
sets $gp to 0x10008000 (the middle of the global data segment) and $sp to 0x7FFFFFFC (the
top of the dynamic data segment), then performs a jal 0x00400000 to jump to the beginning
of the program. Figure 7 shows the memory map at the beginning of program execution.
6
Figure 6: Executable loaded in memory
2 Laboratory Tasks
2.1 Write a code of your choice in high level language and explain the
process of compilation, assembling, linking, and loading.
7
2.1.1 Compilation of High Level code into Machine Code
8
2.1.2 Assemble the assembly language code into an object file containing machine
language code.
9
1. Assigns instruction addresses that depicts the starting and ending of your text segment.
Instruction Addresses Assembly Instruction
0x0 Main: addi sp,sp,-4
0x4 sw ra,0(sp)
0x24 sw a2,0(a3)
0x2c sw a5,0(a4)
0x30 lw ra,0(sp)
0x38 jr ra
0x40 jr ra
2. Finds all the symbols, such as labels and global variable names and make a Symbol
Table.
Symbol Address
Num1 0x10000000
Num2 0x10000004
Sum 0x10000008
Main 0x0
Sum_val 0x3c
10
2.1.3 Linking: Combining the object files into one machine language file or Executable
File. Fill the table below as per your memory addresses.
11
12
Data Segment size: 30 bytes for 5 values
2.1.4 Loading: Write the values of following registers that depicts the starting addresses
of text, data, and stack segments.
PC 0x40
gp 0x10000000
sp 0x7FFFECD0
13