【问题标题】:GCC [for ARM] force no floating pointGCC [for ARM] 强制无浮点
【发布时间】:2021-06-01 06:36:14
【问题描述】:

我想为我的嵌入式 C 代码创建一个版本,专门检查浮点运算是否不会被意外引入其中。我尝试将+nofp 添加到我的 [cortex-m3] 处理器架构中,但 ARM 的 GCC 不喜欢这样(可能是因为 cortex-m3 没有浮点单元)。我试过指定-mfpu=none,但这不是一个允许的选项。我已经尝试将-lm 离开链接器命令行,但链接器似乎太聪明了,不会被它愚弄,并且正在编译带有double 的代码并解析pow()

这篇帖子:https://gcc.gnu.org/legacy-ml/gcc-help/2011-07/msg00093.html 从 2011 年开始暗示 GCC 没有这样的选择,因为没有人对它感兴趣,这让我感到惊讶,因为至少从嵌入式的角度来看,这似乎是一种常见的想要避免的事情意外的 C 库膨胀。

有谁知道用 GCC/newlib 做到这一点的方法,而我不必经历并从它选择的 C 库文件中手动破解内容?

【问题讨论】:

  • C 库膨胀并不是没有 FPU 的目标中软件浮点的最重要问题。性能和非确定性时序通常更为重要。但是,一般来说,您应该只提出问题而不提出您的理由。
  • 在我的特殊情况下这是一个膨胀:我没有实时做任何事情,但在只有 128 KB 的代码空间中,我的核心代码约为 90 KB,其中大约一半是 C 库浮点版本,然后添加我的单元测试违反了 128 KB 的边界。我很希望他们回来:-)。
  • 是浮点数学运算导致浮点格式化 I/O 支持膨胀吗?如果您不执行任何 fp 数学运算,则不应链接任何 fp 数学库代码。 Newlib 支持不带浮点的类似 stdio 的函数,例如 iprintf(),或者您可以在定义它的每个标头中使用 #undef FLOATING_POINT 重建库。但是,您无法从 scanf() 删除 fp 支持。
  • 是的,我想是的:我正在使用iprintf()sniprintf()siscanf()viprintf(),已经检查了double%f(以防万一)和math.h 的出现,并删除了 pow() 的少数实例,但我无法降低闪存大小。如果我只能以某种方式在它上面打一个nofp,它会告诉我哪里出错了,我可以保持这种状态。想使用 ARM GCC 附带的 newlib 的内置版本来做到这一点,但也许这是不可能的。
  • 我的回答中建议的技术将花费您更少的时间来编写您的问题。此外,地图文件会告诉你什么占用了空间,如果你怀疑它不支持浮点,我会说它。您还可以使用它来检查打印机等,并且比搜索代码库要简单得多。

标签: gcc floating-point arm embedded fpu


【解决方案1】:

这不仅仅是图书馆的问题。您的目标将使用 soft-fp,编译器将提供浮点代码来实现算术运算符,而与库无关。

我通常采用的解决方案是扫描映射文件以查找编译器提供的浮点例程的实例。如果您的代码是“fp clean”,则不会有此类引用。数学库和任何其他执行浮点算术运算的代码都将使用这些运算符实现,因此您只需查找这些运算符调用,可以忽略 Newlib 数学库函数。

内部soft-fp 例程在https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html 中列出。手动检查映射文件中的 fp 符号可能是可行的,但您可以自己编写脚本或工具来扫描映射文件以查找这些名称以检查您的。映射文件的交叉引用部分将列出使用这些符号的所有模块,以便您可以使用它来识别使用浮点代码的位置。

Newlib stdio 函数默认支持浮点。如果您的格式化 I/O 仅限于printf(),您可以改用iprintf(),或者您可以使用FLOATING_POINT undefined 重新构建Newlib,以删除除scanf() 之外的所有浮点支持(不知道为什么)。然后,您可以再次使用映射文件技术来查找“禁止”格式的 I/O 函数(尽管在任何情况下这些函数也可能使用浮点运算符函数,因此您已经间接发现了它们)。

另一种方法是使用替代 stdio 库来覆盖 Newlib 版本。您可以使用任意数量的“tiny printf”实现。如果您将此类库链接为目标代码或在链接命令中将其库列在 Newlib 之前,它将覆盖 Newlib 版本。

【讨论】:

  • 谢谢:我刚刚查看了所有 __ 函数的映射文件,我可以看到它决定包含 C 库版本 /lib/thumb/v7-m/nofp\libg_nano.a 但从那开始,尽管事实上,我没有打电话给vfprintf(),它仍然在带来vfprintf()(以及printf())。现在我使用-ffunction-sections -fdata-sections -fno-strict-aliasing 允许链接器删除未使用的函数,但我感觉它不会对通过库进入的函数执行此操作。这让我不得不手动修改newlib
  • @Rob printf 是使用 vfprintf 实现的。交叉引用部分将告诉您调用 printf 的内容。一般来说,如果库处于对象模块级别,则为粒度。因此,如果您引用在与 printf 相同的模块中定义的一些公共符号,则 printf 必然会被链接。然而,出于这个原因,我认为这个库尽可能细化,每个模块都有一个公共函数。
  • 如果您发布您的地图文件,您可能会得到更好的答案。地图文件还显示对象的大小。通过消除 printf,您实际上将节省多少?暂时不要破解库,因为您的分析可能不正确。
  • .map 文件的交叉引用表中快速搜索gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html 中列出的函数没有显示任何内容,但它向我显示mbedtls (我需要某些加密功能)来自引用printf(),可能是因为我没有正确配置它。通过交叉引用搜索绝对是找出什么是什么的正确方法。将附加.map 文件...
  • 地图文件可以从我的One Drive这里获得:1drv.ms/u/s!AqUHa_qo4gdB-Eh8XGAJ_BgiQMHv?e=4IpoZT.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 2011-06-12
  • 1970-01-01
  • 2019-09-21
  • 2015-01-16
  • 1970-01-01
  • 2013-08-12
相关资源
最近更新 更多