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

使用GNU ld及仅含.text段的链接脚本生成的最小静态ELF可执行文件为何被Linux加载器拒绝?

为什么Linux加载器拒绝运行这个精简ELF可执行文件?

我来帮你拆解这个问题——你遇到的EPERM错误,根源在于你的ELF文件把核心LOAD段映射到了虚拟地址0x0,而Linux内核出于安全防护的考虑,直接拒绝加载这样的可执行文件。

先看看你得到的错误输出:

$ strace ./experiment
execve("./experiment", ["./experiment"], 0x7ffee000bd20 /* 69 vars */) = -1 EPERM (Operation not permitted)

再看readelf输出里的程序头,重点看LOAD段的信息:

$ readelf -hl ./experiment
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x120
  Start of program headers:          64 (bytes into file)
  Start of section headers:          512 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         4
  Size of section headers:           64 (bytes)
  Number of section headers:         6
  Section header string table index: 5

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000190 0x0000000000000190  R E    0x1000
  NOTE           0x0000000000000160 0x0000000000000160 0x0000000000000160
                 0x0000000000000030 0x0000000000000030  R      0x8
  GNU_PROPERTY   0x0000000000000160 0x0000000000000160 0x0000000000000030  R      0x8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10

 Section to Segment mapping:
  Segment Sections...
   00     .text .note.gnu.property
   01     .note.gnu.property
   02     .note.gnu.property
   03

核心问题分析

你的链接脚本里写了这一行:

. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;

这强制把程序的text段(以及包含它的LOAD段)的虚拟起始地址设为0x0。但Linux内核有个安全机制:通过vm.mmap_min_addr这个sysctl参数限制用户空间程序能映射的最低虚拟地址(默认通常是0x10000,也就是65536)。这么做是为了防止NULL指针解引用意外访问到有效内存,避免潜在的安全漏洞。你的LOAD段起始地址0x0远低于这个最小值,所以内核在execve时直接拒绝加载,返回EPERM。

解决方法

修改链接脚本,把text-segment的起始地址改成x86_64 Linux默认的用户空间起始地址0x400000即可:

OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
  . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
  .text : { *(.text) }
}

重新执行编译链接步骤,生成的可执行文件就能被正常加载运行了。

补充说明

虽然ELF标准本身并没有禁止LOAD段使用0x0地址,但Linux的安全策略会阻止这种映射。另外,你程序里的其他段(NOTE、GNU_PROPERTY)本身没有问题,只是LOAD段的地址违反了内核的规则。

可复现的代码与步骤

汇编代码(experiment.S)

#include <sys/syscall.h>
.text
.global _start
.type _start, @function
_start:
        mov %rsp, %rdi
        and $(~4095), %rdi
        mov $4096, %rsi
        mov $SYS_munmap, %rax
        syscall
        test %rax, %rax
        jne .Lfail
.Lloop:
        mov $SYS_pause, %rax
        syscall
        jmp .Lloop
.Lfail:
        mov %rax, %rdi
        neg %rdi
        mov $SYS_exit, %rax
        syscall
.size _start, .-_start
.section .note.GNU-stack,"",@progbits

链接脚本(experiment.ld)

(修改前的版本,也就是导致问题的版本)

OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
  . = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
  .text : { *(.text) }
}

编译链接命令

cc -P -E experiment.S | as -o experiment.o -
ld -o experiment -static -e _start -T experiment.ld experiment.o

Base64编码的问题程序

f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAIAEAAAAAAABAAAAAAAAAAAACAAAAAAAAAAAAAEAAOAAE
AEAABgAFAAEAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAEAAAAAAACQAQAAAAAAAAAQ
AAAAAAAAABAAAAAQAAABgAQAAAAAAAGABAAAAAAAAYAEAAAAAAAAwAAAAAAAAADAAAAAAAAAACAAA
AAAAAABT5XRkBAAAAGABAAAAAAAAYAEAAAAAAABgAQAAAAAAADAAAAAAAAAAMAAAAAAAAAAIAAAA
AAAAAFHldGQGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA
AAAAASInnSIHnAPD//0jHxgAQAABIx8ALAAAADwVIhcB1C0jHwCIAAAAPBev1SInHSPffSMfAPAAA
AA8FAAAAAAAAAAQAAAAgAAAABQAAAEdOVQABAAHABAAAAAEAAAAAAAAAAgABwAQAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAASAAEAIAEAAAAAAAA5AAAAAAAAAABfc3RhcnQA
AC5zeW10YWIALnN0cnRhYgAuc2hzdHJ0YWIALnRleHQALm5vdGUuZ251LnByb3BlcnR5AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAGwAAAAEAAAAGAAAAAAAAACABAAAAAAAAIAEAAAAAAAA5AAAAAAAAAAAAAAAAAAAAAQAA
AAAAAAAAAAAAAAAACEAAAAHAAAAAgAAAAAAAABgAQAAAAAAAGABAAAAAAAAMAAAAAAAAAAAAAAA
AAAAAgAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAACQAQAAAAAAADAAAAAA
AAAABAAAAAEAAAAIAAAAAAAAABgAAAAAAAAACQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAwAEAAAAA
AAAIAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAABEAAAADAAAAAAAAAAAAAAAAAAAAAAAA
AMgBAAAAAAAANAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA=

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 06:40:15