Article by Ayman Alheraki on January 11 2026 10:37 AM
.text, .data, .bssIn the ELF object file format, section headers define the organization of the binary’s data into logically distinct regions. Each section header provides metadata about a region of the file or memory, including its size, location, alignment, and purpose. For assemblers targeting the x86-64 architecture, three standard sections are typically used: .text, .data, and .bss. These correspond respectively to executable code, initialized data, and uninitialized data.
This section discusses their purpose, header structure, and how an assembler generates these headers correctly.
.text SectionContains the machine instructions (i.e., assembled code).
Marked as executable and typically read-only.
The linker will place this section in an executable memory segment during program loading.
.data SectionContains initialized global and static variables.
It is writable and used for storing variables with known initial values at compile-time.
.bss SectionRepresents uninitialized data.
It does not occupy space in the file but will be allocated and zero-initialized in memory at runtime.
Typically used for variables that are declared globally or statically without initialization.
Each ELF file has a section header table that begins at the file offset specified by e_shoff in the ELF header. Every entry in the table is 64 bytes in 64-bit ELF and corresponds to a specific section, including metadata such as name, type, flags, and location.
The relevant C structure is:
xxxxxxxxxxtypedef struct { uint32_t sh_name; uint32_t sh_type; uint64_t sh_flags; uint64_t sh_addr; uint64_t sh_offset; uint64_t sh_size; uint32_t sh_link; uint32_t sh_info; uint64_t sh_addralign; uint64_t sh_entsize;} Elf64_Shdr;Each field must be filled appropriately by the assembler.
.text Section HeaderThis section is responsible for holding executable machine instructions.
Key Fields:
sh_name: Offset into the section header string table pointing to the name ".text".
sh_type: SHT_PROGBITS (value = 1), as it contains actual program data.
sh_flags: SHF_ALLOC | SHF_EXECINSTR (values = 0x6), making the section allocatable and executable.
sh_addr: Set to 0 in relocatable object files.
sh_offset: File offset where the .text section begins.
sh_size: Total size of code in bytes.
sh_addralign: Typically 16 for x86-64 instructions to satisfy CPU alignment requirements.
sh_entsize: 0 unless the section holds fixed-size entries (not the case here).
.data Section HeaderHolds initialized writable data.
Key Fields:
sh_name: Offset to ".data" in the string table.
sh_type: SHT_PROGBITS
sh_flags: SHF_ALLOC | SHF_WRITE (values = 0x3)
sh_addr: 0 (relocatable object)
sh_offset: Offset in the file where .data starts.
sh_size: Number of bytes of initialized data.
sh_addralign: Often 8 for general data alignment.
sh_entsize: 0
.bss Section HeaderHolds uninitialized data that will be zero-filled by the loader.
Key Fields:
sh_name: Offset to ".bss" in the string table.
sh_type: SHT_NOBITS (value = 8)
sh_flags: SHF_ALLOC | SHF_WRITE
sh_addr: 0
sh_offset: File offset where the section would begin (not used since no file space is allocated).
sh_size: Size of zero-initialized space.
sh_addralign: Typically 8
sh_entsize: 0
Although .bss does not occupy file space, it must still be described in the section header table to ensure the linker and loader allocate the correct space in memory.
During assembler output generation, the following actions are required:
Emit actual section contents:
Write the .text and .data contents to the file buffer first.
Keep track of each section's starting file offset and size.
For .bss, track size only, as no bytes are written.
Construct section name string table:
Contains null-terminated strings like .text, .data, .bss, etc.
The assembler must record the offset of each name for use in sh_name.
Construct section headers:
Create a section header entry for each section.
Include an additional header for the section string table itself.
Populate each field precisely, using tracked offsets, sizes, and alignment values.
Update ELF Header:
After all section headers are created, update the e_shoff, e_shnum, and e_shstrndx fields of the ELF header.
The standard order in the section header table (excluding the null section) typically follows:
.text
.data
.bss
.shstrtab (section string table)
The .shstrtab section must be referenced via e_shstrndx in the ELF header to link section names.
Indexing begins from 1, as the first entry (index 0) is reserved and must be all zero bytes to represent the undefined section.
Proper alignment of sections is critical. Modern CPUs expect code and data to be aligned to specific boundaries for optimal performance and correctness. The assembler must ensure:
.text: 16-byte alignment
.data: 8 or 16 bytes depending on structure usage
.bss: 8 bytes or higher
This is enforced through padding in the file and section header sh_addralign fields.
The .text, .data, and .bss sections form the core of the ELF file’s content for code and static data. Properly generating their section headers ensures that the object file is compliant, linkable, and correctly interpretable by the linker and loader. An assembler must not only write section contents but also build complete and accurate metadata reflecting size, location, and usage semantics, all of which are encoded in the section headers.