【问题标题】:Floating point exception ( SIGFPE ) on 'int main(){ return(0); }''int main(){ return(0); 上的浮点异常 (SIGFPE); }'
【发布时间】:2012-09-16 05:28:35
【问题描述】:

我正在尝试为两种不同的 Linux 环境构建一个简单的 C 程序。在一台设备上程序运行良好,在另一台设备上程序生成浮点异常。该程序除了从 main 返回 0 之外什么都不做,这让我相信与启动代码可能存在 ABI 不兼容?

程序使用 gcc 编译,构建规范如下:

使用内置规范。目标:i386-redhat-linux 配置: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions -- enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --disable-plugin --with-java -home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux 线程模型:posix gcc version 4.1.2 20080704 (红帽 4.1.2-52)

程序源码如下:

int main()
{
        return(0);
}

在 Celeron 设备上,该程序在 GDB 下生成以下内容:

[root@n00200C30AA2F jrn]# /jrn/gdb fail GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) (gdb) run Starting program: /jrn/fail 

Program received signal SIGFPE, Arithmetic exception. 0x40001cce in ?? () (gdb) bt
#0  0x40001cce in ?? ()
#1  0x4000c6b0 in ?? ()
#2  0x40000cb5 in ?? ()

以下是我可以收集的详细信息,以帮助了解正在发生的事情:

CELERON:  ( fails on this device )
2.6.8 #21 Mon Oct 1 11:41:47 PDT 2007 i686 i686 i386 GNU/Linux
============
[root@n00200C30AA2F proc]# cat cpuinfo 
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 9
model name      : Intel(R) Celeron(R) M processor          600MHz
stepping        : 5
cpu MHz         : 599.925
cache size      : 512 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 2
wp              : yes
flags           : fpu vme de pse tsc msr mce cx8 sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 tm pbe
bogomips        : 1179.64

GNU C Library stable release version 2.3.2, by Roland McGrath et al.
Compiled by GNU CC version 3.2.2 20030222 (Red Hat Linux 3.2.2-5).
Compiled on a Linux 2.4.20 system on 2003-03-13.
Available extensions:
        GNU libio by Per Bothner
        crypt add-on version 2.1 by Michael Glad and others
        linuxthreads-0.10 by Xavier Leroy
        BIND-8.2.3-T5B
        libthread_db work sponsored by Alpha Processor Inc
        NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk

ATOM:  ( works fine on this device )
2.6.35 #25 SMP Mon Mar 12 09:02:45 PDT 2012 i686 i686 i386 GNU/Linux
==========
[root@n00E04B36ECE5 ~]# cat /proc/cpuinfo 
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 28
model name      : Genuine Intel(R) CPU N270   @ 1.60GHz
stepping        : 2
cpu MHz         : 1599.874
cache size      : 512 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 10
wp              : yes
flags           : fpu vme de tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx constant_tsc up arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 xtpr pdcm movbe lahf_lm
bogomips        : 3199.74
clflush size    : 64
cache_alignment : 64
address sizes   : 32 bits physical, 32 bits virtual
power management:


GNU C Library stable release version 2.5, by Roland McGrath et al.
Compiled by GNU CC version 4.1.2 20080704 (Red Hat 4.1.2-44).
Compiled on a Linux 2.6.9 system on 2009-09-02.
Available extensions:
        The C stubs add-on version 2.1.2.
        crypt add-on version 2.1 by Michael Glad and others
        GNU Libidn by Simon Josefsson
        GNU libio by Per Bothner
        NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk
        Native POSIX Threads Library by Ulrich Drepper et al
        BIND-8.2.3-T5B
        RT using linux kernel aio
Thread-local storage support included.

我可以做些什么来确定是什么导致了这个问题? 尝试静态链接到某个版本的 libc 怎么样?

在GDB下发生故障后我执行:

(gdb) x/1i $eip
0x40001cce:     divl   0x164(%ecx)
(gdb) info reg
eax            0x6c994f 7117135
ecx            0x40012858       1073817688
edx            0x0      0
ebx            0x40012680       1073817216
esp            0xbffff740       0xbffff740
ebp            0xbffff898       0xbffff898
esi            0x8049580        134518144
edi            0x400125cc       1073817036
eip            0x40001cce       0x40001cce
eflags         0x10246  66118
cs             0x73     115
ss             0x7b     123
ds             0x7b     123
es             0x7b     123
fs             0x0      0
gs             0x0      0
(gdb) x/1wx 0x164+$ecx
0x400129bc:     0x00000000
(gdb) 

根据我收到的帮助,由于某种原因,libc 启动代码似乎被 0 除。

现在的问题是,是什么导致了这种明显的不良行为?某些东西必须与其他东西不兼容?

汇编输出:

[jrn@localhost ~]$ more fail.s
        .file   "fail.c"
        .text
.globl main
        .type   main, @function
