Rust 嵌入式应用程序在 AArch64 系统下未正确链接
Rust embedded application is not linked correctly under AArch64 system
我正在尝试使用 ARM 系统作为主机为 stm32f0 编译和调试嵌入式 Rust 应用程序。
该应用程序已在 Intel 安装下编译和运行。
我 运行 使用 Pinebook Pro,由 Quad Cortex-A53,64 位 CPU 驱动。 OS 是 Debian 的 64 位版本:
$ uname -a
Linux pinebook 4.4.196 #1 SMP Tue Oct 15 16:54:21 EDT 2019 aarch64 GNU/Linux
我为 AArch64 安装了 rust 和 cargo with rustup(通道稳定):
$ 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 文件似乎链接不正确:尝试使用 gdb
加载它到 openocd
会导致某种静默失败:
(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 时(在 arm 笔记本电脑上 openocd
仍然是 运行),一切都按预期工作:
(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 系统受支持较少。
谁能指出我正确的方向?
您必须使用专用于该板的链接描述文件创建原始二进制映像。
https://github.com/szczys/stm32f0-discovery-basic-template/tree/master/Device/ldscripts
我假设链接器有问题是正确的,并且有几个解决方案。
从两年前开始,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
env 变量正在删除它。
解决方案是
- 在导出 RUSTFLAGS 时显式包含链接描述文件:
export RUSTFLAGS="-C linker=ldd -C link-arg=-Tlink.x"
- 在
.cargo/config
文件中将 "-C", "linker=lld"
指定为 rust 标志,并使用其他选项
- 启用旧链接器 (
arm-none-eabi-ld
),通过取消注释 .cargo/config
中的以下行更容易检索:"-C", "linker=arm-none-eabi-gcc"
我正在尝试使用 ARM 系统作为主机为 stm32f0 编译和调试嵌入式 Rust 应用程序。 该应用程序已在 Intel 安装下编译和运行。
我 运行 使用 Pinebook Pro,由 Quad Cortex-A53,64 位 CPU 驱动。 OS 是 Debian 的 64 位版本:
$ uname -a
Linux pinebook 4.4.196 #1 SMP Tue Oct 15 16:54:21 EDT 2019 aarch64 GNU/Linux
我为 AArch64 安装了 rust 和 cargo with rustup(通道稳定):
$ 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 文件似乎链接不正确:尝试使用 gdb
加载它到 openocd
会导致某种静默失败:
(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 时(在 arm 笔记本电脑上 openocd
仍然是 运行),一切都按预期工作:
(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 系统受支持较少。
谁能指出我正确的方向?
您必须使用专用于该板的链接描述文件创建原始二进制映像。
https://github.com/szczys/stm32f0-discovery-basic-template/tree/master/Device/ldscripts
我假设链接器有问题是正确的,并且有几个解决方案。
从两年前开始,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
env 变量正在删除它。
解决方案是
- 在导出 RUSTFLAGS 时显式包含链接描述文件:
export RUSTFLAGS="-C linker=ldd -C link-arg=-Tlink.x"
- 在
.cargo/config
文件中将"-C", "linker=lld"
指定为 rust 标志,并使用其他选项 - 启用旧链接器 (
arm-none-eabi-ld
),通过取消注释.cargo/config
中的以下行更容易检索:"-C", "linker=arm-none-eabi-gcc"