You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ELF64文本/数据段布局与填充机制解析及编译程序段结构相关疑问

Understanding ELF LOAD Segments and Padding for x86-64 Programs

Let's break down your questions step by step using the readelf output you shared.

First, your initial guesses are spot-on:

  • The LOAD segment starting at 0x401000 (with R E flags) is indeed the text segment (holds executable machine code).
  • The LOAD segment starting at 0x403e00 (with RW flags) is the data/bss segment—notice that MemSiz (0x238) is larger than FileSiz (0x230), which accounts for the uninitialized bss section that gets allocated in memory but isn't stored in the executable file itself.

1. What are the other two read-only LOAD segments used for?

Looking at your output, there are two additional R-only LOAD segments, each serving a distinct purpose:

a. First LOAD segment (0x400000)

This segment contains critical ELF metadata and helper sections needed to load and initialize the program:

  • It includes the PHDR (program headers) and INTERP (path to the dynamic linker, /lib64/ld-linux-x86-64.so.2 in your case) sections.
  • It also covers the ELF file header itself, plus read-only note sections (like .note.gnu.build-id) that carry build or version information.
    All of this data is marked read-only because it never needs modification during program execution.

b. Third LOAD segment (0x402000)

This segment holds read-only data sections that don't require execution permissions:

  • The .rodata section (string constants like your "hello world" text, const global variables).
  • Dynamic linking-related read-only sections like .dynsym (dynamic symbol table), .dynstr (dynamic symbol strings), and .hash (symbol hash table).
    Separating these from the executable text segment is a security choice—making read-only data non-executable reduces the attack surface for code injection attacks.

2. How does ELF padding work?

ELF padding exists to satisfy alignment requirements defined by the Align field in program headers (here, 0x1000 = 4KB, the default page size for x86-64). Here's the core mechanism:

  • Each LOAD segment's virtual address (VirtAddr) must be a multiple of Align.
  • The segment's offset in the executable file (Offset) must also satisfy VirtAddr % Align == Offset % Align—this ensures the segment maps cleanly to memory pages without misalignment.
  • When a section's actual size doesn't fill an entire alignment block, padding is added (either in the file or in memory) to reach the next alignment boundary.

The 2MB padding you read about refers to huge page alignment, a performance optimization for large memory regions. By default, GCC uses 4KB pages, so you won't see 2MB-aligned padding unless you explicitly enable huge pages with flags like -mcmodel=large or linker options like -Wl,-z,huge-page-size=2MB.


3. Why doesn't the data segment start at 0x403000?

Your expectation that the data segment should start at 0x403000 (the next 4KB boundary after the third LOAD segment) makes sense in theory, but linker behavior and dynamic linking rules change the layout:

  • The third LOAD segment ends at 0x402000 + 0x138 = 0x402138. The next 4KB boundary is 0x403000, but the linker didn't place the data segment here because:
    1. File offset alignment: The data section in your executable starts at file offset 0x2e00. To meet the ELF rule VirtAddr % Align == Offset % Align, the virtual address for the data segment must be 0x403e00 (since 0x403e00 % 0x1000 = 0xe00, matching 0x2e00 % 0x1000 = 0xe00).
    2. Permission separation: Linkers intentionally place read-only and read-write segments on separate page boundaries to enforce strict memory protection. The gap between 0x402fff and 0x403dff is unused padding memory—trying to access this region would trigger a segmentation fault, adding an extra layer of security against memory corruption attacks.

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 05:39:09