我无法在链接描述文件中指定 Rust 程序的起始偏移量是不是有原因?

Posted

技术标签:

【中文标题】我无法在链接描述文件中指定 Rust 程序的起始偏移量是不是有原因?【英文标题】:Is there a reason I am unable to specify the start offset of a Rust program in a linker script?我无法在链接描述文件中指定 Rust 程序的起始偏移量是否有原因? 【发布时间】:2021-10-02 14:28:36 【问题描述】:

我正在尝试为 Raspberry Pi 编译一个 Rust 程序。我的印象是起始地址需要是0x8000,所以我使用自定义链接器脚本来布局程序以遵循这个要求:

SECTIONS

  .text 0x8000 : 
    *(.text)
  

  .data : 
    *(.data)
  

我在架构文件aarch64-unknown-none.json中指定了这一点:


  "arch": "aarch64",
  "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
  "disable-redzone": true,
  "executables": true,
  "features": "+strict-align,+neon,+fp-armv8",
  "linker": "rust-lld",
  "linker-flavor": "ld.lld",
  "pre-link-args": 
    "ld.lld": [
      "-Taarch64-raspi3.ld"
    ]
  ,
  "llvm-target": "aarch64-unknown-none",
  "max-atomic-width": 128,
  "panic-strategy": "abort",
  "relocation-model": "static",
  "target-pointer-width": "64",
  "unsupported-abis": [
    "stdcall",
    "stdcall-unwind",
    "fastcall",
    "vectorcall",
    "thiscall",
    "thiscall-unwind",
    "win64",
    "sysv64"
  ]

我使用cargo build -Zbuild-std --features=raspi3 --target=aarch64-unknown-none.json --release 命令构建。

这是我的main.rs

#![cfg_attr(not(test), no_std)]
#![cfg_attr(not(test), no_main)]
#![feature(global_asm)]
#![feature(asm)]
#![feature(naked_functions)]

#[cfg(not(test))]
global_asm!(include_str!("platform/raspi3/start.s"));

mod aarch64;
mod panic;
mod platform;

这里是start.s

.section .init
.global _start

.equ BASE,  0x3f200000 //Base address
.equ GPFSEL2, 0x08          //FSEL2 register offset 
.equ GPSET0,  0x1c          //GPSET0 register offset
.equ GPCLR0,0x28            //GPCLR0 register offset
.equ SET_BIT3,   0x08       //sets bit three b1000      
.equ SET_BIT21,  0x200000   //sets bit 21
.equ COUNTER, 0xf0000

_start:
    ldr x0, =BASE
    ldr x1, =SET_BIT3
    str x1, [x0, #GPFSEL2]
    ldr x1, =SET_BIT21
    str x1, [x0, #GPSET0]
    b _start

当我编译它时,它将起始块放置在 0x0 处,如下所示:

0000000000000000 <_start>:
   0:   d2a7e400        mov     x0, #0x3f200000                 // #1059061760
   4:   d2800101        mov     x1, #0x8                        // #8
   8:   f9000401        str     x1, [x0, #8]
   c:   d2a00401        mov     x1, #0x200000                   // #2097152
  10:   f801c001        stur    x1, [x0, #28]
  14:   17fffffb        b       0 <_start>

发生这种情况有什么原因吗?

【问题讨论】:

【参考方案1】:

当你写作时:

.text 0x8000 : 
    *(.text)
  

您告诉链接器通过连接每个编译模块 (*) 中的 .text 部分来在地址 0x8000 处设置可执行的 .text 部分。

但是,在您的程序集中,_start 函数在.section .init 中定义,链接描述文件中的任何地方都没有提及。我不确定链接描述文件中未提及的部分究竟会发生什么,但我很确定依赖它是一个坏主意。

您可能希望您的 .init 部分位于可执行文件 .text 部分的开头:

  .text 0x8000 : 
    *(.init) /* _start */
    *(.text)
  

注意:据我所知,Rust 不会将所有代码发送到一个大的 .text 部分,但它会创建一个更小的 .text.name_of_the_thing 部分。您可能希望将它们全部链接在一起:

  .text 0x8000 : 
    *(.init) /* _start */
    *(.text)
    *(.text.*)
  

【讨论】:

我认为未提及的部分根本不会成为链接器输出的一部分。 @PeterCordes:这就是我的想法,但 OP 确实将_start 放入可执行文件中,但没有提及其部分,我复制了它。它最终出现在 exe 中的 .init 部分。我的猜测是未提及的部分被复制到同名的输出部分。但是按什么顺序呢? 我以为我记得在其他问答中会出现类似的内容,但可能是我记错了写的内容,或者在某个地方有错误的想法。 @PeterCordes:来自info ld,我想如果您使用伪造的SECTIONS(强调我的),它同样适用:“如果您在您的链接器脚本,链接器会将每个输入节放置到按照在输入文件中第一次遇到这些节的顺序,以相同名称的输出节。例如,如果所有输入节都存在于第一个文件中,输出文件中节的顺序将与第一个输入文件中的顺序相匹配。第一个节的地址为零。"

以上是关于我无法在链接描述文件中指定 Rust 程序的起始偏移量是不是有原因?的主要内容,如果未能解决你的问题,请参考以下文章

我啥时候需要在 Rust 中指定显式生命周期?

如何在 SQL 中指定主键起始编号

Rust: Cargo 使用本地 crate

在Java中指定默认文件编码[重复]

链接器脚本:我可以在多个部分中指定 (*COMMON) 吗?

无法在 Qt5/cmake 项目中加载 Qt 资源文件中指定的图像