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

今天小编想要给大家带来的是最近在调试一个项目时候发现的怪事,同样的函数库在使用不同的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加油站】欢迎添加关注!文章转载请注明出处。

数字电视SoC H.264+AVS+以太网连接
疑似索尼首款Z系列无反相机的专利曝光
使用可控硅三极管MOS管的单片机控制220V交流电通断电路图解
TDK推出支持串行ATA 6Gbps的高可靠性CFast卡CAS1B系列
采集EtherCAT从站设备数据转modbus方案
浮点库应用,你也有困惑吗?
PCIe物理层的基本概念
TDK推出通过最高安全等级认证的坚固耐用型交流滤波电容器
华为将成为全球第二大智能手机厂商 5年投资105亿华为发展鲲鹏产业
从安全性出发 雾计算标准轮廓初现
未来AI做可编程FPGA芯片可能超过人类
物联网如何改变电子供应链
与柔性PCB组装相关的五个常见问题-第二部分
指针万用表:分辨高频管和低频管
B站开始新一轮加速 准备进发海外市场
处理器可能发生死锁或者数据丢失
断路器和隔离开关之间的操作顺序是怎样的?
脉冲电源优点
台积电/GF/联电/中芯国际四大晶圆代工厂市占达85%
当WIFI6遇到5G,擦出了怎样的火花