Lab 07
Lab 07
Objectives:
Understand the C compilation process.
Learn to use Command Line Interface (CLI) of GNU C Compiler (GCC).
Learn to compile single code files using GCC, CLI
Learn to compile multiple code files using GCC, CLI
1. Preprocessing
2. Compilation
3. Assembly
4. Linking
We will be using the following piece of code to illustrate this process. Save this code in a file
(using any text editor) and name it
#include<stdio.h>
int main(void)
{
int x = 0; // A variable to hold some data
int y = 5; // and another variable
return(0);
}
Pre-processing:
This is the first phase through which source code is passed. This phase includes:
Removal of Comments
Expansion of Macros
In this stage, lines starting with a character are interpreted by the preprocessor as
preprocessor commands. These commands form a simple macro language with its own syntax
and semantics. This language is used to reduce repetition in source code by providing
functionality to inline files, define macros, and to conditionally omit code.
Before interpreting commands, the preprocessor does some initial processing. This includes
joining continued lines (lines ending with a \) and stripping comments.
To print the result of the preprocessing stage, pass the -E option to gcc:
gcc - \test1.c - Path\
or call the sub-process cpp as follows
cpp \test1.c - \
header file joined with the contents of the test1.c file, stripped free from its leading comments.
[lines omitted for brevity]
return(0);
}
Compilation:
The second stage of compilation is confusingly enough called compilation. In this stage, the
preprocessed code is translated to assembly instructions specific to the target processor
architecture. These form an intermediate human readable language.
The existence of this step allows for C code to contain inline assembly instructions and for
different assemblers to be used.
Some compilers also support the use of an integrated assembler, in which the compilation stage
generates machine code directly, avoiding the overhead of generating the intermediate assembly
instructions and invoking the assembler.
To save the result of the compilation stage, pass the -S option to gcc:
gcc - \ - \test1.s
This will create a file named , containing the generated assembly instructions. On
Windows 7 the following output is generated:
.file "test1.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "The sum of x and y is: %d\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
call ___main
movl $0, 28(%esp)
movl $5, 24(%esp)
movl 28(%esp), %edx
movl 24(%esp), %eax
addl %edx, %eax
movl %eax, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $0, %eax
leave
ret
.ident "GCC: (tdm-1) 5.1.0"
.def _printf; .scl 2; .type 32; .endef
Assembly:
During this stage, an assembler is used to translate the assembly instructions to object code. The
output consists of actual instructions to be run by the target processor.
To save the result of the assembly stage, pass the -c option to gcc:
gcc - \ - \test1.o
or invoke the Assembler as follows:
as \ - \test1.o
Running the above command will create a file named , containing the object code of the
program. The contents of this file are in a binary format and can be inspected using Notepad++:
Linking:
The object code generated in the assembly stage is composed of machine instructions that the
processor understands but some pieces of the program are out of order or missing. To produce an
executable program, the existing pieces have to be rearranged and the missing ones filled in. This
process is called linking.
The linker will arrange the pieces of object code so that functions in some pieces can
successfully call functions in other ones. It will also add pieces containing the instructions for
ogram, the linker will add
the object code for the printf function.
The result of this stage is the final executable program. When run without options, gcc will name
this file test1.exe (on a Windows machine). To name the file something else, pass the -o option
to gcc:
\ - \test1.exe
Or invoke the linker directly passing the Object file as input:
\ - \test1 (This will only work if the correct path
to libraries is provided. Out of scope for this lab.)
This process can be summarized by the following figure:
We saw when discussing functions, that one way of including custom-written functions in your
C code, is to simply place them in your main source file, above the declaration of the main()
function. A better way to re-use functions that you commonly incorporate into your C programs
is to place them in their own file, and to include a statement above main() to include that file.
When compiled, it's just like copying and pasting the code above main(), but for the purpose of
editing and writing your code, this allows you to keep things in separate files. It also means that
if you ever decide to change one of those re-usable functions (for example if you find and fix an
error) that you only have to change it in one place, and you don't have to go searching through all
of your programs and change each one.
Header files
A common convention in C programs is to write a header file (with .h suffix) for each source file
(.c suffix) that you link to your main source code. The logic is that the .c source file contains all
of the code and the header file contains the function prototypes, that is, just a declaration of
which functions can be found in the source file.
This is done for libraries that are provided by others, sometimes only as compiled binary "blobs"
(i.e. you can't look at the source code). Pairing them with plain-text header files allows you see
what functions are defined, and what arguments they take (and return).
Example:
Let's say you want to write a program that takes one integer input from the user, and determines
whether that integer is a prime number or not. Now let's say that you don't want to write your
own code for determining primality, so you ask your friend, who you know has written such a
function already. He sends you a pair of files (primes.h and primes.c). His header file (primes.h)
looks like this:
So we know a couple of things from this header file. It declares a function prototype for
isPrime(). We can see this function takes a single integer as an input argument, and returns an
integer value: 1 if the input value is a prime number, and 0 if it is not. Now we know all we need
to know in order to use this function (without even looking at the function's source code, which
resides in primes.c).
Here is what the primes.c file look like:
int isPrime(int n)
{
int i;
for (i=3; i*i < n; i++) { // test divisibility up to sqrt(n)
if ((n % i) == 0) {
return 0;
}
}
return 1;
}
#include <stdio.h>
#include <stdlib.h>
#include "primes.h"
int main(void)
{
int N;
int prime;
while(1)
{
printf("Enter a number");
scanf("%d", &N);
if(isPrime(N) != 0)
printf("The number %d is prime ",N);
else
{
printf("The number %d is not prime ",N);
break;
}
}
return 0;
Search path
The compiler will look in several places for header files that you include with the #include
directive, depending on how you use it. If you use include with the angled brackets (e.g. #include
<stdio.h>) then the compiler will look in a series of "default" system-wide locations (see Search
Path for details). If you use double-quotes (e.g. #include "neuron.h") then the compiler will look
in the directory containing the current file. It's possible to add other directories to the search path
by using the -Idir compiler option, where dir is the other directory. You might have to do this if
you link your code to an external C library that is not part of the standard C library, and does not
reside in the usual "system" default locations.
In-Lab Task 1:
Using the Notepad (the Windows text editor), save the program given in Code Listing 1 as a C
file (test1.c). Then use the GNU CLI to compile the program and generate the intermediate files
like, test1.i, test1.s, test1.o and finally test1.exe.
Hint: You will have to provide the complete path to source and destination files in double quotes
\
In-Lab Task-2:
Using the Notepad (the Windows text editor), save the programs given in Code Listing 2, 3 and 4
as c/h files (primes.h, primes.c, and go.c). Then use the GNU CLI to compile the program and
generate the intermediate files like, go.i, go.s, go.o and finally go.exe.
Post-Lab Task:
Submit a hand written report on what difficulties you faced in the lab, what sources of
information did you refer to to solve your problems, and what were the solutions you
implemented.
Reference Links:
1. https://www.gribblelab.org/CBootCamp/12_Compiling_linking_Makefile_header_files.html
2. https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
3. https://www.classes.cs.uchicago.edu/archive/2017/winter/51081-1/LabFAQ/lab2/compile.html#compilation_steps
4. https://www.gribblelab.org/CBootCamp/
5. https://www.geeksforgeeks.org/compiling-a-c-program-behind-the-scenes/
6. https://www.youtube.com/watch?v=VDslRumKvRA
7. https://www.youtube.com/watch?v=N2y6csonII4
Lab Assessment
Pre Lab /1
In Lab /5
Writing Style /4