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

64位Linux下机器码打印字符串触发Segmentation fault问题排查

64位Linux手动编写ELF机器码程序段错误问题

机器码十六进制内容

00000000: 7f45 4c46 0201 0103 0000 0000 0000 0000  .ELF............
00000010: 0200 3e00 0100 0000 7800 4000 0000 0000  ..>.....x.@.....
00000020: 4000 0000 0000 0000 0000 0000 0000 0000  @...............
00000030: 0000 0000 4000 3800 0100 4000 0000 0000  ....@.8...@.....
00000040: 0100 0000 0700 0000 0000 0000 0000 0000  ................
00000050: 0000 4000 0000 0000 0000 4000 0000 0000  ..@.......@.....
00000060: 8e00 0000 0000 0000 8e00 0000 0000 0000  ................
00000070: 0010 0000 0000 0000 48b9 0000 0000 0000  ........H.......
00000080: 0001 bf00 0000 0000 4000 88bb 0000 0000  ........@.......
00000090: 0000 0005 c000 0000 0000 0000 010f 05c7  ................
000000a0: c03c 0000 0048 c7c7 0000 0000 0f05 6865  .<...H........he
000000b0: 6c6c 6f00 0a                             llo..

指令与机器码对应关系(存在错误)

  1. mov rax, 1 对应 b900 0000 0000 0000 01
  2. mov rsi, input 对应 bf00 0000 0000 4000 88
  3. mov rdx, 5 对应 bb00 0000 0000 0000 05
  4. mov rdi, 1 对应 c000 0000 0000 0000 01
  5. syscall 对应 0f05

参考汇编程序

; print.asm - written in fasm assembly language
format ELF64 executable 3       ; value 3 marks the executable for Linux system
; print
mov rax, 1      ; syscall #1 (write)
mov rsi, input  ; arg1 = msg
mov rdx, 5      ; arg2 = msg length
mov rdi, 1      ; arg3 = 1 (stdout)
syscall
; exit 
mov rax, 60     ; syscall #60 (exit)
mov rdi, 0      ; arg 1 = 0 (OK)
syscall         ; call exit
; data
input db "hello", 0

执行与调试信息

$ ./print
Segmentation fault (core dumped)

$ gdb ./print
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400087 in ?? ()
(gdb) quit

$ readelf -l print

Elf file type is EXEC (Executable file)
Entry point 0x400078
There is 1 program header, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x000000000000008e 0x000000000000008e  RWE    0x1000

$ file print
print: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, no section header

问题分析与排查步骤

核心问题1:机器码与汇编指令完全不匹配

x86-64的立即数mov指令有严格编码规则:

  • mov rax, imm64 正确编码是 48 c7 c0 xx xx xx xx(xx为小端存储的立即数),你用的48 b9 00 00 00 00 00 00 00 01实际是mov rcx, 0x100000000,根本没给rax赋值,导致syscall时rax不是write的系统调用号1。
  • mov rsi, imm64 正确编码是 48 be xx xx xx xx xx xx xx xx,你用的bf开头编码实际是mov rdi, imm64,把input地址写到rdi(本该存stdout的文件描述符1),rsi反而没拿到缓冲区地址,参数完全错位。
  • mov rdi, 1 你写的c000 0000 0000 0000 01不是有效指令,CPU执行时会触发非法操作,直接导致段错误。

核心问题2:数据段未被加载到内存

从readelf -l输出看,LOAD段的FileSiz和MemSiz都是0x8e,意味着只有文件前0x8e字节被映射到内存。但你的input字符串在文件偏移0xa0处,不在该范围内,内存中0x4000a0位置是未映射区域,即使寄存器赋值正确,访问该地址也会触发段错误。

排查步骤

  1. 验证指令编码正确性:

    • 用fasm/nasm编译参考汇编代码,再用objdump -d反编译,对比正确机器码:
      fasm print.asm print.o && objdump -d print.o
      
    • 对照x86-64指令集手册,逐一确认寄存器对应的操作码(比如rax对应c0、rsi对应be、rdi对应bf)。
  2. 修正ELF程序头:

    • 调整LOAD段的p_filesz和p_memsz字段,从0x8e改为至少0xb6(覆盖到字符串末尾),让数据段也被映射到内存。
  3. 用gdb逐指令分析:

    • 在gdb中执行x/20i 0x400078,查看入口点开始的实际执行指令,对比预期指令,快速定位编码错误:
      gdb ./print
      (gdb) x/20i 0x400078
      

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:14:55