When a program is compiled, it is divided into several sections that categorize the types of data and instruction it contains. These sections help the linker organize and manage program's memory layout efficiently.
Here are the primary sections you will encounter:
- .text
- .data
- .bss
- .rodata
- .comment
- .eh_frame
- .init, .fini, .ctors, .dtors
- Heap and Stack (though not sections in the binary, they are crucial in memory layout)
1 Visualization of Program Sections
Consider a typical memory layout for a simple program:
Memory Address
|--------------|----------------------|
| Section | Description |
|--------------|----------------------|
| 0x00000000 | .text (code) |
| | - Executable code |
|--------------|----------------------|
| 0x00100000 | .rodata (read-only) |
| | - Constants |
|--------------|----------------------|
| 0x00200000 | .data (initialized) |
| | - Global/static vars |
|--------------|----------------------|
| 0x00300000 | .bss (zero-init) |
| | - Uninitialized vars |
|--------------|----------------------|
| 0x00400000 | Heap |
| | - Dynamic allocation |
|--------------|----------------------|
| 0x00500000 | Stack |
| | - Function call data |
|--------------|----------------------|
2 Detailed Explanation of Each Section
1 .text
Section:
Contains the executable code of the program.
Characteristics:
- Read-only
- Executable
Memory Example:
0x08048000: start: MOV EAX, 1
0x08048005: ADD EAX, 2
0x08048008: INT 0x80 ; syscall
2 .rodata
Section:
Stores read-only data such as string literals and constants.
Characteristics:
- Read-only
Memory Example:
0x08049000: "Hello, World!\0"
3 .data
Section:
Contains initialized global and static variables.
Characteristics:
- Read-write
Memory Example:
0x0804A000: int_var: 0x12345678
0x0804A004: char_var: 'A'
4 .bss
Section:
Contains uninitialized global and static variables, which are zeroed out at runtime.
Characteristics:
- Read-write
Memory Example:
0x0804B000: uninit_var: 0x00000000
0x0804B004: another_var: 0x00000000
5 .comment
Section:
Typically includes comments or metadata (not used at runtime).
Characteristics:
- Often discarded
Memory Example:
(This section is often not loaded into memory and may contain version info or compiler metadata.)
6 .eh_frame
Section:
Used for exception handling (part of the stack unwinding process).
Characteristics:
- Read-only
Memory Example:
(Contains frame unwind information for exception handling.)
7 init, .fini, .ctors, .dtors
Sections:
Contain initialization and finalization code and constructors/destructors for C++.
Characteristics:
.init
and.fini
are used for initialization and cleanup routines..ctors
and.dtors
are used for constructors and destructors.
Memory Example:
.init
0x08048000: _init_start:
0x08048004: <init code>
.fini
0x08048010: _fini_start:
0x08048014: <cleanup code>
.ctors
0x08048020: constructor_list:
0x08048024: <address of constructor>
.dtors
0x08048030: destructor_list:
0x08048034: <address of destructor>
8 Heap and Stack
- Heap: Used for dynamic memory allocation (
malloc
,free
).- Grows upwards in memory.
- Stack: Used for function call management (local variables, return addresses).
- Grows downwards in memory.
3 Creating Custom Sections
3.1 In C:
3.1.1 Creating Custom
To place variables or function in the custom section, you can use GCC-specific attributes in your C code.
#include <stdio.h>
// Placing a variable in the custom section
int my_custom_variable __attribute__((section(".mycustomsection"))) = 42;
// Placing a function in the custom section
void my_custom_function(void) __attribute__((section(".mycustomsection")));
void my_custom_function(void) {
printf("Hello from custom section!\n");
}
int main() {
printf("Custom variable value: %d\n", my_custom_variable);
my_custom_function();
return 0;
}
Code Attributes
__attribute__((section(".mycustomsection")))
: This GCC-specific attribute places the variable or function in the.mycustomsection
.- The custom variable and function will be located in the memory region specified for
.mycustomsection
.
3.1.1 Linker Script Example:
Here's a sample linker script that defines custom sections:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
OUTPUT("custom_sections.bin")
MEMORY
{
ROM (rx) : ORIGIN = 0x08048000, LENGTH = 0x00001000
RAM (rwx) : ORIGIN = 0x08049000, LENGTH = 0x01000000
}
SECTIONS
{
.text : {
*(.text)
. = ALIGN(4096);
} > ROM
.data : {
*(.data)
. = ALIGN(4096);
} > RAM
.bss : {
*(.bss)
. = ALIGN(4096);
} > RAM
.mycustomsection : {
*(.mycustomsection)
. = ALIGN(4096);
} > RAM
/DISCARD/ : {
*(.comment)
*(.eh_frame)
}
}
Linker Script (.mycustomsection)
.mycustomsection
: This custom section is defined to store any data or code labeled with the.mycustomsection
attribute.*
indicates that all input sections with the specified name should be included in this output section.> RAM
places the custom section in RAM. You can change this to another memory region if needed.. = ALIGN(4096);
ensures that the section is aligned on a 4096-byte boundary, which can be important for performance or hardware requirements.
3.1.2 Visualizing Custom Sections
Here's how the memory layout might look with a custom section added:
Memory Address
|--------------|----------------------|
| Section | Description |
|--------------|----------------------|
| 0x08048000 | .text (code) |
| | - Executable code |
|--------------|----------------------|
| 0x08049000 | .rodata (read-only) |
| | - Constants |
|--------------|----------------------|
| 0x0804A000 | .data (initialized) |
| | - Global/static vars |
|--------------|----------------------|
| 0x0804B000 | .bss (zero-init) |
| | - Uninitialized vars |
|--------------|----------------------|
| 0x0804C000 | .mycustomsection |
| | - Custom data/funcs |
|--------------|----------------------|
| 0x0804D000 | Heap |
| | - Dynamic allocation |
|--------------|----------------------|
| 0xFFFFE000 | Stack |
| | - Function call data |
|--------------|----------------------|
In this example:
.mycustomsection
starts at address0x0804C000
and includesmy_custom_variable
andmy_custom_function
.
3.2 In Assembly
3.2.1 Assembly Code with Custom Sections
Let's start with an example in assembly where we define a custom section named .mycustomsection
.
.section .text
.globl _start
_start:
call my_custom_function
mov $1, %eax # syscall: exit
xor %ebx, %ebx # exit code 0
int $0x80
.section .mycustomsection
.globl my_custom_function
my_custom_function:
# Function body
push %ebp
mov %esp, %ebp
mov $message, %eax
call print_string
pop %ebp
ret
message:
.asciz "Hello from custom section!\n"
.section .data
print_string:
# Print string pointed to by %eax
push %ebp
mov %esp, %ebp
mov %eax, %ecx # Pointer to string
mov $4, %eax # syscall: write
mov $1, %ebx # file descriptor: stdout
mov $24, %edx # message length
int $0x80
pop %ebp
ret
- .section .text
- The
.text
section contains the_start
label, which is the entry point of the program. _start
callsmy_custom_function
and then exits.
- The
- .section .mycustomsection
- This section is defined as
.mycustomsection
. - It contains the
my_custom_function
and a message string.
- This section is defined as
- .section .data
- The
.data
section contains theprint_string
function, which is used to print a string to the console.
- The
3.2.2 Linker Script with Custom Sections
Next, we need a linker script that defines where our custom section should be placed in memory.
OUTPUT_FORMAT(elf32-i386)
ENTRY(_start)
OUTPUT("custom_sections.bin")
MEMORY
{
ROM (rx) : ORIGIN = 0x08048000, LENGTH = 0x00001000
RAM (rwx) : ORIGIN = 0x08049000, LENGTH = 0x01000000
}
SECTIONS
{
.text : {
*(.text)
. = ALIGN(4096);
} > ROM
.data : {
*(.data)
. = ALIGN(4096);
} > RAM
.bss : {
*(.bss)
. = ALIGN(4096);
} > RAM
.mycustomsection : {
*(.mycustomsection)
. = ALIGN(4096);
} > RAM
/DISCARD/ : {
*(.comment)
*(.eh_frame)
}
}
PROVIDE(_stack_start = 0xFFFFE000);
PROVIDE(_heap_start = 0x0804C000);
- OUTPUT_FORMAT(elf32-i386)
- Specifies the output file format, in this case, 32-bit ELF for x86.
- ENTRY(_start)
- Defines the entry point of the program as
_start
.
- Defines the entry point of the program as
- MEMORY Block
- ROM: Read-only memory region, starting at
0x08048000
with a length of0x00001000
bytes. - RAM: Read-write memory region, starting at
0x08049000
with a length of0x01000000
bytes.
- ROM: Read-only memory region, starting at
- SECTIONS Block
- .text: Contains the
.text
section and aligns it to the next 4096-byte boundary. - .data: Contains the
.data
section and aligns it to the next 4096-byte boundary. - .bss: Contains the
.bss
section and aligns it to the next 4096-byte boundary. - .mycustomsection: Contains the
.mycustomsection
and aligns it to the next 4096-byte boundary. - /DISCARD/: Discards the
.comment
and.eh_frame
sections.
- .text: Contains the
- PROVIDE Statements
- _stack_start: Defines the start of the stack at
0xFFFFE000
. - _heap_start: Defines the start of the heap at
0x0804C000
.
- _stack_start: Defines the start of the stack at
3.2.3 Building and Linking
To assemble and link this program, you would typically use the following commands:
as -o program.o program.s
ld -T linker_script.ld -o program program.o
3.2.4 Visualizing the Memory Layout
Here's how the memory layout might look with the custom section:
Memory Address
|--------------|----------------------|
| Section | Description |
|--------------|----------------------|
| 0x08048000 | .text (code) |
| | - Executable code |
|--------------|----------------------|
| 0x08049000 | .rodata (read-only) |
| | - Constants |
|--------------|----------------------|
| 0x0804A000 | .data (initialized) |
| | - Global/static vars |
|--------------|----------------------|
| 0x0804B000 | .bss (zero-init) |
| | - Uninitialized vars |
|--------------|----------------------|
| 0x0804C000 | .mycustomsection |
| | - Custom data/funcs |
|--------------|----------------------|
| 0x0804D000 | Heap |
| | - Dynamic allocation |
|--------------|----------------------|
| 0xFFFFE000 | Stack |
| | - Function call data |
|--------------|----------------------|