32位LINUX 2.6可执行文件能否在LINUX 3.2机器上可靠运行? (是的,重申标题)显然不是!
对32位程序有什么限制(根据什么类型的程序,而不是4GB限制等)?
是否有特定的标记文件,可执行文件,系统调用可以检查以提前确定,以便脚本可以通知用户系统配置不正确?然后我可以写一个剧本,说" canirunhere"这可能会让用户明白,而不仅仅是让一些离奇的FLOATING POINT EXCEPTION崩溃。
我有一个针对2.6 LINUX的32位二进制构建,它展示了经典的不兼容堆栈跟踪(见下文)。它适用于某些机器,例如x86_64 Linux 3.2机器(在本例中为3.2.0-8),但不适用于其他机器,例如AMD64 Linux 3.2机器(在本例中为3.2.44-3)。
程序在动态加载程序中死掉。这是"文件"和" uname -a"信息:
文件:
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped
非功能系统:
3.2.44-3.2.0.3.1-amd64-10846333 #1 SMP Wed May 29 13:08:01 UTC 2013 x86_64 GNU/Linux
FUNCTIONAL系统,运行Ubuntu的 x86_64 VM :
3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 17:37:58 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
请注意,Ubuntu系统最初并不支持32位程序,因此I had to follow the instructions on the (now sadly dead) link in this previous question. (click here)我无法在非功能机器上执行相同的任务,尽管找不到"文件&# 34;错误意味着理论上存在32位支持。
堆栈追踪:
Program received signal SIGFPE, Arithmetic exception.
0xf7feb876 in do_lookup_x () from /lib/ld-linux.so.2
(gdb) where
#0 0xf7feb876 in do_lookup_x () from /lib/ld-linux.so.2
#1 0xf7febc07 in _dl_lookup_symbol_x () from /lib/ld-linux.so.2
#2 0xf7fed251 in _dl_relocate_object () from /lib/ld-linux.so.2
#3 0xf7fe7108 in dl_main () from /lib/ld-linux.so.2
#4 0xf7ff58f1 in _dl_sysdep_start () from /lib/ld-linux.so.2
#5 0xf7fe3c33 in _dl_start () from /lib/ld-linux.so.2
#6 0xf7fe3817 in _start () from /lib/ld-linux.so.2
Strace输出: 在响应者的建议中,这里是strace的输出(不是完全相同的程序,因此地址会略有不同),这证实它处于动态加载状态,希望有助于缩小原因。 / p>
strace ./porgram
execve("./program", ["./program"...], [/* 63 vars */]) = 0
brk(0) = 0x80ea000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf77c5000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=47552, ...}) = 0
mmap2(NULL, 47552, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf77b9000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
open("/lib/tls/i686/cmov/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\222"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1265332, ...}) = 0
mmap2(NULL, 1275268, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7681000
mmap2(0xf77b2000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x130) = 0xf77b2000
mmap2(0xf77b6000, 9604, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf77b6000
close(3) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7680000
set_thread_area({entry_number:-1 -> 12, base_addr:0xf76806b0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
--- SIGFPE (Floating point exception) @ 0 (0) ---
答案 0 :(得分:3)
假设已将32位支持加载到给定的64位LINUX安装
基本上是的,内核应该支持更旧的二进制文件,但在你的情况下程序是动态链接的,所以它需要特定版本的glibc和所有其他动态库。
您可以尝试将完整的旧32位分发包解压缩到某个子文件夹,然后执行chroot
,然后在chroot中运行您的程序。
另外,检查二进制文件的ldd
输出(如果使用非常旧的glibc构建二进制文件,它可能无效,因为有ld.so
又名ld-linux.so.2
程序来加载动态二进制文件和实施ldd)。
do_lookup_x中有一个SIGFPE示例(您可以使用以下内容进行搜索:SIGFPE, Arithmetic exception. do_lookup_x):
Floating point exception ( SIGFPE ) on 'int main(){ return(0); }' @ stackoverflow.com
2006年左右,glibc增加了对GNU哈希部分的支持 主线发行版在2007年或2008年左右开始只是GNU-hash。你的 Centrino的glibc是从2003年开始的,它早于GNU哈希。
如果ld.so不理解GNU哈希,它会尝试使用旧的 相反,ELF哈希部分是空的。特别是,我怀疑 您的崩溃发生在elf / do-lookup.h中的这一行:
for (symidx = map->l_buckets[hash % map->l_nbuckets];
由于链接器可能不理解GNU哈希值,因此l_nbuckets将为0,从而导致崩溃。
因此,您的FPE可能来自旧版32位Linux上的glibc和某些较新发行版中的32位glibc之间的相同不兼容性。
答案 1 :(得分:0)
正如other answer中正确指出的,您的问题与内核版本无关。
相反,目标(非功能)机器上的glibc太旧了。
通常,在较新的glibc系统上构建并在较旧的glibc系统上运行的结果会导致动态链接器错误GLIBC_2.x version not found (required by ...)
,但在这种情况下,甚至在您到达该点之前就会崩溃。
现在,如果您可以使用-Wl,--hash-style=sysv
重建应用程序,则可以解决SIGFPE
问题,并最终得到一个正在运行的应用程序(有些不太可能)或出现GLIBC_2.x not found
错误(非常可能)。
This answer显示了解决这个问题的一些方法。
注意:大多数UNIX系统支持向后兼容性(旧二进制文件继续在较新的系统上运行)但不支持向前兼容性(在较旧的机器上构建的二进制文件运行在较旧的机器上)。