【问题标题】:SIGSEGV when executing 32 bit binary on 64 bit Linux在 64 位 Linux 上执行 32 位二进制时的 SIGSEGV
【发布时间】:2018-01-25 12:51:35
【问题描述】:

您可能听说过 StoneKnifeForth,这是 kragen 的一个项目:https://github.com/kragen/stoneknifeforth。它是一个充当小型 Forth 解释器的 Python 程序和一个充当 Forth 编译器的 Forth 程序。因此,您可以同时使用这两者来构建 Forth 编译器二进制文件。

在将 StoneKnifeForth 移植到 C++ (https://github.com/tekknolagi/stoneknifecpp) 后,我注意到 StoneKnifeForth 生成的所有二进制文件(任何一种)在 64 位 Linux 上都会出现段错误。也就是说,如果你克隆 stoneknifecpp 并运行:

make
./l01compiler  # produced by the Forth program

您将获得以下信息:

willow% ./l01compiler                 
[1]    31614 segmentation fault  ./l01compiler

这显然不是一个非常有趣的错误消息,所以我想我会 strace 它:

willow% strace ./l01compiler
execve("./l01compiler", ["./l01compiler"], [/* 110 vars */]) = -1 EPERM (Operation not permitted)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=0} ---
+++ killed by SIGSEGV +++
[1]    31615 segmentation fault (core dumped)  strace ./l01compiler

得到了……更多的信息。看起来 ELF 标头是错误的不知何故,除了以下两个有趣的花絮:

  • 在 32 位 qemu 下运行良好
  • 如果我sudo ./l01compiler 它运行良好

我有点不知所措,即使在互联网上搜索了 32 位和 64 位 Linux 内核之间的 ELF 标头格式之间的可能差异等之后。如果有人有任何信息,我会很高兴。

我附上了下面的标题:

willow% readelf -h l01compiler   
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x1e39
  Start of program headers:          52 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         1
  Size of section headers:           40 (bytes)
  Number of section headers:         0
  Section header string table index: 0

【问题讨论】:

  • 请显示来自readelf -l 的输出。问题可能出在 PT_LOAD 段上,而不是 ELF 标头。
  • @EmployedRussian 我的朋友 Tom 今天早些时候帮助找到了这个问题。我会尽快尝试发布一个自我回答。
  • @EmployedRussian 我已经发布了一个解释问题的答案。

标签: linux linux-kernel binary segmentation-fault elf


【解决方案1】:

非常感谢 Tom Hebb (tchebb) 证实了我的怀疑并弄清楚了这一点。从this commit 可以看出,问题在于源地址太低了。它与 32 位或 64 位无关,而是较早的内核与较新的内核。

较新的内核增加了vm.mmap_min_addr sysctl 参数,这意味着旧版本将完全禁止程序启动。这就解释了为什么sudo 有效。正如 Tom 解释的那样,“除非你调用支持 KVM 的 qemu,否则 qemu 是一个仿真器而不是一个虚拟机管理程序,因此它在软件中模拟整个地址空间和虚拟内存子系统,并且大概不会施加任何加载地址限制。”

【讨论】:

  • 您的回答解释了为什么程序在 QEMU 下运行正常,但没有解释为什么它在 sudo 下运行。特别是,您引用的评论说“我们不能低于 0x10000”,而您的程序链接在 0x1000(或附近)。
  • @EmployedRussian 你是对的。我有点挥手致意。我不完全确定,但我正在继续查找。比如wiki.debian.org/mmap_min_addr,说root解决了dosemu/qemu的问题...
猜你喜欢
  • 2012-04-12
  • 2021-09-01
  • 1970-01-01
  • 2011-09-08
  • 2018-09-17
  • 1970-01-01
  • 1970-01-01
  • 2012-09-17
  • 2017-12-12
相关资源
最近更新 更多