compiling a c program

2022-01-13

 | 

~5 min read

 | 

869 words

How do you actually compile a C program? What are the steps to go from authoring a program in C to running it?

Steps:

  1. Author
  2. Compilation
    • Pre-process
    • Compile
    • Assemble
    • Link
  3. Run

Author

The authoring step is where you actually write your program.

This can be as big or small as you want.

Let’s write a small “Hello, World!”1

hello-world.c
// program that prints Hello, World!
#include<stdio.h>
int main()
{
    printf("Hello, world!\n");
}

Compile

The compilation step is actually an aggregate of several sub-steps.

In one step, we can use the gcc compiler:

% gcc -Wall hello-world.c -o hello-world

This compilation has two flags:

  1. Wall which enables warnings about construction
  2. o which allows us to specify the output file.

To learn about other flags, check out the compiler’s manual.

One way to see the intermediate steps is to use the save-temps flag:

% gcc -save-temps -Wall hello-world.c -o hello-world

Now, instead of just the compiled file, we can see the steps that the compiler goes through.

% gcc -save-temps -Wall hello-world.c -o hello-world
% ls -la
total 200
drwxr-xr-x   9 stephen.weiss  staff    288 Jan 13 14:22 .
drwxr-xr-x+ 85 stephen.weiss  staff   2720 Jan 13 14:22 ..
-rwxr-xr-x   1 stephen.weiss  staff  49424 Jan 13 14:22 hello-world
-rw-r--r--   1 stephen.weiss  staff   3168 Jan 13 14:22 hello-world.bc
-rw-r--r--   1 stephen.weiss  staff    101 Jan 13 14:07 hello-world.c
-rw-r--r--   1 stephen.weiss  staff  28130 Jan 13 14:22 hello-world.i
-rw-r--r--   1 stephen.weiss  staff    760 Jan 13 14:22 hello-world.o
-rw-r--r--   1 stephen.weiss  staff    666 Jan 13 14:22 hello-world.s
-rw-r--r--   1 stephen.weiss  staff    101 Jan 13 14:08 pbcopy

My initial understanding for this process and the details for the steps comes from Vikash Kumar’s write up for Geeks for Geeks and Wendy Leung’s How the Compilation Process Works for C Programs

Pre-Process

This is a preparation step. In this step, the compiler looks for directives (indicated by the #) and removes comments and expands macros / included files. It will also replace symbolic constants defined using the #define directive with the appropriate value.

In our hello-world.c, we included the #include directive.

In our case, we told the compiler to include the stdio header file. During this step, the compiler will go and find that header file.

If compiled with the -save-temps flag, the pre-process file is the .i.2

Compile

The next step in the process is the compile step which receives as input the output of the preprocessor step and outputs assembly language.

If compiled with the -save-temps flag, the compiled file is the .s.3

Assemble

Following the compile step is the assemble step. In this step, the compiler converts the assembly code into binary / machine code. If compiled with the -save-temps flag, the compiled file is the .o.4

The final step in the process is the linking. In this step the linker merges all of the output modules into a single module.

If libraries are used, the linker will link the code to the library’s function code.

There are two types of linking: static and dyanmic. In static linking, all referenced code is copied. In dynamic linking, the code is not copied but is instead linked through a reference to the library in the binary output.

Run

Now that we have a compiled C program, we can run it:

% ./hello-world
Hello, world!

Wrap up

This is not the most in-depth article. There’s plenty more to be said about how each of the steps work when it comes to compiling a C program, but this gives me a basis from which to expand. I know the parts and the mechanisms.

Footnotes

  • 1 C programmers may object to this file as it has a return type of an int but no return statement. It would be more appropriate to do so, for example:

    hello-world.
    #include <stdio.h>
    
    int main()
    {
        printf("Hello, World!\n");
        return 0;
    }
  • 2 The file in full at this point looks like the following:

    hello-world.i
    # 1 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h" 1 3 4
    # 31 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h" 3 4
    # 1 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_common.h" 1 3 4
    # 32 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h" 2 3 4
    # 42 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h" 3 4
    extern int __sprintf_chk (char * restrict, int, size_t,
        const char * restrict, ...);
    # 52 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h" 3 4
    extern int __snprintf_chk (char * restrict, size_t, int, size_t,
        const char * restrict, ...);
    
    extern int \_\_vsprintf_chk (char _ restrict, int, size_t,
    const char _ restrict, va_list);
    
    extern int \_\_vsnprintf_chk (char _ restrict, size_t, int, size_t,
    const char _ restrict, va_list);
    
      # 400 "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h" 2 3 4
    
      # 3 "hello-world.c" 2
    
      int main()
      {
          printf("Hello, world!\n");
      }
  • 3 The file in full at this point looks like the following:

    hello-world.s
            .section        __TEXT,__text,regular,pure_instructions
            .build_version macos, 11, 0     sdk_version 12, 1
            .globl  _main                           ## -- Begin function main
            .p2align        4, 0x90
    _main:                                  ## @main
            .cfi_startproc
    ## %bb.0:
            pushq   %rbp
            .cfi_def_cfa_offset 16
            .cfi_offset %rbp, -16
            movq    %rsp, %rbp
            .cfi_def_cfa_register %rbp
            leaq    L_.str(%rip), %rdi
            movb    $0, %al
            callq   _printf
            xorl    %eax, %eax
            popq    %rbp
            retq
            .cfi_endproc
                                            ## -- End function
            .section        __TEXT,__cstring,cstring_literals
    L_.str:                                 ## @.str
            .asciz  "Hello, world!\n"
    
    .subsections_via_symbols

Related Posts
  • A Tour of computer Systems: Notes


  • Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!