GNU Arm 嵌入式工具链:未定义对"__sync_synchronize"的引用



我正在尝试更新裸金属嵌入式项目的工具链。我们正在windows上构建,到目前为止,我们一直在使用版本5.4.1 20160609(发行版)[ARM/embedded-5-branch修订版237715]。

现在我正在尝试版本9.3.1 20200408(发行版)(9-2020 q2-update),但我在链接时遇到了一个未定义符号的问题:__sync_synchronize被报告为丢失,我不知道应该从哪个源解决此符号。我必须链接我丢失的图书馆吗?我应该给编译器不同的标志,以便它为该函数生成代码吗?

下面是一个示例,它使用旧的工具链进行编译和链接很好,但使用新的工具链失败了。在这两种情况下都使用了此命令行:

arm-none-eabi-g++ -mthumb -specs=nosys.specs sample.cpp

确切的故障信息是:

c:/projects/cpt_tools/gcc-arm-none-eabi/9.3.1/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld.exe: C:UsersnooneAppDataLocalTempccSZkMXN.o: in function 'use_static_inst(int)': sample.cpp:(.text+0xc): undefined reference to '__sync_synchronize' collect2.exe: error: ld returned 1 exit status

BTW:当我在Linux上运行测试时没有什么区别:

noone@nowhere:~/gcc-arm-none-eabi-9-2020-q2-update/bin$ ./arm-none-eabi-g++ -mthumb -specs=nosys.specs sample.cpp /media/persistent_storage/home/rmatano/gcc-arm-none-eabi-9-2020-q2-update/bin/../lib/gcc/arm-none-eabi/9.3.1/../../../../arm-none-eabi/bin/ld: /tmp/ccltslyj.o: in function 'use_static_inst(int)': />sample.cpp:(.text+0xc): undefined reference to '__sync_synchronize' collect2: error: ld returned 1 exit status

