C Language Compiled Code

C Language Compiled Code

C Language Compiled Code refers to the machine-readable version of a program written in the C programming language. When you write C source code in human-readable files (.c and .h), it cannot be executed directly by a computer. A compiler translates this source code through several stages including preprocessing, compilation to assembly, assembling into object code, and linking with libraries to produce a standalone executable file. The resulting compiled code consists of binary instructions that the CPU can interpret and run directly. This makes compiled code fundamentally different from the original C source code, which is intended for humans to read, write, and modify.

Source Code

The code is in C language (.c and .h files)

cat # Command used to display the contents of a file
test.c # The C source file whose contents will be printed to the terminal

(host) cat test.c

#include <stdio.h> // Includes the Standard Input/Output library so we can use functions like printf()

int main(){ // The main function: program execution starts here
  printf(“Hello World!”); // Prints the text “Hello World!” to the standard output (usually the terminal)
  return 0; // Ends the program and returns 0 to the operating system indicating successful execution
}

#include <stdio.h>

int main(){
printf("Hello World!");
return 0;
}

Pre-Processor

This step includes the headers and expand the macros, the generated file have the .i, .ii extensions  

gcc # GNU C Compiler
-E # Tells gcc to run only the preprocessor (expands #include, #define, etc.)
test.c # The C source file being processed
| # Pipe operator; sends the output of the command on the left to the command on the right
head # Displays only the first 10 lines of the output

(host) gcc -E test.c | head

# 0 "test.c"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 0 "<command-line>" 2
# 1 "test.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4

Compiler

The expanded code/preprocessed code gets converted into assembly code, the generated file have the .s, .asm extensions 

gcc # GNU C Compiler
-S # Tells gcc to compile the code into assembly language but not create an executable
test.c # The C source file being compiled

(host) gcc -S test.c

cat # Command used to display the contents of a file
test.s # The generated assembly language file from the compilation step

(host) cat test.s

        .file   "test.c"
        .text
        .section        .rodata
.LC0:
        .string "Hello World!"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        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
        movl    $0, %eax
        call    printf@PLT
        movl    $0, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .ident  "GCC: (Debian 14.2.0-16) 14.2.0"
        .section        .note.GNU-stack,"",@progbits

Assembler

The assembly code gets converted into object code/machine code, the generated file have the .o, .obj extensions  

gcc # GNU C Compiler
-c # Compile the source code into an object file (machine code) without linking
test.c # The C source file being compiled

(host) gcc -c test.c

cat # Outputs the contents of the file
test.o # Object file containing compiled machine code
| # Pipe operator; sends output of the left command to the right command
xxd # Converts binary data into a hexadecimal (hex) and ASCII representation
| # Pipe operator again
head # Displays only the first 10 lines of the hex output

(host) cat test.o | xxd | head

00000000: cffa edfe 0c00 0001 0000 0000 0100 0000  ................
00000010: 0400 0000 b801 0000 0020 0000 0000 0000  ......... ......
00000020: 1900 0000 3801 0000 0000 0000 0000 0000  ....8...........
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 6800 0000 0000 0000 d801 0000 0000 0000  h...............
00000050: 6800 0000 0000 0000 0700 0000 0700 0000  h...............
00000060: 0300 0000 0000 0000 5f5f 7465 7874 0000  ........__text..
00000070: 0000 0000 0000 0000 5f5f 5445 5854 0000  ........__TEXT..
00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000090: 3400 0000 0000 0000 d801 0000 0200 0000  4...............
...
...
...

Linker

The last step is combining the object code/machine code and .lib/.a static library files, the generated file have the .exe, elf, bin extensions

gcc # GNU C Compiler used to compile and link the program
test.c # The C source file being compiled
-o # Option to specify the name of the output file
test.bin # Name of the final executable binary file that will be created

(host) gcc test.c -o test.bin

cat # Outputs the contents of the file
test.bin # The compiled executable binary file
| # Pipe operator; sends output of one command to another
xxd # Converts binary data into hexadecimal and ASCII representation
| # Pipe operator again
head # Displays the first 10 lines of the output

(host) cat test.bin | xxd | head

00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000  .ELF............
00000010: 0300 3e00 0100 0000 5010 0000 0000 0000  ..>.....P.......
00000020: 4000 0000 0000 0000 9036 0000 0000 0000  @........6......
00000030: 0000 0000 4000 3800 0e00 4000 1f00 1e00  ....@.8...@.....
00000040: 0600 0000 0400 0000 4000 0000 0000 0000  ........@.......
00000050: 4000 0000 0000 0000 4000 0000 0000 0000  @.......@.......
00000060: 1003 0000 0000 0000 1003 0000 0000 0000  ................
00000070: 0800 0000 0000 0000 0300 0000 0400 0000  ................
00000080: 9403 0000 0000 0000 9403 0000 0000 0000  ................
00000090: 9403 0000 0000 0000 1c00 0000 0000 0000  ...............
...
...