Preprocessing, compiling, assembling, and linking

s.drawio.png

The compiling a multi-file c program is multi stage process:
an overview of the process:

Preprocessing, Compiling, Assembling and Linking

Preprocessing

The preprocessing step is the first phase of compiling a C program.It removes comments, expands macros, and includes headers. It controls compilation with #ifdef, #ifndef, #pragma directives.

*compiling:

The compilation step converts the expanded source code into assembly language after checking the preprocessed code for syntax errors and performs optimizations if specified**.**

Example of the Compilation Step:

#include <stdio.h>

int
main(void)
{
	puts("Hello, World!");
	return 0;
}

After running:

gcc -S main.c -o main.s

we get:

        .file   "main.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello, World!"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        endbr64
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        leaq    .LC0(%rip), %rax
        movq    %rax, %rdi
        call    puts@PLT
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 14.2.0-4ubuntu2) 14.2.0"
        .section        .note.GNU-stack,"",@progbits
        .section        .note.gnu.property,"a"
        .align 8
        .long   1f - 0f
        .long   4f - 1f
        .long   5
0:
        .string "GNU"
1:
        .align 8
        .long   0xc0000002
        .long   3f - 2f
2:
        .long   0x3
3:
        .align 8
4:

Assembling

The assembler (as) converts assembly instructions into binary format that the CPU understands.
but

To assemble the file, run:

gcc -c main.s -o main.o

to view the binary file:

objdump -d main.o

output:

main.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <main>:
   0:   f3 0f 1e fa             endbr64
   4:   55                      push   %rbp
   5:   48 89 e5                mov    %rsp,%rbp
   8:   48 8d 05 00 00 00 00    lea    0x0(%rip),%rax        # f <main+0xf>
   f:   48 89 c7                mov    %rax,%rdi
  12:   e8 00 00 00 00          call   17 <main+0x17>
  17:   b8 00 00 00 00          mov    $0x0,%eax
  1c:   5d                      pop    %rbp
  1d:   c3                      ret

We are almost done, but there is one issue: how does the puts function execute when its code is not included in the object file? The final stage fixes that.

Linking

The assembly stage generates object code containing machine instructions that the processor understands. However, some pieces of the program remain out of order or missing. To create an executable program, these pieces must be rearranged and completed—this process is called linking.

The linker organizes the object code pieces so functions can properly call each other across different sections. It also incorporates object code for any library functions the program uses. For example, in the "Hello, World!" program, the linker adds the object code for the puts function.

This stage produces the final executable program. By default, cc names this file a.out. To specify a different name, use the -o option with cc:

cc -o hello_world hello_world.c

image.png