8

有一个供应商的软件我想合作。他们有一个代码库,只能使用 IAR Embedded Workbench 编译(据我所知,他们的代码不能使用 GCC 编译)。不幸的是,他们的硬件只适用于他们的软件堆栈,所以我真的无法选择是否要使用它。他们将此代码作为.a为 ARM Cortex-M4 CPU 编译的静态库文件(和随附的头文件)分发。(他们不想分发资源。)为了讨论方便,我们称它为evil_sw_stack.a.

我想使用这段代码,但我没有 IAR 许可证并且对 IAR 的专业知识为零。我想使用 GCC。

有没有办法让 IAR 生成这样一个 GCC 可以链接到的静态库?供应商需要使用什么样的编译器选项来生成这样的二进制文件?
(我猜想生成的二进制文件的 ABI 可以以某种方式指定并设置为符合 GCC 的设置。)

GCC 的示例用法

他们的默认软件堆栈对 GCC 非常友好,这个特定的堆栈是他们产品中唯一不支持的堆栈。一般来说,如果我有以下内容,我可以编译一段简单的示例代码:

  • startup_(devicename).S: GCC 特定的汇编文件
  • system_(devicename).c
  • (devicename).ld: 链接器脚本
  • 特定设备的一些头文件

例如,我可以像这样编译一个简单的示例:

$ arm-none-eabi-gcc helloworld.c startup_(devicename).S system_(devicename).c -T (devicename).ld -o helloworld -D(devicename) -I. -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mcpu=cortex-m4 -mthumb -mno-sched-prolog -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group

到目前为止,一切都很好。没有警告,没有错误。

我如何尝试使用静态库

为了讨论方便,我们称它为evil_sw_stack.a
这就是我尝试使用它的方式:

$ arm-none-eabi-gcc evil_sw_stack.a helloworld.c startup_(devicename).S system_(devicename).c -T (devicename).ld -o helloworld -D(devicename) -I. -fno-builtin -ffunction-sections -fdata-sections -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -mcpu=cortex-m4 -mthumb -mno-sched-prolog -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group

不幸的是,这抱怨在system_(devicename).c. 也许他们不小心把它编译到了这个库中?或者也许 IAR 只是这样编译它?现在,如果我尝试system_(devicename).c从 GCC 命令行中删除并简单地链接到该.a文件,我会收到以下错误:

/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: thelibrary.a(startup_chipname.o) uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
undefined reference to `__iar_program_start'
undefined reference to `CSTACK$$Limit'
undefined reference to `__iar_program_start'

戳文件readelf让我无处可去:

$ readelf -h evil_sw_stack.a 
readelf: Error: evil_sw_stack.a: did not find a valid archive header

有趣的是,这似乎正在某个地方:

$ arm-none-eabi-ar x evil_sw_stack.a

现在我有一堆目标文件,它们确实有根据 的 ELF 头文件,是的readelf,他们确实将启动文件(他们的另一个设备的)编译到库中......我想知道为什么,但我认为这个是一个错误。

这也有效:

$ arm-none-eabi-objdump -t evil_sw_stack_objfile.o

所以现在的问题是,尝试使用 GCC 将这些目标文件编译到我自己的应用程序中是否安全?根据this other SO question,目标文件格式不兼容。

我假设启动代码被错误地编译到库中。我可以删除它:

$ arm-none-eabi-ar d evil_sw_stack.a startup_(otherdevicename).o
$ arm-none-eabi-ar d evil_sw_stack.a system_(otherdevicename).o

现在我得到了一个evil_sw_stack.a哪个 gcc 可以接受作为输入而不会抱怨。

但是,还有一件事让我仍然担心。当我使用目标文件而不是静态库时,会收到以下警告:

/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: evil_objfile.o uses 2-byte wchar_t yet the output is to use 4-byte wchar_t; use of wchar_t values across objects may fail
/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: evil_objfile.o uses 32-bit enums yet the output is to use variable-size enums; use of enum values across objects may fail

所以它似乎evil_sw_stack.a是用(IAR 等价物)-fno-short-enums-fshort-wchar. 当我在命令行中使用 GCC 时evil_sw_stack.a,它不会抱怨这一点,但当我尝试使用从库中提取的任何目标文件时,它确实会抱怨。我应该担心这个吗?

我不在wchar_t我的代码中使用,所以我相信一个无关紧要,但我想在我的代码和库之间传递枚举。

更新

即使链接器没有抱怨,当我实际从静态库中调用一些函数时它也不起作用。在这种情况下,请确保在调用链接器时以正确的顺序放置库。根据这个问题的公认答案,它们需要以相反的依赖顺序排列。这样做之后,它仍然遗漏了一些 IAR 废话:

undefined reference to `__aeabi_memclr4'
undefined reference to `__aeabi_memclr'
undefined reference to `__aeabi_memmove'
undefined reference to `__aeabi_memset4'
undefined reference to `__aeabi_memset'
undefined reference to `__iar_vla_alloc2'
undefined reference to `__iar_vla_dealloc2'
undefined reference to `__aeabi_memclr4'

我发现这些__aeabi函数是在中定义的,libgcc但即使我也链接到 libgcc,中的定义libgcc对于里面的函数似乎还不够好evil_sw_stack.a

编辑:经过一番谷歌搜索,似乎arm-none-eabi-gcc不支持这些特定__aeabi功能。看看这个问题

无论如何,在查看ARM 的运行时 ABI 文档__aeabi之后,可以使用它们的标准 C 库等效项轻松实现缺少的函数。但我不太确定如何__iar_vla_alloc2以及__iar_vla_dealloc2应该如何工作,并且在网上找不到任何关于它们的文档。我发现的唯一一件事是 VLA 的意思是“可变长度数组”。

因此,除非芯片供应商能够以不使用这些符号的方式编译他们的静态库,否则这似乎永远不会奏效。那正确吗?

免责声明

我不想透露供应商是谁,也不愿透露我使用的产品。他们对这件事不能正常工作并不感到自豪,并要求我不要这样做。我问这个问题是为了帮助而不是诋毁他们。

4

0 回答 0