The compilation of a C program is a sophisticated process that transforms high-level C code into machine-executable instructions. This multi-stage pipeline ensures that human-readable code is converted into efficient binary code that computers can execute directly.
The compilation of a C program is a sophisticated process that transforms high-level C code into machine-executable instructions. This multi-stage pipeline ensures that human-readable code is converted into efficient binary code that computers can execute directly.
The preprocessing stage prepares the source code for compilation by performing several text manipulations:
#include: Inserts the contents of header files into the source code
#define: Replaces macros and constants with their defined values
#ifdef, #ifndef, #endif: Handles conditional compilation
#pragma: Provides implementation-specific instructions to the compiler
For example, when encountering #include, the preprocessor locates the stdio.h file and inserts its entire content at that position. Similarly, for #define MAX_SIZE 100, every occurrence of MAX_SIZE in the code is replaced with 100.
The output of this stage is an expanded source code file (typically with a .i extension) that contains no preprocessor directives.
The compilation stage converts the preprocessed code into assembly language:
During this stage, the compiler detects errors such as missing semicolons, undeclared variables, type mismatches, and other syntax violations. The output is typically an assembly file (.s extension) containing human-readable assembly instructions.
The assembly stage converts assembly code into machine code:
The resulting object file contains machine instructions that correspond directly to the target processor's instruction set, but it cannot be executed yet as it lacks necessary linking information.
The linking stage combines multiple object files and libraries to create the final executable:
The linker detects errors such as undefined references, multiple definitions of the same symbol, or missing the main() function. The output is a complete executable program ready to be loaded and run by the operating system.
If we used functions stored inside libraries, it will link it to our file so that the program knows where to look at to find said function. There are two types of libraries:
- Static libraries (.lib, .a): its code is put inside the binary file, which increase its size;
- Dynamic libraries (.dll, .so): the name of the library is put inside the binary file and is loaded when first called.
By default, gcc use dynamic libraries.
Static Linking
Static lib have extension (.a)
Example:
- I have a file is isalpha to check if the character is alphabetic while the other checks if the integer is even
main.h
1#ifdef MAIN_H
2#define MAIN_H
3
4// prototypes
5int _iseven(int n);
6int _isalpha(int c);
7
8#endif /* MAIN_H*/
1#ifdef MAIN_H
2#define MAIN_H
3
4// prototypes
5int _iseven(int n);
6int _isalpha(int c);
7
8#endif /* MAIN_H*/
isalpha.c
1// file isalpha.c
2#include "main.h"
3int _isalpha(int c) {
4 if (condition) {
5 return ...
6 }
7}
1// file isalpha.c
2#include "main.h"
3int _isalpha(int c) {
4 if (condition) {
5 return ...
6 }
7}
Similar with file iseven.c
Then, stop at step assembly with:
Create the static library using:
Explain command:
Dynamic Linking
With the extension .so for dynamic libraries. Using libraries enable us to call functions without hard coding them inside the source code file as we can call a lot of different functions depending on the program we are creating.
How to create dynamic lib:
Explain command:
Explain command:
To verify that we did it correctly and have the right functions as dynamic symbols we can use nm -D libname.so.
Consider a simple C program in a file named "example.c":
example.c
1#include "stdio.h"
2#define GREETING "Hello, World!"
3
4int main() {
5 // Print greeting message
6 printf("%s\n", GREETING);
7 return 0;
8}
9
1#include "stdio.h"
2#define GREETING "Hello, World!"
3
4int main() {
5 // Print greeting message
6 printf("%s\n", GREETING);
7 return 0;
8}
9
The compilation process would proceed as follows:
1. Preprocessing: Comments are removed, GREETING is replaced with "Hello, World!", and the contents of stdio.h are inserted.
2. Compilation: The preprocessed code is analyzed and converted to assembly language specific to the target architecture.
3. Assembly: The assembly code is converted to machine code, creating the object file example.o.
4. Linking: The object file is linked with the C standard library (which contains the implementation of printf) to create the final executable.
To compile a C program using GCC (GNU Compiler Collection), you can use:
This command performs all four stages and produces an executable named "example". To perform each stage separately:
terminal
1# Preprocessing only
2gcc -E example.c -o example.i
3
4# Compilation to assembly
5gcc -S example.i -o example.s
6
7# Assembly to object code
8gcc -c example.s -o example.o
9
10# Linking to create executable
11gcc example.o -o example
12
13# It is possible to keep a file for each steps by doing
14gcc file.c -save-temps
1# Preprocessing only
2gcc -E example.c -o example.i
3
4# Compilation to assembly
5gcc -S example.i -o example.s
6
7# Assembly to object code
8gcc -c example.s -o example.o
9
10# Linking to create executable
11gcc example.o -o example
12
13# It is possible to keep a file for each steps by doing
14gcc file.c -save-temps
main.js
button.tsx
1hehe
2what
1hehe
2what
1hehe
2why
1hehe
2why
1hehe
2what
1hehe
2what
1hehe
2why
1hehe
2why
Reference link here
Reference link here
Reference link here
Reference link here
Reference link here