浮点库应用,你也有困惑吗?

描述

今天小编想要给大家带来的是最近在调试一个项目时候发现的怪事,同样的函数库在使用不同的IDE时,得到的运行结果竟然是不一致的。相信眼尖的读者朋友已经从标题中猜出一二了,正是因为库中依赖了浮点计算库所导致的问题。那么就请和小编一起,探究下详细的来龙去脉吧!

项目背景

首先再详细描述以下项目背景:我们使用了一个由GCC工具链构建的函数库,编译器选项为-mfloat-abi=hard,即在编译时,使能了硬件浮点单元指令加速。但在我们将该库与Keil项目链接后,发现结果不正确。当然,我们最先怀疑的当然是库编译的有问题啦。但是奇怪的事情发生了,我当我们使用GCC工具链链接编译相同的工程,并运行后,得到了正确的结果。那么可以基本确定,库应该是没有问题的。那么问题出在哪呢?

 

 

问题分析

由于小编所拿到的库并不包含调试信息,只能通过一些技术手段进行破解。通过反汇编库代码,我们发现库依赖了一些浮点计算库的C函数,如sqrtf、expf等,为了简便,让我们称之为xxf函数,由于GCC并没有提供其具体实现,因此需要由库的使用者链接这些函数,而经过进一步的debug,我们发现这些函数导致了错误的结果,换句话说,这些函数的返回值是错的。

 

 

问题调试

那就有意思了,为了简单起见,让我们先编写一段简单的测试代码来复现这个问题,代码很简单,我们直接定义一个开平方根的函数:

 

#include "math.h"

 

 

 

 

 

float calc_sqrt(float a){

 

 

       return  sqrtf(a);

 

 

}

 

 

使用gcc工具链对其进行编译:

 

arm-none-eabi-gcc.exe -mcpu=cortex-m7  -mthumb  -mfpu=fpv5-sp-d16  -mfloat-abi=hard test.c -fshort-wchar -c -o test.o

 

 

随后,随便找到一个Keil的测试工程,我们这里选择一个Hello_World示例工程,将编译出来的.o文件添加到工程中:

 

 

 

恩智浦

 

并在主程序中添加调用代码:

 

 

float calc_sqrt(float a)

 

 

volatile float a = calc_sqrt(4.0f);

 

 

编译链接下载程序,并让程序停在函数调用处:

 

 

 

恩智浦

 

单步进入calc_sqrt函数内部,到这里,我们可以发现对这些函数的调用顺序是正确的。通过将参数传递给S0(对于float)如下所示,S0中寸的就是待计算的数据4.0f:

 

 

 

恩智浦

 

 

恩智浦

 

看起来好像没有问题,再进一步现在让我们检查由Keil链接的sqrtf函数的汇编实现:

 

 

 

恩智浦

 

相信大家发现了奇怪的事情了,链接的sqrtf将S0中的值传递给S0,而此时R0的值其实为0,但正如之前所说,浮点值已经由库的代码传递给了S0。因此,由于S0中实际要计算的值被临时替换了,就导致了一个错误的结果。

 

 

 

恩智浦

 

这里要强调一下,如果在Keil中直接调用sqrtf时候,或是使用keil编译器所编译出来的.o文件,Keil运行时库会使用“__hardfp_sqrtf”作为sqrtf的混淆名称:

 

 

 

恩智浦

 

而因为我们所使用库来自GCC工具链,因此Keil并不会对其进行替换,而是会将C库中叫做sqrtf的函数直接链接进去,而这个函数的默认实现,是使用R0作为参数传递的寄存器。这也就导致,实际要被计算的数丢失,最终导致结果计算错误。

 

 

那么怎么解决这个问题,让keil不去链接这个奇怪的sqrtf呢,这就要用到Keil的一个小技巧了:

 

 

float $Sub$$sqrtf(float a){

 

 

     return __builtin_sqrtf(a);

 

 

}

 

 

这样一来,调用sqrtf函数的地方,就会编程对$Sub$$sqrtf的调用:

 

 

 

恩智浦

 

 

恩智浦

 

而结果也变为正确的结果2.0了:

 

 

 

恩智浦

 

当然,大家可能会想啊,那我开了gcc优化之后,是不是就可以自动展开sqrtf了呢?让我们来看看:

 

 

arm-none-eabi-gcc.exe -mcpu=cortex-m7  -mthumb  -mfpu=fpv5-sp-d16  -mfloat-abi=hard test.c -fshort-wchar -c -o3 -o test.o

 

 

代码并没有变化:

 

 

 

恩智浦

 

 

 

 

结论

小编想用这个例子和大家说明下,在涉及到跨工具链开发时,一定要注意浮点库的使用或依赖问题,由于不同编译器对于浮点运算的实现可能有些许不同,会导致意想不到的奇怪问题出现。最好的方案,还是根据不同的工具链都构建一个专属的库来使用。

 

 

   

END

   

更多恩智浦AI-IoT市场和产品信息,邀您同时关注“NXP客栈”微信公众号

恩智浦      

NXP客栈


恩智浦致力于打造安全的连接和基础设施解决方案,为智慧生活保驾护航。

       

长按二维码,关注我们

恩智浦MCU加油站


这是由恩智浦官方运营的公众号,着重为您推荐恩智浦MCU的产品信息、开发技巧、教程文档、培训课程等内容。

恩智浦  

长按二维码,关注我们

 


原文标题:浮点库应用,你也有困惑吗?

文章出处:【微信公众号:恩智浦MCU加油站】欢迎添加关注!文章转载请注明出处。


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分