2017-08-17 183 views
1

您可能聽說過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 
+0

請顯示'readelf -l'的輸出。問題可能在於「PT_LOAD」段,而不是ELF標題。 –

+0

@EmployedRussian我的朋友湯姆今天早些時候幫忙找到了這個問題。我會盡快發佈自己的回答。 – tekknolagi

+0

@EmployedRussian我發佈了一個解釋事情的答案。 – tekknolagi

回答

1

非常感謝湯姆·赫布(tchebb)確認了我的懷疑,並搞清楚了這一點。從this commit可以看出,問題在於起始地址太低。它與32位或64位無關,而是與較早的內核和較新的內核相關。

較新的內核已增加了sysctl參數vm.mmap_min_addr,這意味着舊的源將禁止程序啓動。這解釋了爲什麼sudo工作。當湯姆解釋說,「除非你用KVM支持調用QEMU,QEMU是一個仿真程序不是一個系統管理程序,因此它模擬了整個軟件的地址空間和虛擬內存子系統大概不會強加任何負載地址限制。」

+0

你的回答解釋了爲什麼程序在QEMU下運行正常,但不是爲什麼它在'sudo'下運行。特別是,你引用的評論說「我們不能低於0x10000」,而你的程序鏈接在0x1000處(或其附近)。 –

+0

@EmployedRussian你是對的。我有點擔心。我不完全確定,但我仍在繼續查找。例如,https://wiki.debian.org/mmap_min_addr表示root可以解決dosemu/qemu的問題。 – tekknolagi