‘ int main(){ return (0) ; }’上的浮点异常(SIGFPE)

我试图为两个不同的 Linux 环境构建一个简单的 C 程序。在一个设备上程序运行良好,在另一个设备上程序生成一个浮点异常。这个程序除了从 main 返回0之外什么也不做,这让我相信它与启动代码有一些不兼容性,也许是 ABI?

该程序使用 gcc 编译,具有以下构建规范:

使用内置 specs 目标: i386-redhat-linux 配置如下: . ./configure —— prefix =/usr —— mandir =/usr/share/man —— infodir =/usr/share/info —— enable-share —— able-thread = posx —— enable-check = release —— with-system-zlib —— able-_ cxa _ atexit —— able-libunwind- 常规—— able-libgcj-multifile —— able-language = c,c + + ,objecc,obj-c + + ,java,fortran,ada —— able-java-awt = gtk —— able-dssi —— able-plugin —— with-java-home =/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre —— with-cpu = general —— host = i386-redhat-linux Thread model: posx gcc版本4.1.220080704(红帽子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
6802 次浏览

由于它可以在 ATOM 上工作,但不能在老赛扬上工作,我认为问题可能出在赛扬无法执行的编译器最佳化生成代码上。尝试使用标志 -O0进行编译。此外,我建议添加-March = i686来显式地声明体系结构。另外,为了帮助隔离问题,我还建议禁用到 C + + 运行时和 JAVA 的链接。

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

这听起来像是一个很长的机会... ... 但是你能尝试下面的方法吗?

$ readelf -a fail

并查找 GNU _ HASH 动态标记?我的猜测是,二进制文件使用 GNU_HASH,而您的 ld.so太老了,无法理解它。2006年左右,glibc 增加了对 GNU 散列部分的支持,2007年或2008年左右,主线发行版开始只支持 GNU 散列。Centrino 的 glibc来自 二零零三年,它比 GNU 散列早。

如果 ld.so不理解 GNU 散列,它将尝试使用旧的 ELF 散列区段,该区段为空。特别是,我怀疑你的坠机发生在 elf/do-lookup.h中的这条线:

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

由于链接器可能不理解 GNU 散列,因此 l_nbuckets将为0,从而导致崩溃。请注意,map是一个大型结构,大约有100个结构元素,而 l_nbuckets大约是较新的 ld.so(0x164 = 4*89,所以在较旧的 ld.so中可能正是这个成员)中的第90个结构元素。

如果这是 决定性的的问题,建立与 -Wl,--hash-style=sysv-Wl,--hash-style=both,看看是否崩溃消失。