Introduction
Hello Ninjas, We hope you have encountered the term compiler in your programming journey. You can think of a compiler as a translator who translates a high-level language into a low-level language without making any changes in the meaning of the program so that it can be understood by computers.
Cousins of a compiler consist of a preprocessor, an assembler, and a loader and linker, which play an essential role in converting a high-level language into a low-level language along with the Compiler.
Don't worry if you haven't heard about them before because, in this article, we will learn about them in detail.
So without any delays, let's dive deep into the topic.

Cousins of Compiler
Converting a high-level language into a low-level language takes multiple steps and involves many programs apart from the Compiler. Before the compilation can start, our source code needs to be preprocessed. After the compilation, our code needs to be converted into executable code to execute on our machine. These essential tasks are performed by the preprocessor, assembler, Linker, and Loader. They are known as the Cousins of the Compiler. Let's study them in detail.

Let's see who the cousins of Compiler are and what their contributions are in the process of converting a high-level language into a low-level language.
Preprocessor
The preprocessor is one of the cousins of the Compiler. It is a program that performs preprocessing. It performs processing on the given data and produces an output. The output generated is used as an input for some other program.
The preprocessor increases the readability of the code by replacing a complex expression with a simpler one by using a macro.
A preprocessor performs multiple types of functionality and operations on the data.
Some of them are-
Macro processing
Macro processing is mapping the input to output data based on a certain set of rules and defined processes. These rules are known as macros.
Rational Preprocessors
Relational preprocessors are the processors that change older languages with some modern flow-of-control and data-structuring facilities.
File Inclusion
The preprocessor is also used to include header files in the program text. A header file is a text file included in our source program file during compilation. When the preprocessor finds an #include directive in the program, it replaces it with the entire content of the specified header file.
Language extension
Language extension is used to add new capabilities to the existing language. This is done by including certain libraries in our program, which provides extra functionality. An example of this is Equel, a database query language embedded in C.
Error Detection
Some preprocessors are capable of performing error-checking on the source code that is given as input to them. For example, it can check if the headers files are included properly and if the macros are defined correctly or not.
Conditional Compilation
Certain preprocessors are capable of including or excluding certain pieces of code based on the result of a condition. They provide more flexibility to the programmers for writing the code as they allow the programmers to include or exclude certain features of the program based upon some condition.
Assembler
Assembler is also one of the cousins of the compiler. A compiler takes the preprocessed code and then converts it into assembly code. This assembly code is given as input to the assembler, and the assembler converts it into the machine code. Assembler comes into effect in the compilation process after the Compiler has finished its job.
There are two types of assemblers-
- One-Pass assembler: They go through the source code (output of Compiler) only once and assume that all symbols will be defined before any instruction that references them.
- Two-Pass assembler: Two-pass assemblers work by creating a symbol table with the symbols and their values in the first pass, and then using the symbol table in a second pass, they generate code.
Linker
Linker takes the output produced by the assembler as input and combines them to create an executable file. It merges two or more object files that might be created by different assemblers and creates a link between them. It also appends all the libraries that will be required for the execution of the file. A linker's primary function is to search and find referred modules in a program and establish the memory address where these codes will be loaded.
Multiple tasks that can be performed by linkers include-
-
Library Management: Linkers can be used to add external libraries to our code to add additional functionalities. By adding those libraries, our code can now use the functions defined in those libraries.
-
Code Optimization: Linkers are also used to optimize the code generated by the compiler by reducing the code size and increasing the program's performance.
- Memory Management: Linkers are also responsible for managing the memory requirement of the executable code. It allocates the memory to the variables used in the program and ensures they have a consistent memory location when the code is executed.
- Symbol Resolution: Linkers link multiple object files, and a symbol can be redefined in multiple files, giving rise to a conflict. The linker resolves these conflicts by choosing one definition to use.
Loader
The loader works after the linker has performed its task and created the executable code. It takes the input of executable files generated from the linker, loads it to the main memory, and prepares this loaded code for execution by a computer. It also allocates memory space to the program. The loader is also responsible for the execution of programs by allocating RAM to the program and initializing specific registers.
Following tasks are performed by the loader
- Loading: The loader loads the executable files in the memory and provides memory for executing the program.
- Relocation: The loader adjusts the memory addresses of the program to relocate its location in memory.
-
Symbol Resolution: The loader is used to resolve the symbols not defined directly in the program. They do this by looking for the definition of that symbol in a library linked to the executable file.
- Dynamic Linking: The loader dynamically links the libraries into the executable file at runtime to add additional functionality to our program.
Also see, Cross Compiler