繁体   English   中英

构建用于 Nordic SDK 程序的静态 Rust 库时对 `memset' 的多重定义

[英]multiple definition of `memset' when building static rust library to be used for Nordic SDK program

注意:没有看到这是另一个问题的重复。 在我的问题中,我检查了那里提供的建议,但这在这里没有帮助(如下所示)。 如果你有不同的看法,我想知道你在想什么类型的信息,当你写“如果解决方案不起作用,你应该清楚为什么不可行以及你已经尝试解决了什么问题。” 我很高兴提供了解问题所需的一切。

这就是我写这个问题的方式,以询问我可以测试什么或我可以在哪里搜索其他解决方案的其他建议。

我知道这个问题很长。 但是我写的文字实际上是尽可能短的。 这只是我提供的 shell 输出,所以它很长。 所以我认为它实际上很有可读性。

我尝试在 Rust 中构建一个静态库,我想在嵌入式程序中使用它,该程序在 Nordic nRF52832 蓝牙低功耗微控制器上运行。

问题是 Rust 生成的静态库包含符号,这些符号也是由 libc_nano 定义的:

/usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/bin/ld: ../../modem/target/thumbv7em-none-eabihf/release/libtbmodem.a(compiler_builtins-ace0cbd4c713eeda.compiler_builtins.8gdoevk6-cgu.12.rcgu.o): in function `memset':
/checkout/src/rustc/compiler_builtins_shim/../../libcompiler_builtins/src/mem.rs:47: multiple definition of `memset'; /usr/lib/gcc/arm-none-eabi/7.3.1/../../../arm-none-eabi/lib/thumb/v7e-m/fpv4-sp/hard/libc_nano.a(lib_a-memset.o):/build/newlib-4qXI0C/newlib-3.0.0.20180802/build_nano/arm-none-eabi/thumb/v7e-m/fpv4-sp/hard/newlib/libc/string/../../../../../../../../../newlib/libc/string/memset.c:41: first defined here
collect2: error: ld returned 1 exit status

查看nm的输出可以看到,rust 编译的库确实定义了memset和其他一些典型的 libc 函数:

$ nm target/thumbv7em-none-eabihf/release/libtbmodem.a|grep mem
         U __aeabi_memclr
         U __aeabi_memcpy
         U __aeabi_memclr
         U __aeabi_memcpy
         U __aeabi_memcpy
         U __aeabi_memmove
         U __aeabi_memcpy
         U __aeabi_memcpy
         U __aeabi_memmove
         U __aeabi_memcpy
         U memcmp
         U __aeabi_memcpy
00000000 T memcmp
00000000 T memcpy
00000000 T memmove
00000000 T memset
00000000 W __aeabi_memclr
00000000 W __aeabi_memclr4
00000000 W __aeabi_memclr8
00000000 W __aeabi_memcpy
00000000 W __aeabi_memcpy4
00000000 W __aeabi_memcpy8
00000000 W __aeabi_memmove
00000000 W __aeabi_memmove4
00000000 W __aeabi_memmove8
00000000 W __aeabi_memset
00000000 W __aeabi_memset4
00000000 W __aeabi_memset8
         U memcmp
00000000 T _ZN4core5slice6memchr6memchr17h3803f373e8c2e0b4E
00000000 T _ZN4core5slice6memchr7memrchr17hed16b4d75d82bdf8E
         U __aeabi_memcpy
         U memcmp
         U _ZN4core5slice6memchr6memchr17h3803f373e8c2e0b4E
         U __aeabi_memclr4
         U __aeabi_memcpy4
         U memcmp
         U __aeabi_memcpy
         U __aeabi_memset
         U memcmp
         U _ZN4core5slice6memchr6memchr17h3803f373e8c2e0b4E
         U __aeabi_memclr4
         U __aeabi_memcpy4
         U __aeabi_memset
         U __aeabi_memclr4
         U __aeabi_memcpy4
         U memcmp

有趣的是,当我为我的主机架构x86_64-unknown-linux-gnu编译时,这些碰撞符号不是由 Rust 生成的:

$ nm target/x86_64-unknown-linux-gnu/release/libtbmodem.a |grep mem
                 U memcpy
                 U memset
                 U memcpy
                 U memset
                 U memcpy
                 U memmove
                 U memcpy
                 U memcpy
                 U memmove
                 U memcmp
                 U memcpy
                 U memcpy
0000000000000000 T _ZN17compiler_builtins3mem6memcmp17hd848cdf5fbc51bd1E
0000000000000000 T _ZN17compiler_builtins3mem6memcpy17he0a8277ca9da5208E
0000000000000000 T _ZN17compiler_builtins3mem6memset17h0fcc19dd786ae994E
0000000000000000 T _ZN17compiler_builtins3mem7memmove17h75c47f31c61a641fE
0000000000000000 T _ZN4core5slice6memchr6memchr17h3803f373e8c2e0b4E
0000000000000000 T _ZN4core5slice6memchr7memrchr17hed16b4d75d82bdf8E
                 U memcmp
                 U memcpy
                 U _ZN4core5slice6memchr6memchr17h3803f373e8c2e0b4E
                 U memcmp
                 U memcpy
                 U memset
                 U memcmp
                 U memcpy
                 U _ZN4core5slice6memchr6memchr17h3803f373e8c2e0b4E
                 U memcpy
                 U memset
                 U memcmp
                 U memcpy

