我有这个非常简单的代码:
#include <stdio.h>
#include <math.h>
int main()
{
long v = 35;
double app = (double)v;
app /= 100;
app = log10(app);
printf("Calculated log10 %lf\n", app);
return 0;
}
此代码完全适用于x86,但不适用于arm,结果为0.00000。有些想法?
其他信息:
操作系统:linux 3.2.27
我使用ct-ng构建arm工具链:arm-unknown-linux-gnueabi -
libc版本2.13
gcc -v
的输出:
使用内置规格。 COLLECT_GCC =臂未知-Linux的gnueabi-GCC COLLECT_LTO_WRAPPER = /选择/ X-工具/臂未知-Linux的gnueabi /的libexec / GCC /臂未知-Linux的gnueabi / 4.5.1 / LTO-包装 目标:arm-unknown-linux-gnueabi 配置为:/home/mirko/misc/rasppi-ct-ng-files/.build/src/gcc-4.5.1/configure --build = x86_64-build_unknown-linux-gnu --host = x86_64-build_unknown-linux -gnu --target = arm-unknown-linux-gnueabi --prefix = / opt / x-tools / arm-unknown-linux-gnueabi --with-sysroot = / opt / x-tools / arm-unknown-linux- gnueabi / arm-unknown-linux-gnueabi // sys-root --enable-languages = c --disable-multilib --with-pkgversion = crosstool-NG-1.9.3 --enable -__ cxa_atexit --disable-libmudflap - -disable-libgomp --disable-libssp --with-host-libstdcxx =' - static-libgcc -Wl,-Bstatic,-lstdc ++, - Bdynamic -lm' - with-gmp = / home / mirko / misc / rasppi -ct-ng-files / .build / arm-unknown-linux-gnueabi / build / static --with-mpfr = / home / mirko / misc / rasppi-ct-ng-files / .build / arm-unknown-linux -gnueabi / build / static --with-mpc = / home / mirko / misc / rasppi-ct-ng-files / .build / arm-unknown-linux-gnueabi / build / static --with-ppl = / home / mirko / misc / rasppi-ct-ng-files / .build / arm-unknown-linux-gnueabi / build / static --with-cloog = / home / mirko / misc / rasppi-ct-ng-files / .build /臂UNK nown-linux-gnueabi / build / static --with-libelf = / home / mirko / misc / rasppi-ct-ng-files / .build / arm-unknown-linux-gnueabi / build / static --enable-threads = posix --enable-target-optspace --with-local-prefix = / opt / x-tools / arm-unknown-linux-gnueabi / arm-unknown-linux-gnueabi // sys-root --disable-nls - enable-symvers = gnu --enable-c99 --enable-long-long 线程模型:posix gcc版本4.5.1(crosstool-NG-1.9.3)
答案 0 :(得分:10)
ARM Linux发行版上的浮点支持并非易事。因此,您应该使用与您的操作系统和系统匹配的工具链。硬件并使用正确的编译开关。
首先你需要了解ARM的调用约定,即关于“调用函数时如何传递参数?”。 ARM是RISC架构,只能在寄存器上工作。没有指令直接操作内存。如果你需要更改内存中的值,首先需要将其加载到寄存器中,修改它,然后你需要将它存储回内存。
当你调用一个函数时,你可能需要向它传递参数,你可以将参数放在堆栈(内存)上,但由于ARM只能使用寄存器,你的函数可能会做的第一件事就是将它们加载回寄存器。为了避免这种浪费,ARM调用约定使用寄存器来传递参数。但是由于ARM的寄存器数量有限,因此调用约定也要求您只使用前四个(r0-r3)寄存器作为前四个参数,剩下的仍然必须使用堆栈来传递。
第二件事是早期的ARM内核没有任何浮点支持,操作在软件中实现。 (这仍然是通过gcc的-mfloat-abi=soft
支持的。)
我们可以通过以下代码段轻松演示这意味着什么。
float pi2(float a) {
return a * 3.14f;
}
通过-c -O3 -mfloat-abi=soft
和obdump
来编译此内容
00000000 <pi2>:
0: f24f 51c3 movw r1, #62915 ; 0xf5c3
4: b508 push {r3, lr}
6: f2c4 0148 movt r1, #16456 ; 0x4048
a: f7ff fffe bl 0 <__aeabi_fmul>
e: bd08 pop {r3, pc}
正如您所看到的(实际上它不可见:))pi2
在r0
中获取其参数,在pi constant
上填充r1
并使用__aeabi_fmul
乘以这些并返回r0
的结果。由于__aeabi_fmul
也使用相同的调用约定,因此有关r0
的详细信息不可见。我们所有的功能都填充r1
并将其委托给__aeabi_fmul
。
当浮动硬件支持添加到ARM时(再次因为体系结构样式),它带有自己的一组寄存器(s0,s1,...)。
如果我们使用-c -O3 -mfloat-abi=softfp
编译相同的代码段并转储我们
00000000 <pi2>:
0: eddf 7a04 vldr s15, [pc, #16] ; 14 <pi2+0x14>
4: ee07 0a10 vmov s14, r0
8: ee27 7a27 vmul.f32 s14, s14, s15
c: ee17 0a10 vmov r0, s14
10: 4770 bx lr
12: bf00 nop
14: 4048f5c3 .word 0x4048f5c3
正如您所看到的,编译器不会创建对__aeabi_fmul
的调用,而是在将vmul.f32
中的参数移动到r0
之后创建s14
指令。在3.14
上填充s15
。在乘法指令之后,它将s14
中可用的结果移回r0
,因为此函数的任何调用者都会因为调用约定而期望它。
现在,如果您认为pi2
是某个第三方提供给您的库,您可以理解soft和softfp实现对您做同样的事情,您可以互换使用它们。如果系统为您提供它们,您不关心您的应用程序是否在具有硬件浮点支持的系统上运行。保持旧软件在新硬件上运行非常好。
然而,在保持兼容性的同时,这种方法引入了在ARM寄存器和FP寄存器之间移动值的开销。这显然会影响性能并通过hard
称为gcc
的新调用约定来解决。这个新约定规定,如果函数中有浮点参数,则可以使用与正常值交错的浮点寄存器,也可以在浮点寄存器s0
中返回浮点值。
再次,如果我们使用-c -O3 -mfloat-abi=hard
编译我们的代码段并转储我们
00000000 <pi2>:
0: eddf 7a02 vldr s15, [pc, #8] ; c <pi2+0xc>
4: ee20 0a27 vmul.f32 s0, s0, s15
8: 4770 bx lr
a: bf00 nop
c: 4048f5c3 .word 0x4048f5c3
你可以看到没有寄存器被移动。 pi2
传递s0
的参数,编译器创建的代码填充3.14
中的s15
并使用vmul.f32 s0, s0, s15
获取我们想要的结果s0
这个新约定的大问题是当您改进编译器生成的代码时,您会彻底破坏兼容性。您不能指望使用hard
约定构建的应用程序可以使用为soft/softfp
构建的库,而为softfp构建的应用程序将不适用于为硬构建的库。
有关调用约定的更多信息,请检查ARM's website。