ELF64中.data与.bss段内存顺序及汇编语法问询
Great questions—ELF section ordering and assembly-time size calculations are easy to take for granted, but it's smart to verify when your code depends on specific memory layouts. Let's break this down clearly.
The ELF64 specification does not formally mandate a fixed order for .data and .bss sections. However, every mainstream linker (like GNU ld, the default for most Linux systems) follows a standard, efficient layout where:
.data(initialized read-write data) is placed first in the process's data segment.bss(uninitialized zero-filled read-write data) follows immediately after.data
This default comes from standard linker scripts, which group these sections into a single contiguous memory region. The OS can optimize .bss by mapping zero-filled pages without loading data from disk, so placing it after .data keeps related read-write memory together.
For your specific code:
section .data malloc_pointer: dq start_of_my_malloc start_of_data: ; ... more data content ... section .bss start_of_my_malloc: resb 1 << 30 ; Pre-allocate 1GB
Under default linking, start_of_my_malloc will definitely be at a higher address than start_of_data, so [malloc_pointer] - start_of_data will be positive.
Caveat: If you use a custom linker script, you could reorder sections. If you need absolute certainty, check your linker script or explicitly enforce the order by placing .data and .bss in the same output section.
start_of_data to calculate resb size? Your original attempt resb (1 << 30) - start_of_data fails because:
resbis an assembler (e.g., NASM) pseudo-instruction that calculates sizes at assembly time, not link time.start_of_datais a label in the.datasection—at assembly time, the assembler doesn't know the final memory offset between.dataand.bss(that's determined by the linker later).
Here's how to fix this using linker-provided symbols, which resolve at link time:
Solution for NASM + GNU ld
- Declare the linker-provided symbol for the end of
.dataas external in your assembly:EXTERN __data_end__ ; GNU ld defines this as the address right after .data ends - Calculate the reserved size using this symbol (the assembler generates a relocation for the linker to resolve):
section .bss start_of_my_malloc: resb (1 << 30) - (__data_end__ - start_of_data)
This works because __data_end__ - start_of_data is the total size of your .data section, which the linker can compute once it knows the final memory layout. Note: Some toolchains use alternative symbols like _edata—adjust if needed.
Alternative: Custom Linker Script
For full control, define a symbol for the size of .data in your linker script:
SECTIONS { /* ... other section definitions ... */ .data : { start_of_data = .; *(.data) data_size = SIZEOF(.data); } .bss : { *(.bss) } }
Then reference this symbol in your assembly:
EXTERN data_size start_of_my_malloc: resb (1 << 30) - data_size
内容的提问来源于stack exchange,提问作者Harel Rozental