Rust 在为 ARM 编译时定义这些符号而不是在为 x86_64 编译时定义这些符号的原因是什么?

我知道, 在将 Rust staticlib 与嵌入式 C 程序链接时,“memcmp 的多重定义”错误中也讨论了相同的错误,但那里提供的解决方案对我不起作用。 实际上,我已经将 rust 生成的静态库作为链接器调用的最后一个参数:

arm-none-eabi-gcc -DBUILD=\\" date +%F \\" -DBUILDY= date +%Y -DBUILDM= date +%-m -DBUILDD= date +%-d -mcpu=cortex-m4 -mthumb - mabi=aapcs -mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -Iconfig -std=c99 -DNRF52 -DNRF52832_XXAA -DBOARD_CUSTOM -DBLE_STACK_SUPPORT_REQD -DNRF_SD_BLE_API_VERSION = 6 -DNRF_DFU_SVCI_ENABLED -DNRF_DFU_TRANSPORT_BLE = 1 -DS132 -DSOFTDEVICE_PRESENT -DSWI_DISABLE0 -Wall -Werror -DFLOAT_ABI_HARD -DCONFIG_GPIO_AS_PINRESET -DNRF52_PAN_74 -I /家/马提亚/源极/ tbblue / libtrailer / SRC @sdk_include_paths -OG -g3 -DDEBUG -DDEBUG_NRF -mthumb -mabi=aapcs -mcpu=cortex-m4 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=tbplatform.map,--wrap ,_sbrk -L/home/matthias/source/tbblue/libtrailer/src -L /home/matthias/source/tbblue/nRF5_SDK//components/toolchain/gcc -T tbplatform.ld -o tbplatform .sdk/modules/nrfx/ mdk/gcc_startup_nrf52.o nrfplatform.o base64.o bleinithelper.o ble_dfu_service.o 广播。 o config_service.o fw_version.o main.o mac_address.o modem.o nrf_ble_qwrs.o on_board_flash.o service.o system.o 隔间_util.o saved_config.o temperature_util.o tick_util.o digitalinput/digital.o spi/spi.o spi/can/can_controller.o spi/can/can_interrupt.o spi/can/can_timer.o spi/can/can.o spi/uart/spi_uart.o uart/datacold500_uart.o uart/datacold600_uart.o uart/euroscan_uart.o uart/ibox_uart.o uart/uart.o .sdk/components/ble/ble_advertising/ble_advertising.o .sdk/components/ble/ble_services/ble_dfu/ble_dfu.o .sdk/components/ble/ble_services/ble_dfu/ble_advertising.o .sdk/components/ble/ble_services/ble_dfu/ble_dfu.o .sdk/components/ble/ble_services/ble_dfu/ble_advertising.o .sdk/components/ble/common/ble_advdata.o .sdk/components/ble/common/ble_conn_params.o .sdk/components/ble/common/ble_conn_state.o .sdk/components/ble/common/ble_srv_common.o .sdk /components/ble/nrf_ble_gatt/nrf_ble_gatt.o .sdk/components/ble/peer_manager/gatt_cache_manager.o .sdk/components/ble/peer_manager/gatts_cache_manager.o .sdk/components/ble/peer_manager/gatt_cache_manager.o /ble/peer_manager/peer_database. o .sdk/components/ble/peer_manager/peer_data_storage.o .sdk/components/ble/peer_manager/peer_id.o .sdk/components/ble/peer_manager/peer_manager.o .sdk/components/ble/peer_buffer.pm sdk/components/ble/peer_manager/pm_mutex.o .sdk/components/ble/peer_manager/security_dispatcher.o .sdk/components/ble/peer_manager/security_manager.o .sdk/components/boards/boards.o .sdk/components图书馆/原子/nrf_atomic.o .sdk/components/libraries/atomic_fifo/nrf_atfifo.o .sdk/components/libraries/atomic_flags/nrf_atflags.o .sdk/components/libraries/balloc/nrf_ballocaries/component/slibraries/引导加载程序/dfu/nrf_dfu_svci.o .sdk/components/libraries/crc16/crc16.o .sdk/components/libraries/experimental_log/src/nrf_log_default_backends.o .sdk/components/libraries/experimental.rfdsrdk.组件/库/experimental_log/src/nrf_log_backend_serial.o .sdk/components/libraries/experimental_log/src/nrf_log_backend_uart.o .sdk/components/libraries/experimental_log/src/nr f_log_frontend.o .sdk/components/libraries/experimental_log/src/nrf_log_str_formatter.o .sdk/components/libraries/experimental_memobj/nrf_memobj.o .sdk/components/libraries/experimental_section_components.fdlibraries/experimental_section_components/flibraries fds.o .sdk/components/libraries/fifo/app_fifo.o .sdk/components/libraries/fstorage/nrf_fstorage.o .sdk/components/libraries/fstorage/nrf_fstorage_sd.o .sdk/components/mg_wrfmtmpm o .sdk/components/libraries/strerror/nrf_strerror.o .sdk/components/libraries/timer/app_timer.o .sdk/components/libraries/uart/app_uart_fifo.o .sdk/components/libraries/uart/retarget.o . sdk/components/libraries/util/app_error_weak.o .sdk/components/libraries/util/app_util_platform.o .sdk/components/softdevice/common/nrf_sdh.o .sdk/components/softdevice/common/nrf_sdh_ble.o .sdk组件/softdevice/common/nrf_sdh_soc.o .sdk/external/fprintf/nrf_fprintf.o .sdk/external/fprintf/nrf_fprintf_format.o .sdk/external/segger_rtt/SEGGER_RTT.o .sdk/ l/segger_rtt/SEGGER_RTT_Syscalls_GCC.o .sdk/external/segger_rtt/SEGGER_RTT_printf.o .sdk/external/tiny-AES128/aes.o .sdk/integration/nrfx/legacy/nrf_drvs/integration/nrf_drvsdspi nrf_drv_uart.o .sdk/modules/nrfx/drivers/src/nrfx_gpiote.o .sdk/modules/nrfx/drivers/src/nrfx_spis.o .sdk/modules/nrfx/drivers/src/nrfx_uart.o nrfx/drivers/src/nrfx_uarte.o .sdk/modules/nrfx/drivers/src/prs/nrfx_prs.o .sdk/modules/nrfx/drivers/src/nrfx_spim.o .sdk/modules/nrfx.mrfk/system o -ltrailer ../../modem/target/thumbv7em-none-eabihf/release/libtbmodem.a

