Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

From source code to a running program (gcc)

After this lesson: I can name the stages a compiler takes a program through.

50 min lesson8 commandsCompilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

The build that broke at the end

A shop's till program will not build. The error says undefined reference to printf. A colleague starts reading the C code line by line.

The code is fine. The error came from the very last step of the build, which never looks at the code at all. Knowing the steps would have saved an hour.

By the end of this lesson

Note

I can name the stages a compiler takes a program through.

Key words

WordWhat it meansExample
Drivera program that runs the other build programs in ordergcc
Preprocessorthe stage that pastes in files and replaces macros
Assemblerthe program that turns assembly into machine codeas
Object filemachine code that is not yet a whole programhello.o
Symbola name the linker must find, such as a function
Linkerthe program that joins object files and librariesld

The cells students fill in are left blank in this preview.

gcc runs other programs for you

When you type gcc hello.c, gcc does very little itself. It is a driver. It runs other programs, one after another, and passes each one the last one's file.

The option -### makes gcc print those commands and run none of them. The two Runs below go into the lab's folder and show just the program each command starts.

Go into the compiler folder

Command
cd ~/compiler

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

The programs gcc would run

Command
gcc -### -o hello hello.c 2>&1 | grep "^ " | cut -d " " -f 2

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Worked example: three programs, four stages

ProgramStages it doesIt writes
cc1Preprocess, then compileAssembly, a .s file
asAssembleAn object file, .o
collect2Link, by running ldThe program

The cells students fill in are left blank in this preview.

Keep the file from every stage

Normally the files between stages go in a temporary folder and are deleted. The option -save-temps keeps them beside the source.

One build then leaves four files: hello.i after preprocessing, hello.s after compiling, hello.o after assembling, and hello after linking. The command file reads the start of each file and says what kind it is.

Build once, keep everything

Command
gcc -save-temps -o hello hello.c

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

List the folder

Command
ls

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

What kind of file is each?

Command
file hello.i hello.s hello.o hello

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Worked example: what file said

FileMade byWhat file calls it
hello.iThe preprocessorC source, ASCII text
hello.sThe compilerassembler source, ASCII text
hello.oThe assemblerELF 64-bit LSB relocatable
helloThe linkerELF 64-bit LSB pie executable

The cells students fill in are left blank in this preview.

An object file has holes in it

hello.o holds the machine code for square and main. But main calls printf, and printf is not in this file. It lives in the C library.

nm lists an object file's symbols. T means the code is here. U means undefined: a hole the linker must fill.

Then run the linker ld yourself, with no C library. Read what it says.

The symbols in hello.o

Command
nm hello.o

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Link with nothing else

Command
ld hello.o -o broken

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people think every build error means a mistake in their code. An undefined reference comes from the linker, after the code compiled cleanly. It means a symbol's code was never given to the last step. Check what is linked, not the line of C.

Where printf comes from

Command
ldd hello

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Going further

Type these yourself. Copy hello.c to twice.c and change square(7) to twice(7), with no twice function anywhere. Build it with gcc -c twice.c and say which stage spoke.

Now add the line int twice(int n); above main. Build with gcc -c twice.c, read nm twice.o, then build with gcc twice.c. Explain why the two errors come from different stages.

About this lab and its source: Compilers and computer architecture lab: gcc, flex, bison and RISC-V in one VM

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.