Understanding Object Code in C 🔬
Object code is the binary, machine-readable translation of your C
source code. It's the output of the compiler and assembler and is stored
in an object file (usually with a .o
or .obj
extension).
Think of it this way: if your source code is a manuscript written in English, the object file is that manuscript translated into French (machine code). However, it's missing the library and table of contents needed to be a complete book. That final step is handled by the linker.
Key Characteristics of an Object File
·
Contains
Machine Code: It holds the raw binary
instructions for the functions and variables that were defined in its
corresponding .c
source file.
· Contains a Symbol Table: This is a crucial piece of metadata. The symbol table is a list of all the global functions and variables (symbols) that the file either:
o Defines:
Provides the implementation for (e.g., your main
function).
o References:
Uses but does not define (e.g., the printf
function).
· It is Relocatable: The memory addresses within an object file are not final. The linker is responsible for assigning the final memory locations and adjusting (relocating) the code to work in that final layout.
· It is Not Executable: You cannot run an object file directly. It's an incomplete program because it's missing the code for any library functions it references, as well as the startup code required by the operating system.
Role in the Compilation Process
The object file is the output of the third stage of compilation (Assembly) and the input for the final stage (Linking).
Source Code (.c)
→ Preprocessor
→ Compiler
→ Assembly Code (.s)
→ Assembler
→ Object Code (.o)
→ Linker
→ Executable
Its primary role
is to enable modular programming. In a project with multiple .c
files, each one is compiled into its own object file.
If you only modify one source file, you only need to recompile that single
file. The linker can then quickly re-link all the existing object files, which
is much faster than recompiling the entire project.
Example: Creating and Inspecting an Object File
Let's take a simple C file and see what its object file looks like.
Source Code (hello.c
):
C
#include <stdio.h>
int main() {
printf(
"Hello, Object Code!\n");
return
0;
}
1.
Compilation Command We can use the -c
flag with GCC to stop the compilation process after
the assembly stage, which generates only the object file.
Bash
gcc -c hello.c -o hello.o
This
command creates hello.o
.
2. Inspecting
the Symbol Table We can use a tool
like nm
(on Linux/macOS) to inspect the symbol table of the
object file.
Bash
nm hello.o
Output and Explanation:
0000000000000000 T main
U printf
This output tells us exactly what the linker needs to know:
·
T main
: The symbol main
is defined (T
means it's in the text/code section) within this object file.
·
U printf
: The symbol printf
is Undefined (U
). This object file uses printf
, but its code is not here. The linker must find the
code for printf
in another library (the C standard library) and link
it in to create the final executable.
An object file is a structured, intermediate binary file that contains relocatable machine code and associated metadata. It's the compiler's output and the linker's input, forming a critical bridge between source code and a runnable program.