0% found this document useful (0 votes)
3 views

labtask11

This document outlines the process of compiling, assembling, and loading a high-level program in MIPS architecture. It describes the MIPS memory map, detailing the text, global data, dynamic data, and reserved segments, as well as the steps involved in translating high-level code into machine language and executing it. The document also includes laboratory tasks for practical application of these concepts.

Uploaded by

omarashraf13456
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

labtask11

This document outlines the process of compiling, assembling, and loading a high-level program in MIPS architecture. It describes the MIPS memory map, detailing the text, global data, dynamic data, and reserved segments, as well as the steps involved in translating high-level code into machine language and executing it. The document also includes laboratory tasks for practical application of these concepts.

Uploaded by

omarashraf13456
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Department of Computer Science

Institute of Business Administration, Karachi

Lab #11: Compiling, Assembling, and Loading

Computer Architecture & Assembly Language


April 22, 2024

Course Instructor ..........................................................Salman Zaffar Lab Instructor


............................................................Mehwish Zafar Week Performed ...............................................................:
Week 11 Room .............................................................................MTL4

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.1 The Memory Map


With 32-bit addresses, the MIPS address space spans 232 bytes 4 gigabytes (GB). Word
addresses are divisible by 4 and range from 0 to 0xFFFFFFFC. Figure 1 shows the MIPS
memory map. The MIPS architecture divides the address space into four parts or segments:
the text segment, global data segment, dynamic data segment, and reserved segments. The
following sections describes each segment.

1
Figure 1: MIPS memory map

1.1.1 The Text Segment


The text segment stores the machine language program. It is large enough to accommodate
almost 256 MB of code. Note that the four most significant bits of the address in the text space
are all 0, so the j instruction can directly jump to any address in the program.

1.1.2 The Global Data Segment


The global data segment stores global variables that, in contrast to local variables, can be seen
by all procedures in a program. Global variables are defined at start-up, before the program
begins executing. These variables are declared outside the main procedure in a C program and
can be accessed by any procedure. The global data segment is large enough to store 64 KB of
global variables.
Global variables are accessed using the global pointer ($gp), which is initialized to 0x100080000.
Unlike the stack pointer ($sp), $gp does not change during program execution. Any global
variable can be accessed with a 16-bit positive or negative offset from $gp. The offset is known
at assembly time, so the variables can be efficiently accessed using base addressing mode with
constant offsets.

1.1.3 The Dynamic Data Segment


The dynamic data segment holds the stack and the heap. The data in this segment are not
known at start-up but are dynamically allocated and deallocated throughout the execution of
the program. This is the largest segment of memory used by a program, spanning almost 2 GB
of the address space.
As discussed before, the stack is used to save and restore registers used by procedures and to
hold local variables such as arrays. The stack grows downward from the top of the dynamic

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.

1.1.4 The Reserved Segments


The reserved segments are used by the operating system and cannot directly be used by the
program. Part of the reserved memory is used for interrupts (e.g. undefined instructions and
arithmetic overflow) and for memory-mapped I/O in which a portion of the address space is
dedicated to I/O devices rather than memory.
For example, suppose that addresses in the range 0xFFFF0000 to 0xFFFFFFFF are used for
I/O. By dedicating a portion of the address space to I/O devices, the computer’s hardware and
operating system can efficiently manage communication between the CPU and these devices.
This allows programs to interact with external devices seamlessly, enabling tasks such as
printing documents, transferring data over a network, or reading input from a keyboard.

1.2 Translating and Starting a Program


Figure 2 shows the steps required to translate a program from a high-level language into
machine language and to start executing that program. First, the high-level code is compiled
into assembly code. The assembly code is assembled into machine code in an object file. The
linker combines the machine code with object code from libraries and other files to produce
an entire executable program. Finally, the loader loads the program into memory and starts
execution. The remainder of this section walks through these steps for a simple program.

Figure 2: Steps for translating and starting a program

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.

Figure 3: Compiling A High-Level Program

1.2.2 Step 2: Assembling


The assembler turns the assembly language code into an object file containing machine
language code. The assembler makes two passes through the assembly code. On the first pass,
the assembler assigns instruction addresses and finds all the symbols, such as labels and global
variable names. The code after the first assembler pass is shown here.

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.

Figure 4: Symbol Table

1.2.3 Step 3: Linking

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)

0x8 addi a0,zero,4

0xc la a1, num1

0x10 la a1, num1

0x14 sw a0, 0(a1)

0x18 addi a2,zero,8

0x1c la a3, num2

0x20 la a3, num2

0x24 sw a2,0(a3)

0x28 jal sum

0x2c sw a5,0(a4)

0x30 lw ra,0(sp)

0x34 addi sp,sp,4

0x38 jr ra

0x3c Sum_val: add a4,a0,a2

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

Text segment size: 40 bytes for 10 instructions

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

You might also like