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

ELF文件存在2MiB未使用空间,求原因解析

ELF文件中2MiB未使用空间的原因分析

我在加载ELF文件到内存时,发现文件内存在大量未使用空间。使用的ELF文件大小约2.1MiB,链接脚本如下:

ENTRY(start)
OUTPUT_FORMAT(elf64-x86-64)

SECTIONS {
    . = 0xC00000;
    phys = .;

    .text ALIGN(0x1000): {
        code = .;
        *(.text)
        . = ALIGN(0x1000);
    }

    .rodata ALIGN(0x1000): {
        *(.rodata*)
        . = ALIGN(0x1000);
    }

    .data ALIGN(0x1000): {
        data = .;
        *(.data)
        . = ALIGN(0x1000);
    }

    .bss ALIGN(0x1000): {
        bss = .;
        *(.bss)
        . = ALIGN(0x1000);
    }

    end = .; _end = .; __end = .;

    /DISCARD/ : {
        *(.comment)
        *(.note.gnu.build-id)
    }
}

查看程序头(地址0x40处)的p_offset字段值为0x200000,所有段表的偏移均大于0x200000,x86_64-elf-objdump的输出也验证了这一点:

cdcontents/!kernel.bin:     file format elf64-x86-64
cdcontents/!kernel.bin
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x000000000c000000

Program Header:
    LOAD off    0x0000000000200000 vaddr 0x000000000c000000 paddr 0x000000000c000000 align 2**12
         filesz 0x0000000000009384 memsz 0x000000000000b000 flags rwx

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         00006000  000000000c000000  000000000c000000  00200000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .text.startup 00000094  000000000c006000  000000000c006000  00206000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .data         00001000  000000000c007000  000000000c007000  00207000  2**5
                  CONTENTS, ALLOC, LOAD, DATA
  3 .rodata       00001000  000000000c008000  000000000c008000  00208000  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .eh_frame     00000384  000000000c009000  000000000c009000  00209000  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .bss          00001000  000000000c00a000  000000000c00a000  00209384  2**5
                  ALLOC
  6 .debug_info   000035be  0000000000000000  0000000000000000  00209384  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  7 .debug_abbrev 00000db5  0000000000000000  0000000000000000  0020c942  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  8 .debug_loclists 00006865  0000000000000000  0000000000000000  0020d6f7  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
  9 .debug_aranges 000001b0  0000000000000000  0000000000000000  00213f5c  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 10 .debug_rnglists 0000059a  0000000000000000  0000000000000000  0021410c  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 11 .debug_line   00002046  0000000000000000  0000000000000000  002146a6  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 12 .debug_str    000005f3  0000000000000000  0000000000000000  002166ec  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS
 13 .debug_line_str 0000015c  0000000000000000  0000000000000000  00216cdf  2**0
                  CONTENTS, READONLY, DEBUGGING, OCTETS

这并非链接脚本中对齐设置导致的,因为脚本里指定的对齐值是0x1000,而非0x200000。我想知道:从0x78(ELF头部结束位置)到0x200000的这段2MiB空间有何用途?

简化版Makefile如下:

C_SOURCES = $(wildcard lib/*.c) $(wildcard libc/*.c)
HEADERS = $(wildcard include/*.h) $(wildcard include/kernel/*.h)
OBJ = ${C_SOURCES:.c=.o} lib/idtr.o asmlib/memmove.o asmlib/memcpy.o asmlib/unalignedisfaster.o asmlib/instrset.o \
       asmlib/cputype.o asmlib/cachesize64.o

CFLAGS = -O2 -std=gnu11 -g -static -Wall -Wextra -Werror -Wno-unused-function \
         -Wno-unused-parameter -nostartfiles -Wno-unused-but-set-variable  \
         -Wstrict-prototypes -Wpointer-arith -Wcast-align -Wwrite-strings -Wshadow \
         -fno-stack-protector -Wundef -nostdlib -fno-builtin -nodefaultlibs \
         -fms-extensions -ffreestanding -mcmodel=large -fverbose-asm -nostartfiles \
         -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -Iinclude -Wfloat-equal

all: kernel.bin

kernel.bin: lib/kernel_start.o ${OBJ}
    x86_64-elf-gcc -o $@ $^ -T link.ld -ffreestanding -O2 -nostdlib -lgcc

%.o: %.c
    x86_64-elf-gcc ${CFLAGS} -c $< -o $@

%.o: %.asm
    nasm $< -f elf64 -o $@

问题原因

这段2MiB的空白空间是由-mcmodel=large编译选项导致的。在x86_64的大内存模型(large model)下,链接器会将可加载段的文件偏移对齐到2MiB(0x200000),这是因为大模型下代码和数据的寻址范围更大,链接器需要满足特定的内存布局要求来确保地址计算的正确性。

验证与解决方法

  • 可以通过将编译选项中的-mcmodel=large替换为-mcmodel=kernel来解决这个问题。-mcmodel=kernel是专门为x86_64内核设计的内存模型,它默认使用1GiB的地址空间,不需要将段偏移对齐到2MiB,同时保留内核所需的寻址特性。
  • 另外,如果你确实需要使用大内存模型,也可以通过在链接脚本中显式指定PHDRS并设置段的偏移来强制覆盖默认对齐行为,但对于内核开发来说,-mcmodel=kernel是更合适的选择。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 18:50:42