在64位Linux上执行32位二进制时的SIGSEGV
您可能听说过StoneKnifeForth,kragen的一个项目:https://github.com/kragen/stoneknifeforth。这是一个Python程序,充当小Forth解释器和作为Forth编译器的Forth程序。因此,您可以使用这两者一致地构建Forth编译器二进制文件。在将StoneKnifeForth移植到C++(https://github.com/tekknolagi/stoneknifecpp)之后,我注意到在64位Linux上StoneKnifeForth生成的所有二进制文件(无论是多种)segfault。也就是说,如果你克隆stoneknifecpp并运行:在64位Linux上执行32位二进制时的SIGSEGV
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
非常感谢汤姆·赫布(tchebb)确认了我的怀疑,并搞清楚了这一点。从this commit可以看出,问题在于起始地址太低。它与32位或64位无关,而是与较早的内核和较新的内核相关。
较新的内核已增加了sysctl参数vm.mmap_min_addr
,这意味着旧的源将禁止程序启动。这解释了为什么sudo
工作。当汤姆解释说,“除非你用KVM支持调用QEMU,QEMU是一个仿真程序不是一个系统管理程序,因此它模拟了整个软件的地址空间和虚拟内存子系统大概不会强加任何负载地址限制。”
你的回答解释了为什么程序在QEMU下运行正常,但不是为什么它在'sudo'下运行。特别是,你引用的评论说“我们不能低于0x10000”,而你的程序链接在0x1000处(或其附近)。 –
@EmployedRussian你是对的。我有点担心。我不完全确定,但我仍在继续查找。例如,https://wiki.debian.org/mmap_min_addr表示root可以解决dosemu/qemu的问题。 – tekknolagi
请显示'readelf -l'的输出。问题可能在于“PT_LOAD”段,而不是ELF标题。 –
@EmployedRussian我的朋友汤姆今天早些时候帮忙找到了这个问题。我会尽快发布自己的回答。 – tekknolagi
@EmployedRussian我发布了一个解释事情的答案。 – tekknolagi