【问题标题】:Can 32-bit LINUX 2.6 executables run reliably on LINUX 3.2 machines?32 位 LINUX 2.6 可执行文件能否在 LINUX 3.2 机器上可靠运行?
【发布时间】:2014-04-18 19:46:18
【问题描述】:

假设 32 位支持已加载到给定的 64 位 LINUX 安装:

  • 32 位 LINUX 2.6 可执行文件能否在 LINUX 3.2 机器上可靠运行? (是的,重述标题)显然不是!

  • 对 32 位程序有哪些限制(在什么样的程序方面,而不是在 4GB 限制等方面)?

  • 是否有特定的标记文件、可执行文件、系统调用可以提前检查以确定这一点,以便脚本可以通知用户系统配置不正确?然后我可以编写一个脚本,比如“canirunhere”,它可以让用户明白这一点,而不是仅仅得到一些奇怪的浮点异常崩溃。

    • 尝试运行程序(在脚本内)并查看它是否崩溃不是一个选项,因为该程序可能只是在执行除以零!

背景故事:

我有一个用于 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 系统,一个 x86_64 运行 Ubuntu 的虚拟机
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) 我无法在非功能机器上执行相同的任务,尽管缺少“找不到文件”错误意味着 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 的输出(不是完全相同的程序,所以地址会略有不同),这证实了它是在动态加载中,希望有助于缩小原因。

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) ---

【问题讨论】:

  • 尝试strace你的执行。
  • 感谢您的建议,这是结果太大,无法放在这里,将其添加到上面的信息中。
  • Mark Gerolimatos,你能在你的 32 位二进制文​​件上运行 ldd 吗?什么是较旧的 32 位 linux(哪个版本的 ubuntu)?如果较新的 64 位 Linux 没有相同版本的 32 位 glibc,您应该使用静态链接软件...

标签: linux x86 x86-64 glibc strace


【解决方案1】:

假设 32 位支持已加载到给定的 64 位 LINUX 安装中

基本上是的,内核应该支持较旧的二进制文件,但在你的情况下,程序是动态链接的,所以它需要特定版本的 glibc 和所有其他动态库。

您可以尝试将完整的旧 32 位分发包解压缩到某个子文件夹,然后在其中执行 chroot,然后在 chroot 中运行您的程序。

另外,检查您的二进制文件的ldd 输出(如果二进制文件是使用非常旧的 glibc 构建的,它可能无法正常工作,因为有 ld.so aka 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-only。你的 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 之间的相同不兼容。

【讨论】:

  • readelf 将向您展示动态链接程序的内部结构,而无需来自同一个 glibc 的 ld.so
  • 感谢您提供的重要信息!还是要过关。具有讽刺意味的是,readelf 是我运行以生成堆栈跟踪的程序(显然是交叉编译版本:))
  • 在您的问题中,stacktrace 来自 gdb。 objdump 是 binutils 的另一个程序,用于检查 ELF 的内部结构。
  • 不,我的意思是我通过在 GDB 中运行 32 位版本的 READELF 来生成堆栈跟踪 :-)
  • 这个答案是正确猜测 FPE 的原因,但不是如何处理它。为此,您也不妨阅读我的回答。
【解决方案2】:

正如other answer 中正确指出的那样,您的问题与内核版本无关。

相反,您的目标(非功能性)机器上的 glibc 太旧了。

通常,在较新的 glibc 系统上构建并在较旧的系统上运行会导致动态链接器错误 GLIBC_2.x version not found (required by ...),但在这种情况下,您甚至在到达该点之前就崩溃了。

现在,如果您可以使用 -Wl,--hash-style=sysv 重新构建您的应用程序,您将解决 SIGFPE 问题,并最终得到一个正常工作的应用程序(有点不太可能),或者出现 GLIBC_2.x not found 错误(很可能)。

This answer 展示了您可以解决此问题的一些方法。

注意:大多数 UNIX 系统支持向后兼容性(旧的二进制文件继续在新系统上运行),但不支持向前兼容性(在新机器上构建的二进制文件在旧机器上运行)。

【讨论】:

  • 非常感谢您提供的信息。 LDD 输出确实表明程序的 libc 高于故障机器上运行的 libc。
猜你喜欢
  • 2015-08-21
  • 1970-01-01
  • 2015-06-20
  • 2023-03-19
  • 1970-01-01
  • 2014-02-09
  • 1970-01-01
  • 2013-11-25
  • 1970-01-01
相关资源
最近更新 更多