我发现这个问题GCC Linaro交叉编译失败的链接器步骤在一个Windows主机上似乎处理了同样的问题。但是我不能使用建议的指定-mcpu=cortex-a9的解决方案,因为我的代码应该在一个相当旧的硬件上运行('-cpu=arm926ej-s)。

以下是sample.cpp的内容:

// compile with 'arm-none-eabi-g++.exe -mthumb -specs=nosys.specs sample.cpp'
//
// result: in function `use_static_inst(int)':
// sample.cpp:(.text+0x18): undefined reference to `__sync_synchronize'
class A
{
int m_i;
public:
A(int i) : m_i(i)
{
}
int value(int x)
{
return m_i + x;
}
};

int use_static_inst(int x)
{
// in preparation for calling the ctor of this static instance
// the compiler generates a call to __sync_synchronize
static A a(0);
return a.value(x);
}
int main(int argc, char* argv[])
{
return use_static_inst(argc);
}

免责声明:我不在我的专业范围内。

缺少的函数正在实现内存屏障。这在多核CPU(如Cortex-A9)中是需要的,但在arm926ej-s上不太可能需要。由于您使用的工具链明确针对Cortex-M和Cortex-R CPU,如果新的工具链没有针对ARM9 CPU进行大量测试(或根本没有),我也不会感到惊讶。

我的第一个意见是,你应该IMHO不让编译器使用其默认设置,并明确你的目标ARM架构和CPU-请注意,这并不能解决你的问题,链接器错误仍然存在:

arm-none-eabi-g++ -march=armv5tej -mcpu=arm926ej-s -mthumb -specs=nosys.specs sample.cpp 

需要注意的一件有趣的事情是,使用-marm进行编译不会触发链接器错误:

arm-none-eabi-g++ -march=armv5tej -mcpu=arm926ej-s -marm -specs=nosys.specs sample.cpp 

在这种情况下,为__sync_synchronize()生成的代码将是:

00011014 <__sync_synchronize>:
11014:   f44f 637a   mov.w   r3, #4000   ; 0xfa0
11018:   f6cf 73ff   movt    r3, #65535  ; 0xffff
1101c:   4718        bx  r3
1101e:   bf00        nop

我的理解是,这将导致程序分支到地址0xffff0fa0,这似乎有点奇怪:我们使用的是arm-none-eabi工具链,生成的代码似乎试图触发Linuxkuser_memory_barrier的执行-请参阅此处的文档。这可能是因为它相当于在Linux环境中调用__sync_synchronize()。这是IMHO,是工具链中未检测到的错误。

现在,__sync_synchronize()是一个内置的gcc,它确实发布了一个完整的内存屏障。当以Cortex-A9为目标时,它将生成一条数据内存屏障dmb ish指令。之所以需要此指令,是因为Cortex-A9确实支持无序执行,因此程序可能需要在某些点执行完整的内存屏障,更具体地说,如果存在多个内核。

值得注意的是,用于在Linux 5.9.6中实现kuser_memory_barrier的代码(文件arch/arm64/kernel/kuser32.S)也使用dmb ish

__kuser_memory_barrier:         // 0xffff0fa0
.inst   0xf57ff05b      //  dmb     ish
.inst   0xe12fff1e      //  bx      lr

也就是说,如果需要数据内存屏障,可能需要底层硬件为内置实现提供最低限度的支持。

由于arm926ej-s似乎只有指令-内存屏障IMB指令可用,这可能只是因为arm926ej-s不支持无序执行,在这种情况下,不需要调用__sync_synchronize(),您可以尝试提供__sync_synchronize()的空/不执行的实现,但仍然是安全的。你需要确定情况是否如此。

请注意,《arm926ej-s参考手册》仅在谈到紧密耦合内存接口事务时提到了"无序",但您需要再次深入了解。您可能还应该查看为__cxa_guard_acquire()__cxa_guard_release()生成的代码,以便完全了解它们与硬件的关系。您可能不想在多线程应用程序中调试奇怪的问题。

例如,通过查看它们在gcc-arm-none-eabi-9-2020-q2-update/arm-none-eabi/lib/libstdc++_nano.a中的实现,我看不到任何可能阻止它们在目标上使用的特定指令,但我对arm926ej-s指令集并不熟悉,最终应该调用的是您:

Disassembly of section .text.__cxa_guard_acquire:
00000000 <__cxa_guard_acquire>:
0:   e5902000    ldr r2, [r0]
4:   e3120001    tst r2, #1
8:   e1a03000    mov r3, r0
c:   1a000006    bne 2c <__cxa_guard_acquire+0x2c>
10:   e5d02001    ldrb    r2, [r0, #1]
14:   e3520000    cmp r2, #0
18:   0a000000    beq 20 <__cxa_guard_acquire+0x20>
1c:   e7f000f0    udf #0
20:   e3a00001    mov r0, #1
24:   e5c30001    strb    r0, [r3, #1]
28:   e12fff1e    bx  lr
2c:   e3a00000    mov r0, #0
30:   e12fff1e    bx  lr
Disassembly of section .text.__cxa_guard_abort:
00000000 <__cxa_guard_abort>:
0:   e3a03000    mov r3, #0
4:   e5c03001    strb    r3, [r0, #1]
8:   e12fff1e    bx  lr
Disassembly of section .text.__cxa_guard_release:
00000000 <__cxa_guard_release>:
0:   e3a03001    mov r3, #1
4:   e5803000    str r3, [r0]
8:   e12fff1e    bx  lr
guard_error.o:     file format elf32-littlearm

这些额外的预防措施可能是必要的,因为你使用的是2019年发布的C++编译器,其CPU家族已经有近20年的历史了。

我在尝试使用gcc-arm-none-eabi-6-2017-q1-update链接Cortex-R4时遇到了同样的错误。链接器错误为:

Invoking: GNU Linker
"C:/ti/ccs1040/ccs/tools/compiler/gcc-arm-none-eabi-6-2017-q1-update/bin/arm-none-eabi-gcc-6.3.1.exe" -Og -g -gdwarf-3 -gstrict-dwarf -Wall -specs="nosys.specs" -mfloat-abi=hard -Wl,-Map,"RM46L850_GCC_halcogen_cpp.map" -o"RM46L850_GCC_halcogen_cpp.out" "./source/cpp_test.o" "./source/dabort.o" "./source/errata_SSWF021_45.o" "./source/esm.o" "./source/notification.o" "./source/pinmux.o" "./source/sci.o" "./source/sys_core.o" "./source/sys_dma.o" "./source/sys_intvecs.o" "./source/sys_main.o" "./source/sys_mpu.o" "./source/sys_pcr.o" "./source/sys_phantom.o" "./source/sys_pmm.o" "./source/sys_pmu.o" "./source/sys_selftest.o" "./source/sys_startup.o" "./source/sys_vim.o" "./source/system.o" -Wl,-T"../source/sys_link.ld"  -Wl,--start-group -lc -lstdc++ -Wl,--end-group 
makefile:163: recipe for target 'RM46L850_GCC_halcogen_cpp.out' failed
c:/ti/ccs1040/ccs/tools/compiler/gcc-arm-none-eabi-6-2017-q1-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib/hardlibstdc++.a(locale_init.o): In function `(anonymous namespace)::get_locale_mutex()':
locale_init.cc:(.text._ZN12_GLOBAL__N_116get_locale_mutexEv+0xc): undefined reference to `__sync_synchronize'
c:/ti/ccs1040/ccs/tools/compiler/gcc-arm-none-eabi-6-2017-q1-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib/hardlibstdc++.a(locale.o): In function `std::locale::_Impl::_M_install_cache(std::locale::facet const*, unsigned int)':
locale.cc:(.text._ZNSt6locale5_Impl16_M_install_cacheEPKNS_5facetEj+0x18): undefined reference to `__sync_synchronize'
c:/ti/ccs1040/ccs/tools/compiler/gcc-arm-none-eabi-6-2017-q1-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib/hardlibstdc++.a(future.o): In function `std::future_category()':
future.cc:(.text._ZSt15future_categoryv+0xc): undefined reference to `__sync_synchronize'
collect2.exe: error: ld returned 1 exit status

在我的案例中,问题是创建Makefiles的基于TI Eclipse的Code Composer Studio没有向链接器提供与传递给编译器的相同的运行时选项来选择多库。

编译器被赋予了-mcpu=cortex-r4 -mfloat-abi=hard -mfpu=vfpv3-d16,但链接器只被赋予-mfloat-abi=hard。这导致链接器选择了对__sync_synchronize有未定义引用的硬库

一旦链接器被赋予与编译器相同的-mcpu=cortex-r4 -mfloat-abi=hard -mfpu=vfpv3-d16选项,然后选择thumb/v7ar/fpv3/hard multi-lib库,链接就成功了。

供参考,在https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/1023679/ccs-10-4-0-00006-for-the-gcc-arm-compiler-how-does-ccs-determine-how-many-of-the-compiler-runtime-options-to-pass-to-the-linker询问CCS为什么没有向链接器和编译器传递一组一致的运行时选项。

最新更新