这篇文章对最近遇到上的
ARM上浮点运算的问题做一个总结。
首先,我们先看一下ARM处理器是如何处理浮点运算的。
交叉编译器在编译的时候,对于浮点运行会预
设硬浮点运算FPA(Float Point Architecture),而没有FPA的CPU,比如SAMSUNG
S3C2410/S3C2440,会使用FPE(Float Point Emulation
即软浮点),这样在速度上就会遇到极大的限制。也就是说如果有浮点协处理器则交给它去做,如果没有则会产生一个陷阱(trap,处理器响应异常的机制),
而我们事先准备好针对浮点指令的陷阱处理程序就可以通过软件来模拟浮点运算指令。
然后,我们
解释一下OABI和EABI这两个概念。
/********************************************************************************************/
以下部分转
载至
http://linux.chinaunix.net/bbs/thread-1143604-1-1.html
。
1。什么是ABI
ABI,application binary interface
(ABI),应用程序二进制接口。
既然是 接口,那就是某两种东西之间的沟通桥梁,此处有这些种情况:
A。应用程序 <->
操作系统;
B。应用程序 <-> (应用程序所用到的)库
C 。应用程序各个组件之间
类似于API的作用
是使得程序的代码间的兼容,ABI目的是使得程序的二进制(级别)的兼容。
2。什么是OABI 和 EABI
OABI中的O,表示
“Old”,“Lagacy”,旧的,过时的,OABI就是旧的/老的ABI。
EABI中的E,表示“Embedded”,是一种新的ABI。
EABI
有时候也叫做GNU EABI。
OABI和EABI都是专门针对ARM的CPU来说的。
3。EABI的好处 / 为何要用EABI
A。支持软件浮点和硬件实现浮点功
能混用
B。系统调用的效率更高
C。后今后的工具更兼容
D。软件浮点的情况下,EABI的软件浮点的效率要比OABI高很多。
4。OABI和EABI的区别
两种ABI在如下方面有区别:
A。调用规则(包括参数如何传递及如何获得返回
值)
B。系统调用的数目以及应用程序应该如何去做系统调用
C。目标文件的二进制格式,程序库等
D。结构体中的
填充(padding/packing)和对齐。
E。
OABI:
* ABI flags passed to binutils: -mabi=apcs-gnu -mfpu=fpa
*
gcc -dumpmachine: arm-unknown-linux
* objdump -x for compiled binary:
private flags = 2: [APCS-32] [FPA float format] [has entry
point]
* "file" on compiled
Debian binary:
ELF 32-bit LSB
executable, ARM, version 1 (ARM), for GNU/Linux 2.2.0, dynamically
linked (uses shared libs), for GNU/Linux 2.2.0, stripped
* "readelf -h | grep Flags""
Flags: 0x0
EABI:
* ABI flags passed by gcc to binutils: -mabi=aapcs-linux
-mfloat-abi=soft -meabi=4
* gcc -dumpmachine:
arm-unknown-linux-gnueabi
* objdump -x for compiled binary:
private flags = 4000002: [Version4 EABI] [has entry point]
* "file" on compiled binary (under Debian):
ELF 32-bit LSB executable, ARM, version 1 (SYSV), for GNU/Linux
2.4.17, dynamically linked (uses shared libs), for GNU/Linux 2.4.17,
stripped
* "readelf -h | grep
Flags""
Flags: 0x4000002,
has entry point, Version4 EABI
/********************************************************************************************/
在虚拟机
中,运行:arm_v5t_le-gcc -dumpmachine,输出:armv5tl-montavista-linuxeabi;
运行
arm_v5t_le-readelf -h EXEC | grep Flags,(注:EXEC代表用交叉编译工具编译的可执行文件名),输出:
Flags: 0x4000002,
has entry point, Version4 EABI。
上述结果说
明当前使用的montavista的编译器是符合EABI标准的。
使用EABI(Embedded
Application Binary Interface)则可以对此改善处理,ARM
EABI有许多革新之处,其中最突出的改进就是Float Point Performance,它使用Vector Float
Point(矢量浮点),因此可以极大提高涉及到浮点运算的程序。
看到这里,之前遇到的一个问题终于弄明白
了。之前在Makefile中一直包含一个-mabi=apcs-gnu的参数,而apcs-gnu是OABI的参数,因此将OABI的参数传给符合
EABI标准的编译,编译阶段没有报错,但在板上运行时,程序中涉及到浮点数的部分出现了许多莫名的问题。比如printf("%s
%f",s,f);这句话输出的浮点数值并不是传给printf的参数,而是一个莫名其妙的数字。解决办法:在Makefile中将
“-mabi=apcs-gnu”去掉,重新编译运行,成功!
转载一篇相关文章http://blog.chinaunix.net/u1/38994/showart_2023807.html
。
使用arm-
linux-gcc 4.3.2编译必须启用内核中的Use the ARM EABI选项
不知道为什么使用
arm-linux-gcc-4.3.2.tgz
(with
EABI) 86MB
编译同样的东西就是出现如下错误,感觉可能是busybox
1.14.3的问题,因为使用
arm-linux-gcc-4.3.2
编
译出来的zImage可以使用正常挂在arm-linux-gcc-3.4.1编译器编译出来的动态busybox和库,但是使用
arm-linux-gcc-4.3.2.tgz
编译出来的静态busybox就是会出现下面的错误,开始觉得明显是应用程序出了问题
.后来发现原来是内核自己的事情,因为
arm-linux-gcc-4.3.2.tgz
使
用了EABI方式,所以这就需要内核同样配置EABI编译属性才能支持EABI编译出来的应用程序busybox[luther.gliethttp]
错误原因:没有选择Use the ARM EABI to compile the
kernel选项
Kernel Features
[ ] Use the ARM EABI to compile the
kernel
解决方法:将它寻上之后自动多出下面一行,这样再次编译的内核就ok了,嘿嘿:)
[*] Use the ARM
EABI to compile the kernel
[*] Allow
old ABI binaries to run with this kernel (EXPERIMENTAL) (NEW)
ep93xx-rtc
ep93xx-rtc: setting system clock to 1970-01-01 00:01:18 UTC (78)
Freeing init memory: 100K
Kernel panic - not syncing: Attempted
to kill init!
Backtrace:
[
]
(dump_backtrace+0x0/0x114) from []
(dump_stack+0x18/0x1c)
r7:c5818000
r6:c5817a40 r5:c5817a40 r4:c03291c4
[]
(dump_stack+0x0/0x1c) from [] (panic+0x4c/0x120)
[] (panic+0x0/0x120)
from [] (do_exit+0x70/0x58c)
r3:c0313004 r2:c5817a40 r1:c5819d0c r0:c02cbdcb
[] (do_exit+0x0/0x58c)
from [] (do_group_exit+0x94/0xc8)
[] (do_group_exit+0x0/0xc8) from
[] (get_signal_to_deliver+0x2ec/0x324)
r7:c5293a74 r6:c5818000 r5:c5819ed4
r4:00000004
[]
(get_signal_to_deliver+0x0/0x324) from []
(do_signal+0x58/0x528)
[]
(do_signal+0x0/0x528) from []
(do_notify_resume+0x30/0x34)
[]
(do_notify_resume+0x0/0x34) from []
(work_pending+0x1c/0x20)