Writing Function Pointers

Learn how the code is compiled and loaded in memory and how to write function pointers.

Loading and executing code

When we write code inside a source file, we have to compile the source file using a compiler, which results in a binary file.

It’s interesting to explore the steps that convert a source file into an executable file:

  1. The preprocessor step will perform textual replacements inside the source file (removing comments, resolving the #include statements, expanding macros). We don’t go into more detail as this step is not crucial for our current analysis. Note that this step is performed inside the compiler.
  2. The compiler takes the preprocessed source file and converts it into Assembly language, a low-level language.
  3. The Assembly language files are converted into machine code (instructions that the CPU understands) by the Assembler. We obtain a binary file called an object file.
  4. Our code typically uses system libraries or other third-party libraries or object files to achieve its functionality. To link these files together with our object files (obtained in step 3), we need the linker. The linker resolves all dependencies by linking our object files with the required libraries.
    • For example, to write text on the screen, we may use the printf function.
    • This function isn’t implemented in our code but in a system library.
    • The object file from step 3 contains a reference to this function, not its code. At that moment, the code of printf is unknown.
    • The linker will resolve this reference to printf.
  5. Finally, after performing these steps, we have a fully functional executable file that can run on the CPU.

Recall that the executable file contains various segments, such as .data, .bss, .rodata, and .text. The .text section, called .code, is where the code we write gets placed upon completing the executable file generation process.

Get hands-on with 1200+ tech skills courses.