gcc-arm-none-eabi 11.3“未实现并且总是会失败”

Neb*_*ise 16 c embedded gcc arm stm32

我正在开发一个裸机 STM32 项目,在 Linux x64 主机上进行编译。

将我的工具链从 升级到 后gcc-arm-none-eabi-11.2-2022.02arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi我收到以下链接器警告:

warning: _close is not implemented and will always fail
warning: _fstat is not implemented and will always fail
warning: _getpid is not implemented and will always fail
warning: _isatty is not implemented and will always fail
warning: _kill is not implemented and will always fail
warning: _lseek is not implemented and will always fail
warning: _open is not implemented and will always fail
warning: _read is not implemented and will always fail
warning: _write is not implemented and will always fail
Run Code Online (Sandbox Code Playgroud)

更全面地说,我得到了这个:

~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-closer.o): in function `_close_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/closer.c:47: warning: _close is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_a-fstatr.o): in function `_fstat_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/fstatr.c:55: warning: _fstat is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_a-signalr.o): in function `_getpid_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/signalr.c:83: warning: _getpid is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_a-isattyr.o): in function `_isatty_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/isattyr.c:52: warning: _isatty is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_a-signalr.o): in function `_kill_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/signalr.c:53: warning: _kill is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-lseekr.o): in function `_lseek_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/lseekr.c:49: warning: _lseek is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_a-openr.o): in function `_open_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/openr.c:50: warning: _open is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-readr.o): in function `_read_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/readr.c:49: warning: _read is not implemented and will always fail
~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: ~/dev_tools/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libg.a(libc_a-writer.o): in function `_write_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/writer.c:49: warning: _write is not implemented and will always fail
Run Code Online (Sandbox Code Playgroud)

除此之外,该项目似乎编译得很好。阅读发行说明(可在此处获取),我看不出是什么导致了这种情况。

  1. 是什么变化导致了这种情况呢?
  2. 我可以无视这些警告吗?它看起来像系统调用,所以我想我可以吗?
  3. 如果是的话,他们能被压制住吗?

art*_*ise 8

附带的库gcc-arm-none-eabi称为“newlib”。您可以从 git://sourceware.org/git/newlib-cygwin.git 下载副本。它有标签,您可以确定您的编译器发布的特定版本并获取带标签的版本。

例如,syscalls.c就是一种实现。Libc 存根文档包含要实现的函数。但是,您可能想知道为什么会收到这些警告。有各种“C”库函数调用,例如srand()assert()等,它们将拖入“C”文件库。如果您希望最大限度地减少开销,则需要查看映射文件并避免这些函数调用。

我不确定您的代码库和地图文件的子部分是否会有帮助。在这里你有,

  • _打开_r
  • _关闭_r
  • _读_r

它们来自可重入库的“reent”。通常,仅 RTOS 或桌面操作系统需要可重入函数。如果你有裸机单主线程,则不需要这些函数。您不能open()使用此选项调用中断处理程序:) 因此,实际上只有一个上下文(以及一个 errno)。“可重入”功能毫无用处。与 .fini 部分一样,嵌入式设备不会正常“关闭”,而是会重新启动。

这是什么变化造成的?

您已链接到在“C”库中引入文件系统原语的东西(称为函数)。

我可以忽略这些警告吗?

这取决于您的用例。您是安全关键系统吗?一般来说,我会建议修复它们,这样下一个人就不会感到困惑。如果代码遵循这些函数的路径,则很可能已经出现错误/未处理。

它看起来像系统调用,所以我想我可以吗?

不是问题吗?

如果是这样,他们可以被压制吗?

要么避免这些功能,要么提供“做正确的事情”的替代实现。“正确的事情”将取决于您的平台。

以下是出现链接器错误时的选项列表。

  1. 更改构建选项。
  2. 提供图书馆。
  3. 提供替代库。
  4. 避免函数调用/数据使用。

您可以实现自己的close_r()open_r()read_r()。例如,您可以使用带有链接 blob 的嵌入式只读文件系统(选项 3)。最有可能的是写入到 stderr,因此它可能不合适(选项 4)。选项 2 实际上是本例中的问题;但这可能没问题......只是 newlib 的作者不确定什么是正确的,因此发出警告。


小智 6

您遇到的警告被放置在 libnosys 的系统调用实现中(例如,请参阅close.c和相关warning.h。在某些时候,您链接到 libnosys - 可以通过

  • -lnosys链接标志(常见于Makefiles,由STM32CubeMX生成),
  • --specs=nosys.specs编译/链接标志

开发人员使用了一个巧妙的技巧,使用.gnu.warning 将警告消息嵌入到目标文件中。SYMBOL_NAME - 遗憾的是我找不到官方文档,但您可以在此处此处阅读有关它的更多信息。

您看到这些警告的原因是这些系统调用在“某处”被引用...它可能是代码中的杂散 printf/putchar、exit()、rand() 或libc本身中的某些用法。

关于警告的严重性

在独立的裸机环境中,使用虚拟系统调用是绝对正常的,因为我们不希望与操作系统交互。如果您在平台上使用RTOS,则可能有专用的系统调用实现在等着您。因此,可能无需担心此警告。我认为警告消息本身有点误导 - “失败”意味着“不执行任何操作并返回错误状态”,这是明确定义的行为,不应导致程序执行异常。

旁注:我使用 objdump 检查了 10-2020-q4-major 版本的 arm-none-eabi 中的 libnosys.a,它没有这些警告符号。

最后,如何删除消息

正如其他人提到的,在独立环境中,您可以提供自己的虚拟系统调用,并且不要链接到 libnosys。我搜索了ld文档和源代码,没有找到抑制此警告的链接器选项。

请注意,如果您依赖于 C 中使用malloc 的动态内存分配,或者C++ 中的new进行动态内存分配,则 _ sbrk的实现 必须实际工作(更多信息请参见此处),否则您可能会进入“调试如此有趣以至于持续数周”区域。

有趣的是,libnosys 的 _sbrk 实现可以工作,并且没有嵌入警告符号。我强烈建议使用它,除非你需要在外部 RAM 上分配堆等。

使用 libnosys 的额外好处是,您无需在创建的每个项目中编写自定义系统调用,这可能会很烦人且容易出错。

长话短说

话虽如此,实际上有一种方法可以永久摆脱 libnosys 的警告:在工具链目录中查找 libnosys.a (在 arm-none-abi 情况下,每个体系结构和浮动 ABI 都会有一个),然后删除 .a 。档案中的 gnu.warning 符号使用:

arm-none-eabi-objcopy -w -R .gnu.warning.* libnosys.a

请注意,这将不可逆转地修改您的工具链文件。最有可能是有意且无害的方式,但仍然如此。谨慎使用。

如果您使用 CMake 来构建您的项目,我会考虑创建 PRE_LINK 命令来复制相关的 libnosys,删除它的警告,然后与其链接。


小智 5

这些是系统调用需要实现的方法,你使用的是标准库(NEWLIB)的函数,所以你应该根据自己的平台实现这些方法如果你确定不需要实现这些,只需添加一个空的实现到链接添加链接

void _close(void)
{
}
void _lseek(void)
{

}
void _read(void)
{
}
void _write(void)
{
}
Run Code Online (Sandbox Code Playgroud)

void _close(void)
{
}
void _lseek(void)
{

}
void _read(void)
{
}
void _write(void)
{
}
Run Code Online (Sandbox Code Playgroud)

[ 50%] Building C object CMakeFiles/xpad.dir/src/main.c.o
[100%] Linking C executable xpad
/home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: /home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/libc.a(libc_a-closer.o): in function `_close_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/closer.c:47: warning: _close is not implemented and will always fail
/home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: /home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/libc.a(libc_a-lseekr.o): in function `_lseek_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/lseekr.c:49: warning: _lseek is not implemented and will always fail
/home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: /home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/libc.a(libc_a-readr.o): in function `_read_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/readr.c:49: warning: _read is not implemented and will always fail
/home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/bin/ld: /home/wangkai/workspace/xpad/toolchain/arm-gnu-toolchain-11.3.rel1-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.3.1/../../../../arm-none-eabi/lib/libc.a(libc_a-writer.o): in function `_write_r':
/data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/reent/writer.c:49: warning: _write is not implemented and will always fail
[100%] Built target xpad
Run Code Online (Sandbox Code Playgroud)

  • 你的例子是部分正确的,并且会消除错误,但它们确实会造成一些定时炸弹。`read()` 等的原型返回的值是错误代码。由于“C”没有名称修饰,需要“read()”等的代码将编译和链接,但它们可能使用垃圾“r0”值作为缓冲区大小等,认为它们正在读取数据。返回默认失败的示例(提供并警告的示例)可能更好。根据 [newlib 存根](https://sourceware.org/newlib/libc.html#Stubs) `int close(int file) { return -1;}` 等更好。 (2认同)