main:
        leal    4(%esp), %ecx
        andl    $-16, %esp
        pushl   -4(%ecx)
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ecx
        movl    $0, %eax
        popl    %ecx
        popl    %ebp
        leal    -4(%ecx), %esp
        ret
        .size   main, .-main
        .ident  "GCC: (GNU) 4.1.2 20080704 (Red Hat 4.1.2-52)"
        .section        .note.GNU-stack,"",@progbits

【问题讨论】:

  • 甚至 gcc 4.1.2 也很老了。当前的 GCC 版本是 4.7!
  • GCC 已进入 Firefox 带来的修订地狱。您很快就会看到,我们将在几天内面对 GCC 25.3!
  • 它也可能与libclibstdc++ 相关。两者都有重要的初始化代码。我会安装他们的-dbg 软件包并尝试使用gdb 来调试问题。祝你好运,你会需要它的。
  • 在GDB下拿到FPE的时候能不能x/1i $eip
  • @Chimera:不,这是一个非常糟糕的主意。最有可能的是,它很快就会再次崩溃,但即使你可以让它运行,它也可能会在完全不相关的地方开始导致随机的其他故障。

标签: c linux gcc elf sigfpe


【解决方案1】:

由于它适用于 ATOM 但不适用于较旧的 Celeron,我认为问题可能出在编译器优化生成的 Celeron 无法执行的代码上。尝试使用标志 -O0 进行编译。此外,我建议添加 -march=i686 以明确说明架构。此外,为了帮助隔离问题,我还建议禁用与 C++ 运行时和 JAVA 的链接。

您是否构建了这个测试程序并在每个设备上运行它,或者您是否为每个设备构建了不同的可执行文件?如果您正在构建一个可执行文件,您可能在两台设备上或在设备与您的构建机器上拥有不同版本的 libc、libstdc++。

【讨论】:

  • 编译标志没有区别,结果相同。是的,在一台机器上构建并在两个不同的设备上运行可执行文件。 Atom 设备环境正在运行 libc 2.5(与构建机器上的相同)。但是,可执行文件失败的设备具有 libc 2.3.2。那么也许 libc 2.3.2 和 libc 2.5 存在一些向后兼容性问题?
  • glibcxx 或 libstdc++ 怎么样?另外,您是否静态链接了这些库中的任何一个?我建议尝试针对 libc 2.3.2 的最低公分母以及该设备为 c++ 提供的任何内容进行构建。
  • 没有静态链接任何东西。 [jrn@localhost ~]$ ldd 失败 linux-gate.so.1 => (0x0098f000) libc.so.6 => /lib/libc.so.6 (0x00bb0000) /lib/ld-linux.so.2 ( 0x00b91000)
  • 针对旧版本的 libc(即 2.3.2)构建。这很可能会导致您的问题。
  • 是的,这也是我的怀疑,但是,我们正在尝试找到一种方法将我们的构建环境升级到更新的库等,但仍然能够创建与具有不同版本的多个设备兼容的可执行文件libc的。所以我们可能会陷入困境,最终的前进方向是硬着头皮升级旧设备的环境。
【解决方案2】:

这听起来像是一个很长的镜头...但是您可以尝试以下方法吗?

$ readelf -a fail

并寻找 GNU_HASH 动态标签?我的猜测是二进制文件使用了GNU_HASH,而你的ld.so 太旧了,无法理解。对 GNU hash 部分的支持在 2006 年左右被添加到 glibc 中,并且主线发行版在 2007 年或 2008 年左右开始仅支持 GNU-hash。您的 Centrino 的 glibc 来自 2003,它早于 GNU hashing。

如果ld.so 不理解 GNU 哈希,它将尝试使用旧的 ELF 哈希部分来代替,它是空的。特别是,我怀疑您的崩溃发生在this line in elf/do-lookup.h

for (symidx = map->l_buckets[hash % map->l_nbuckets];

由于链接器可能不理解 GNU 哈希,l_nbuckets 将为 0,从而导致崩溃。请注意,map 是一个包含大约 100 个结构元素的大型结构,l_nbuckets 在新的ld.so0x164 = 4*89,所以在旧的ld.so 中可能正是这个成员)中的第 90 个成员左右.

要查看这是否是最终的问题,请使用-Wl,--hash-style=sysv-Wl,--hash-style=both 构建并查看崩溃是否消失。

【讨论】:

  • 谢谢...等我早上到办公室我会试试看的。
  • 哇。哇。不错的分析。 +1,无论它是否解决了 OP 的问题
  • 是的 - 这是一个很好的尝试,它应该是正确的,(即使海报的名字似乎永远不会结束)。 +1。
  • 您,先生,具有出色的心理调试技能。 Raymond Chen 会很自豪的。
  • 你摇滚!这就是问题所在。使用 -Wl,--hash-style=both 编译会生成一个适用于旧环境和新环境的可执行文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多