【问题标题】:Rust embedded application is not linked correctly under AArch64 systemRust 嵌入式应用程序在 AArch64 系统下未正确链接
【发布时间】:2019-11-23 16:07:03
【问题描述】:

我正在尝试使用 ARM 系统作为主机为 stm32f0 编译和调试嵌入式 rust 应用程序。 该应用程序已经编译并在 Intel 安装下运行。

我在 Pinebook Pro 上运行,由 Quad Cortex-A53、64 位 CPU 驱动。操作系统是 64 位版本的 Debian:

$ uname -a
Linux pinebook 4.4.196 #1 SMP Tue Oct 15 16:54:21 EDT 2019 aarch64 GNU/Linux

我用 rustup 为 AArch64(通道稳定)安装了 rust 和 cargo:

$ rustc --version
rustc 1.39.0 (4560ea788 2019-11-04)
$ cargo --version
cargo 1.39.0 (1c6ec66d5 2019-09-30)

根据this issue,我发现 rust-lld 不是以二进制形式分发给 ARM 系统的,所以我不得不从源代码编译它:

$ ld.lld --version
LLD 10.0.0 (https://github.com/llvm/llvm-project.git 1c247dd028b368875bc36cd2a9ccc7fd90507776) (compatible with GNU linkers)

现在编译过程顺利完成:

export RUSTFLAGS="-C linker=ld.lld"
cargo build

但是生成的 elf 文件似乎链接不正确:尝试使用 gdbopenocd 加载它会导致某种静默失败:

(gdb) target remote :3333
Remote debugging using :3333
0x00000000 in ?? ()
(gdb) load
Start address 0x0, load size 0
Transfer rate: 0 bits in <1 sec.
(gdb) 

加载大小为空,因此不会刷新新程序。相比之下,当使用在我的 Intel 系统中编译的 elf(openocd 仍在 arm 笔记本电脑上运行)时,一切都按预期工作:

(gdb) target remote 192.168.1.153:3333
Remote debugging using 192.168.1.153:3333
0x00000000 in ?? ()
(gdb) load
Loading section .vector_table, size 0xc0 lma 0x8000000
Loading section .text, size 0x686e lma 0x80000c0
Loading section .rodata, size 0x4a0 lma 0x8006940
Start address 0x8005b58, load size 28110
Transfer rate: 19 KB/sec, 7027 bytes/write.
(gdb)

似乎精灵没有正确链接。运行readelf -l 突出显示在我的ARM 系统上,入口点集是0x0,这对于stm32f0 是错误的。 这是我的 ARM 笔记本电脑上的 readelf

lf file type is EXEC (Executable file)
Entry point 0x0
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00010034 0x00010034 0x00060 0x00060 R   0x4
  LOAD           0x000000 0x00010000 0x00010000 0x00094 0x00094 R   0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

 Section to Segment mapping:
  Segment Sections...
   00     
   01     
   02 

虽然这是来自工作的精灵,但在我的英特尔系统下编译:

Elf file type is EXEC (Executable file)
Entry point 0x8005b59
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x08000000 0x08000000 0x06de0 0x06de0 R E 0x1000
  LOAD           0x007de0 0x20000000 0x08006de0 0x00000 0x00028 RW  0x1000
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

 Section to Segment mapping:
  Segment Sections...
   00     .vector_table .text .rodata 
   01     .data .bss 
   02     

我不确定这是否与目标架构与主机相同(因此使用 linux 用户空间链接)或简单因为 arm 系统受支持较少有关。

谁能指出我正确的方向?

【问题讨论】:

  • 你有 stm32f0 上的 Linux 吗?
  • 不,它是一个非常小的 MCU,只是尝试刷入独立固件。

标签: rust arm embedded rust-cargo stm32f0


【解决方案1】:

我认为链接器存在问题是正确的,并且有几个解决方案。

从两年前开始,Rust 使用 LLD 作为 ARM 架构的默认链接器 (https://rust-embedded.github.io/blog/2018-08-2x-psa-cortex-m-breakage/)。不幸的是,rust-lld 本身并没有以二进制形式分发给 ARM 平台(很讽刺,不是吗?),所以我不得不从源代码编译它并通过命令行指定它。

导出RUSTFLAGS 变量有效,但会覆盖.cargo/config 中定义的默认值,其中还包括链接描述文件的指令(-C link-arg=-Tlink.x)。简而言之,我确信使用正确的链接器脚本,因为它在 .cargo/config 中列出,但 RUSTFLAGS 环境变量正在删除它。

解决方案是

  • 在导出 RUSTFLAGS 时明确包含链接描述文件: export RUSTFLAGS="-C linker=ldd -C link-arg=-Tlink.x"
  • "-C", "linker=lld" 指定为.cargo/config 文件中的锈标记以及其他选项
  • 启用旧链接器 (arm-none-eabi-ld),通过取消注释 .cargo/config 中的以下行,可以更轻松地检索它:"-C", "linker=arm-none-eabi-gcc"

【讨论】:

    【解决方案2】:

    您必须使用专用于该板的链接器脚本来创建原始二进制图像。

    https://github.com/szczys/stm32f0-discovery-basic-template/tree/master/Device/ldscripts

    【讨论】:

    • 通常为目标架构指定cargo 包就足够了——它在我的英特尔系统上。我知道如何从头开始设置二进制文件,但我正在开发设置环境
    • 你用链接器脚本试过了吗?根据您的假设,二进制文件未正确链接。 @Gabór 在这里可能是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-16
    • 2020-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多