Article by Ayman Alheraki on January 11 2026 10:37 AM
----------------------------------
.bss Section: Storing Uninitialized DataIn the context of low-level programming, particularly when using the GNU Assembler (GAS), the .bss section plays a pivotal role in memory management by handling uninitialized data. It is one of the most important sections in assembly programming and understanding how it works is crucial for efficient memory utilization and the creation of optimized, functional programs. In this section, we will explore the .bss section in great detail, covering its purpose, functionality, advantages, and how it fits within the overall memory layout of a program. Additionally, we will look into various directives used to manipulate the .bss section.
.bss Section?The .bss section (Block Started by Symbol) is a segment of memory reserved for uninitialized global or static variables. These variables are declared but not given a predefined value in the source code. The primary advantage of the .bss section is that it allows programs to allocate space for these variables without actually including the initial values in the binary file. Instead, when the program is loaded into memory, the operating system initializes this space, typically setting the values to zero (or a platform-specific default).
In the binary file, the .bss section does not contribute any data. Its role is purely to indicate that a certain portion of memory needs to be reserved. The actual memory is allocated by the operating system when the program is loaded into the memory space. This differs from the .data section, where values are stored directly in the executable, contributing to the file's size.
.bss SectionThe .bss section provides several important benefits when managing uninitialized variables:
One of the primary advantages of the .bss section is memory efficiency. Since the .bss section does not store any actual data in the executable file, it allows a program to reserve memory without increasing the size of the binary. When a program is compiled, the .bss section only defines the size of the space required, not the actual data to be stored. The operating system allocates the required space in memory when the program is loaded and initializes it to a default value (usually zero).
For example, when you declare a global variable in the .bss section like so:
.section .bssmy_var: .skip 4This tells the assembler to reserve 4 bytes of memory for my_var without storing any specific value in the executable. The value is initialized at runtime, saving both space in the binary and avoiding the unnecessary storage of large amounts of uninitialized data.
The .bss section is initialized at runtime. When the program is loaded into memory, the operating system ensures that all uninitialized data in the .bss section is zeroed out (or initialized to a default value). This is particularly useful for ensuring that variables do not contain garbage values when the program begins execution. For example, in C/C++ programming, global static variables that are declared but not initialized are typically placed in the .bss section.
One of the key features of the .bss section is that the operating system automatically initializes the reserved space to zero (or another default value, depending on the system). This means that any variable in the .bss section is guaranteed to start with a neutral value, which is often zero, simplifying the initialization process for variables.
.bss SectionThe .bss section can be manipulated using several directives within GAS. These directives provide the programmer with the tools to reserve memory for uninitialized variables.
.skip DirectiveThe .skip directive is used to reserve a specific number of bytes in the .bss section. It is the most common directive used to allocate memory without initializing it. For example:
.section .bssmy_var: .skip 4 # Reserve 4 bytes of memory for 'my_var'Here, .skip 4 tells the assembler to reserve 4 bytes of memory for the variable my_var. This space will be zeroed out by the operating system when the program is loaded.
.space DirectiveThe .space directive, like the .skip directive, is used to reserve space in the .bss section, but it may be preferred for aligning purposes. The .space directive reserves a specific number of bytes and is used in scenarios where you need to explicitly define the size of the memory block:
.section .bssbuffer: .space 64 # Reserve 64 bytes of memory for 'buffer'In this example, the .space directive reserves 64 bytes of uninitialized memory for the buffer variable. As with the .skip directive, the operating system will initialize this space to zero at runtime.
.comm DirectiveThe .comm directive is used to define common symbols in the .bss section. These common symbols can be shared between multiple object files, which is useful in larger programs spread across several source files. The .comm directive allocates a block of space for the symbol and ensures that the space is shared across all object files that reference it.
.section .bss.comm my_array, 256 # Reserve 256 bytes for 'my_array'This line reserves 256 bytes for my_array and ensures that the memory space is shared among all the files that reference this symbol. This is especially useful for large programs where memory for global variables needs to be allocated dynamically.
.bss Section Fits into the Memory LayoutThe .bss section is part of the data segment of a program's memory layout. A typical memory layout consists of several segments that serve different purposes:
Text Segment: Contains the executable code (instructions).
Data Segment: Stores initialized variables and constants (the .data section).
BSS Segment: Allocates space for uninitialized global variables (the .bss section).
Heap: A region used for dynamic memory allocation (managed during runtime).
Stack: A region for local variables, function call frames, and storing return addresses.
The .bss section resides between the data segment and the heap. When a program is loaded, the operating system allocates space in the .bss section, initializing the memory to zero (or another default value). This makes it easier to manage uninitialized data by having the OS handle the initialization.
.bss SectionOnce the memory for the .bss section has been allocated at runtime, it can be accessed and manipulated in the same way as variables in other sections like the .data or .text sections. The main difference is that, in the .bss section, the variables are not initialized with any values in the source code, so they are empty until explicitly assigned a value during execution.
For example, if a program defines a variable in the .bss section and wishes to store a value in it during execution, the following steps would occur:
The .bss section reserves space for the variable.
The program loads a value into a register (e.g., eax).
The program stores the value from the register into the variable in the .bss section.
.section .bssmy_counter: .skip 4 # Reserve 4 bytes for 'my_counter'
.section .text.global _start_start: movl $100, %eax # Load the value 100 into register 'eax' movl %eax, my_counter # Store the value from 'eax' into 'my_counter' # Exit the program movl $1, %eax # Syscall number for sys_exit xorl %ebx, %ebx # Set return code to 0 int $0x80 # Trigger the syscallIn this example:
The .bss section reserves 4 bytes of memory for the my_counter variable.
The program stores the value 100 into the my_counter variable during execution.
The program exits using a system call.
.bss Section with the .data SectionA comparison between the .bss section and the .data section can help clarify their roles in a program:
.data Section: Stores initialized data, i.e., variables that have predefined values.
Example: A string with a predefined value, like msg: .asciz "Hello, World!".
Size: The size of the data contributes to the size of the executable binary.
.bss Section: Stores uninitialized data, i.e., variables that are declared but not initialized with values.
Example: A variable declared as counter: .skip 4.
Size: The size of the data does not contribute to the size of the binary file since it is only reserved in memory during runtime.
In essence, while both sections store variables, the .bss section is used for memory allocation without the need to include large amounts of zeroed or uninitialized data in the binary, whereas the .data section includes actual data values.
.bss SectionConsider the following simple example of using the .bss section to store and manipulate uninitialized data:
.section .bssmy_var: .skip 8 # Reserve 8 bytes for 'my_var'
.section .text.global _start_start: # Store a value in 'my_var' movl $42, %eax # Load 42 into eax movl %eax, my_var # Store the value of eax into 'my_var'
# Perform other operations with 'my_var' # Example: Retrieve the value of 'my_var' movl my_var, %eax # Load the value from 'my_var' into eax
# Further operations can be performed on the value of 'my_var'
# Exit the program movl $1, %eax # Syscall number for sys_exit xorl %ebx, %ebx # Set the exit status to 0 int $0x80 # Call the kernel to exit the programThe .bss section is essential for managing uninitialized global and static data in a program. It allows efficient memory allocation, reducing binary size and ensuring that variables are initialized to zero or another default value when the program starts. By understanding how the .bss section works and how to use directives such as .skip, .space, and .comm, developers can create highly optimized and efficient programs. Moreover, the .bss section plays a significant role in the overall memory layout of a program, sitting between the data segment and heap, and helping manage uninitialized variables that are crucial for a program’s execution.