Gcc your .c

K.Wong
5 min readFeb 9, 2017

--

What happens when you type gcc main.c in your terminal?

Compiling with command gcc

No, a goat is not compiling your files in the background when you type in gcc main.c. So what is gcc?

  • gcc, also known as GNU Compiler Collection, is a compiler system that supports various programming languages. When handling the C programming language, it is know as GNU C Compiler.
  • You are putting your source code into the gcc compiler to essentially make your program executable, or usable.
  • There are four parts to the gcc compilation process: preprocessing, compilation, assembly and linking. We’ll go through that in the section below.

What are you doing with gcc main.c?

What are you doing when you type in gcc main.c? When you input the command gcc main.c, you are essentially executing the compiler (gcc) on the program (main.c). To be more straightforward: gcc main.c is a command to compile the program main.c.

The gcc compilation stage. Source: https://developer.gnome.org

The above image gives you a visual idea of what happens, but let’s break it down:

Source File > Preprocessor > Compiler > Assembler > Linker > Output

Preprocessing your source file

You source file is your source code or in this case, main.c. For example, in your main.c program, the goal might be to print ‘Hi, I am compiling with gcc’:

# This is the content of your main.c file and we are using vim to show the content:$ vim main.c# This is your main.c code:#include <stdio.h>
#define STRING "I am compiling with gcc"
/**
* main - main block
*
* Return: Always 0 (Success)
**/
int main(void)
{
printf("Hi, %s\n", STRING);
return (0);
}
# The goal of your program is to output this:
>>> Hi, I'm compiling with gcc

Preprocessing is the first stage where your source code passes through. In preprocessing, the following is done to your code:

  • Macro substitution — (A preprocessor line in the form of #define STRING “Hi", which tells the compiler “Hey, I want to define a macro and name is STRING with the text of Hi to replace every instance of STRING in your source code.)
  • Removal of comments — ( Any text between /**/ is a comment and will not be compiled.
  • Expanding of any included files — ( Also known as #include <stdio.h> )

If you want to print out just the preprocessed output, you can just do gcc -E , which will output your file to something like this:

#499 "12.sdk/usr/include/stdio.h” 2 3 4# 2 “main.c” 2int main(void)
{
printf(“Hi, %s\n, ”I am compiling with gcc");
return (0);
}
# Macro substituted from STRING to "I am compiling with gcc"
# Comments have been removed
# The '#include' is gone as it has been expanded and included into our source code, which is how the compiler is able to see the printf() function declared

Compiling your file

Now that you’re preprocessed your file, your compiler takes in your source, compiles it and produces the 2nd stage compiled output. You may not be aware, but if you reference the image in the beginning of this page, you can see the output file after preprocessing ends in main.i , which is temporary. To access this files, you can do the command gcc -save-temps main.c -o main . To break it down:

gcc -save-temps main.c -o main# gcc: the command to compile
# -save-temps: save the temporary files that are created before assembly and linking
# main.c: your source file
# -o: output the results in another file
# main: the output filename (can be anything)
# You'll get something like this:$ ls
>>> main.i main.s main.o

In the compiling stage, the compiler takes in the main.i temporary file as an input, compiles it and then outputs to main.s, which the compiler then moves to the assembly stage.

The Assembly

Let’s take a look as the main.s file to understand what’s going on:

.section        __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 12
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
# This is only a partial copy of the main.s file, but your file should look similar.

What is going on? The above is the main.s in assembly language and is essentially giving instructions to the assembler to understand in order to convert it to machine level language or in layman’s term, “Hey assembler, tell the computer to do this”. Like the main.i file, the main.s is also a temporary file and is taken in as an input to the assembler and outputted as another temporary file with extension “.o” or main.o . The main.o is known as the object file as it contains object code or machine level instructions (binary). It will look something like this:

Ïúíþ^G^@^@^A^C^@^@^@^A^@^@^@^D^@^@^@^@^B^@^@^@ ^@^@^@^@^@^@^Y^@^@^@<88>^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@¸^@^@^@^@^@^@^@ ^B^@^@^@^@^@^@¸^@^@^@^@^@^@^@^G^@^@^@^G^@^@^@^D^@^@^@^@^@^@^@__text^@^@^@^@^@^@^@^@^@^@__TEXT^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@1^@^@^@^@^@^@^@ ^B^@^@^D^@^@^@Ø^B^@^@^C^@^@^@^@^D^@<80>^@^@^@^@^@^@^@^@^@^@^@^@__cstring^@^@^@^@^@^@^@__TEXT^@^@^@^@^@^@^@^@^@^@1^@^@^@^@^@^@^@ # Object code: machine level instructions or binary, which the computer can now execute
# If you compiled your source without a '-o' to output your code into another file, the default output would be 'a.out'

Linking

The linker is the final stage of your compilation process. You’ve gotten everything set up with preprocessing, compiling and assembly, but it is not until the linking stage that gcc can process the printf function. Remember: when gcc goes through the first three stages, all the files are temporary, which means the printf function hasn’t been implemented and all the moving parts are floating around somewhere. What we have right now before linking are temporary placeholders under the linker to add some code to make sense of the main.o file.

The linker’s job is add code that is standard in order for a program to be executable, which may be code to start and end the program, code to set up the program, calling functions and passing arguments as well as linking to any libraries our original source code references to. After everything has been replaced, we now have our final executable program.

To reiterate, by default, the output filename is a.out, so to run it: ./a.out. If you used -o , and named your file as main, you can run it like: ./main

--

--