(这是文件libtbmodem.a 。)

我还能做些什么来链接图书馆?

我今天遇到了和你一样的问题,我可以提供一个可能的答案(它适用于我的情况)以及为什么它有效的部分回应:

TL;DR:我的解决方案是将 Rust 库放在链接器行上的libc之前 在您的情况下,这意味着将您的电话更改为:

arm-none-eabi-gcc [...] specs=nano.specs -ltbmodem -lc -lnosys [...]

说明:检查我的 Rust 库显示,与您的情况一样, memcpymemset等符号是从我的静态库中导出的。 请注意,这些包含在具有其他几个与内存相关的功能的对象中:

$ nm librustlib.a
[...]
compiler_builtins-17b2875688712538.compiler_builtins.eth5fjl6-cgu.100.rcgu.o:
00000000 T bcmp
00000000 T memcmp
00000000 T memcpy
00000000 T memmove
00000000 T memset
00000000 T _ZN17compiler_builtins3mem40__llvm_memcpy_element_unordered_atomic_117h2c6de8c0ed769de1E
[... seven "compiler_builtins" functions more omitted ...]
00000000 T _ZN17compiler_builtins3mem41__llvm_memmove_element_unordered_atomic_417h971099a5edfec01eE
[...]

其中一些函数也从libc导出,例如:

$ nm /usr/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc_nano.a
[...]
lib_a-memcpy.o:

lib_a-memcpy-stub.o:
00000000 t $t
00000001 T memcpy
[...]

具体来说,可以在libc_nano.a找到没有名称修改的五个函数(具有正常名称的函数)。

要了解链接顺序在这里是否有所不同,我阅读了静态链接中的库顺序,其中包含以下有趣的部分:

当链接器遇到一个新的库时,事情就变得更有趣了。 链接器遍历库中的所有对象。 对于每一个,它首先查看它导出的符号。

  • 如果它导出的任何符号在未定义列表中,则该对象将添加到链接中并执行下一步。 否则,跳过下一步。
  • 如果对象已添加到链接,则按上述方式处理 - 其未定义和导出的符号将添加到符号表中。
  • 最后,如果库中的任何对象已包含在链接中,则会再次重新扫描库 - 由包含的对象导入的符号可能会在同一库中的其他对象中找到。

因此,当链接器扫描一个库时,每个包含的对象都被单独处理,可以使用或从最终结果中省略,这取决于链接器是否需要它,即它是否定义了一个仍未定义的符号。 在上面的文章中,这是这样表述的:

另请注意,在检查库时,如果其中的目标文件不提供符号表所需的符号,则可以将其排除在链接之外。 这是静态链接的一个非常重要的特性。 我之前提到的 C 库大量使用了这个特性,主要是将自身拆分为一个对象每个函数。

为了将我的 Rust 库与 C 代码(以及libc )链接,这特别意味着:

  • 如果 Rust 库在命令行中比libc更早放置,则定义内存相关函数的“compiler_builtins”对象将在最终结果中链接。 之后检查libc ,已经定义了与内存相关的函数,因此将省略libc中的相应对象。
  • 如果稍后将 Rust 库放在命令行中,则将使用libc与内存相关的函数。 然后,链接器使用 Rust 库中的对象,很可能是因为需要名称修饰函数。 这让我们不得不将memcpy等定义两次,这是一个错误。

我希望这些信息仍然有用,或者可以对将来偶然发现相同问题的任何人有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM