Object files contain the binary information which is generated by either assembler or linker. In Linux object files are in Executable and linkable file format (.elf).
In general, we have three types of object files in Linux(i.e. .c file). They are
- Relocatable Object file (.o)
- Executable object file
- Shared Object file (.so)
In this session, we are not going to discuss the shared object file (.so) because this is an advanced concept and you should need to be aware of all the basics before going to look at this.
Note: To proceed further with this article, you need a Unix/Linux-based operating system. If you don’t have that, then please follow this link to install the Linux terminal in windows. It won’t take much time.
Relocatable object file:
A relocatable file holds code and data suitable for linking with other object files to create an executable or a shared object file.
It is generated by the assembler and is also known as a linkable object file because multiple relocatable object files are combined together and an executable file is created by the linker. In order to generate this (.o) file, from the (.c) file, execute the command.
gcc -c file_name.c
This will produce the output file “file_name.o“.
The layout of a relocatable object file:
- Relocatable object files contain a section header table which stores the information about the sections in the program. This file cannot be directly executed by a processor, because it doesn’t contain a program header table.
- The program header table contains info about segments and also holds the info required to create a process image. The linker will add the program header table when we pass the (.o) file to the linker.
Important Sections in the relocatable object file:
.text
The C program that we write will be compiled by using a program called compiler and executable instructions will be generated. All the executable instructions are stored in this .text section. This section will be having RX permission i.e. R – Read, X – Execute (Read and write permission). It is also known as the .code section.
.data
This section stores Initialized global, static variables etc. This section has both Read and write permissions.
.rodata
This section stores the data such as string literals. where this is having read-only permission.
.bss
This section stores the Un-initialized global and static variables. This section has both Read and write permissions.
Executable object file:
An executable file holds a program suitable for execution. This executable object file will be generated by the linker by combining multiple relocatable object files.
In order to generate an executable object file, just enter the below command.
gcc -O file_name.c
The layout of an executable object file:
- Executable object files contain the program header table which will store the info about segments. This file can be directly executed because in program headers it has the required info to create a process image.
- It is not mandatory to have a section header table in executable object files. In case we want to link the executable file with another relocatable object file then we need a section header table.
Important segments in the executable object file:
In an executable object file, we have multiple segments where each segment is formed by combining one or more sections.
Code or text segment:
Multiple sections which are having read-only permissions are combined into a single segment by the linker. Here both the sections .text and .rodata have read permission so they will be combined into a single segment called the code or text segment.
- This code segment has only read and execute permission. If we try to write into a code segment, we will get the segment fault error.
Note: Not only .text & .rodata, but we also have many more sections in the code segment. But to understand C, all those sections are not required for us right now.
Data segment:
Multiple sections such as .data (Initialized data section) &.bss (Non-initialized data section) and etc, will be combined together and formed as a single segment called a Data segment.
- If you notice, both sections have the same read and write permissions. The data segment has read and write permissions.
Stack segment:
The stack segment contains the stack frames which are created when the program is in execution.
- Each stack frame holds the data that is generated by instructions inside the functions.
- Remember, the stack segment doesn’t hold any instructions it just holds the multiple stack frames which are capable to store the data (local variables) of multiple functions.
- For example, we have three functions such as main(), func1() and func2(). when these functions are called, their respective stack frames will be created and each function data i.e. local variables will be stored in their respective stack.
It is impossible to predict the size of the stack segment before the program is in execution.
Heap segment:
The heap segment is used for dynamic memory allocation. i.e. If the user requested the memory while the program is in execution then it is known as dynamic memory allocation. Dynamically memory will be allocated from the heap segment. So, by using malloc() or calloc() functions we can get memory allocated from the heap segment. It has both read and write permissions.
Memory Layout when the program is in execution:
- Each of these segments was placed on different pages, and every page has its own set of permission (read, write, execute) for example, the code segment will be placed on a page having only read and execute permissions.
- So when a user tries to write into a page that is having read and execute permission then segfault will be raised from the kernel level.