在Raspberry Pi的armv6中使用log10数学函数得到错误的结果

我有这个非常简单的代码:

#include <stdio.h>
#include <math.h>
int main()
{
    long v = 35;
    double app = (double)v;
    app /= 100;
    app = log10(app);
    printf("Calculated log10 %lfn", 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 = arm-unknown-linux-gnueabi-gcc COLLECT_LTO_WRAPPER = / opt / x-tools / arm-unknown-linux-gnueabi / libexec / gcc / arm-unknown-linux-gnueabi / 4.5.1 / lto-wrapper目标: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/arm-unknown-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)


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=softobdump编译这个给我们

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}

正如你所看到的(实际上它不可见:)) pi2r0获取它的参数,在r1填充pi constant并使用__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的调用,而是在它将位于r0参数移动到s14并在s15上填充3.14后创建一个vmul.f32指令。 乘法指令后,它在移动可结果s14返回到r0 ,因为该功能的任何调用者所期望的,因为调用约定的它

现在,如果您认为pi2是由某个第三方提供给您的库,您可以理解soft和softfp实现对您都是一样的,您可以互换使用它们。 如果系统为您提供它们,您不会关心您的应用是否在具有硬件浮点支持的系统上运行。 这对保持旧软件在新硬件上运行非常有用。

然而,在保持可兼容性的同时,这种方法引入了在ARM寄存器和FP寄存器之间移动值的开销。 这显然会影响性能,并通过一个新的调用约定来解决,这个约定被gcc hard调用。 这个新的约定规定,如果你的函数中有浮点参数,你可以利用浮点寄存器与正常寄存器交错,以及你可以返回浮点寄存器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传递,编译器创建的代码在s15填充3.14 ,并使用vmul.f32 s0, s0, s15s0获得我们想要的结果。

这个新约定的一个大问题是,当你改进编译器生成的代码时,你会完全丧失compability。 您不能指望使用hard约定构建的应用程序与为soft/softfp构建的库一起工作,而为softfp构建的应用程序将无法与用于硬构建的库一起使用。

有关调用约定的更多信息,您应该查看ARM的网站。

链接地址: http://www.djcxy.com/p/86893.html

上一篇: Wrong result with log10 math function in armv6 on Raspberry Pi

下一篇: GCC: sorry, unimplemented: 64