构建要用于Nordic SDK程序的静态锈库时,对“ memset”有多种定义

时间:2018-09-04 11:56:24

标签: linker rust embedded libc

  

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

     

通过这种方式,我写了这个问题,以寻求其他建议,例如我可以测试的东西或可以在哪里搜索其他解决方案的东西。

     

我知道这个问题很长。但是我写的文字实际上尽可能短。只是我提供的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编译时定义这些符号的原因是什么?

我知道,"multiple definition of `memcmp" error when linking Rust staticlib with embedded C program中也讨论了相同的错误,但是那里提供的解决方案对我不起作用。实际上,我已经有了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 broadcast.o config_servic eo fw_version.o main.o mac_address.o调制解调器.o nrf_ble_qwrs.o on_board_flash.o service.o system.o spacer_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_u .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_dfu_unbondedded.o .sdk /组件/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 / id_s peer_manager / peer_database.o .sdk / componen ts / 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_manager / pm_buffer.s .sdk / component 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 / libraries / atomic / nrf_atomic.o .sdk / components / libraries / atomic_fifo / nrf_atfifo.o .sdk / components / libraries / atomic_flags / nrf_atflags.o .sdk / components / libraries / balloc / nrf_balloc.o .sdk / boots / loaders / loaders / libraries 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_log / src / nrk_library / src / nrf_log_back实验性日志/src/nrf_log_backend_serial.o .sdk / components / libraries / experimental_log / src / nrf_log_backend_uart.o .sdk / components / libraries / experimental_log / src / nrf_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_vars / nrff_section_iters。 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 / libraries / pwr_mgmt / nrfmt。 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 /组件/库/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 / components / 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 / external / segger_rtt.o GGER_RTT_Syscalls_GCC.o .sdk / external / segger_rtt / SEGGER_RTT_printf.o .sdk / external / tiny-AES128 / aes.o .sdk / integration / nrfx / legacy / nrf_drv_spi.o .sddk / integration / nacy_acy sdk /模块/ nrfx /驱动程序/src/nrfx_gpiote.o .sdk /模块/ nrfx /驱动程序/src/nrfx_spis.o .sdk /模块/ nrfx /驱动程序/src/nrfx_uart.o .sdk /模块/驱动器/sr/nrfx_uartx.o src / nrfx_uarte.o .sdk / modules / nrfx / drivers / src / prs / nrfx_prs.o .sdk / modules / nrfx / drivers / src / nrfx_spim.o .sdk / modules / nrfx / mdk / system_nrrf52。 ./../ modem / target / thumbv7em-none-eabihf / release / libtbmodem.a

(这是文件libtbmodem.a。)

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

1 个答案:

答案 0 :(得分:0)

我今天遇到的问题与您相同,我可以提供一个可能的答案(在我的情况下有效)以及部分答案,以确保其正常工作:

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中找到五个没有名称修饰的函数(具有 normal 名称的函数)。

要了解链接顺序是否会有所不同,我已阅读Library Order in Static Linking,其中包含以下有趣的部分:

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

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

因此,当链接程序扫描库时,每个包含的对象都将被单独处理,并且可以根据最终链接程序是否需要它(即,是否定义了仍然存在的符号)而在最终结果中使用或忽略该对象未定义。在上面的文章中,它表示为:

还请注意,在检查库时,如果其中的目标文件未提供符号表所需的符号,则可以将该对象排除在链接之外。这是静态链接的一个非常重要的功能。我之前提到的C库主要通过将自身拆分为每个功能一个对象来大量使用此功能。

要链接我的Rust库与C代码(并因此链接libc),这意味着:

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

我希望这些信息对将来遇到相同问题的任何人仍然有帮助或帮助。