Can 32-bit LINUX 2.6 executable run reliably on LINUX 3.2 machines? (yes, restating title) Apparently not!
What are the limitations placed on 32-bit programs (in terms of what kind of programs, not in terms of 4GB limitations, etc)?
Is there a specific marker file, executable, syscall that can be checked to determine this ahead of time, so that a script could inform the user that the system is not configured correctly? Then I could write a script, say "canirunhere" that could make it obvious to the user, as opposed to just getting some bizarre FLOATING POINT EXCEPTION crash.
I have a 32-bit binary build for 2.6 LINUX that is exhibiting the classic incompatibility stack trace (seen below). It works on SOME machines, such as x86_64 Linux 3.2 machines (in this case, 3.2.0-8) , but not others, such as AMD64 Linux 3.2 machines (in this case, 3.2.44-3).
The program dies in the dynamic loader itself. Here are the "file" and "uname -a" bits of info:
The file:
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped
The NON-functional system:
3.2.44-3.2.0.3.1-amd64-10846333 #1 SMP Wed May 29 13:08:01 UTC 2013 x86_64 GNU/Linux
The FUNCTIONAL system, an x86_64 VM running 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
Note that the Ubuntu system did not initially support 32-bit programs, and thus I had to follow the instructions on the (now sadly dead) link in this previous question. (click here) I cannot perform the same task on the non-functional machine, although the lack of a "file not found" error means that 32-bit support is theoretically there.
Stack trace:
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 output: At a responder's suggestion, here is the output of strace (was not the exact same program, so addresses will be slightly different), which confirms that it is in the dynamic loading, hopefully helping to narrow down the cause.
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) ---
Assuming 32-bit support has been loaded on to a given 64-bit LINUX installation
Basically yes, kernel should support older binaries, but in you case the program was linked dynamically, so it needs the specific version of glibc and all other dynamic libraries.
You can try to unpack the complete older 32bit distributive to some subfolder, then do chroot
into it and then run your program inside the chroot.
Also, check ldd
output of your binary (it may not work if binary was build with very old glibc, because there is the ld.so
aka ld-linux.so.2
program to load dynamic binaries and to implement ldd).
There was one example of SIGFPE in do_lookup_x (you can google it with: SIGFPE, Arithmetic exception. do_lookup_x):
Floating point exception ( SIGFPE ) on 'int main(){ return(0); }' @ stackoverflow.com
Support for the GNU hash section was added to glibc around 2006, and mainline distros began to be GNU-hash-only around 2007 or 2008. Your Centrino's glibc is from 2003, which predates GNU hashing.
If the ld.so doesn't understand GNU hash, it will try to use the old ELF hash section instead, which is empty. In particular, I suspect your crash is occurring at this line in elf/do-lookup.h:
for (symidx = map->l_buckets[hash % map->l_nbuckets];
Since the linker presumably doesn't understand GNU hashes, l_nbuckets would be 0, resulting in the crash.
So, your FPE may come from the same incompatibility between glibc on older 32-bit linux and 32-bit glibc in some newer distros.