linker - 通过使用内联汇编的 Raspberry Pi3 的 Rust 启动代码

标签 linker raspberry-pi rust

我正在用 Rust 为 Raspberry Pi 3 编写裸机代码,但是,我对放置在@0x80000 上的代码有疑问,因为它不是 _start 功能。

编译器设置为 AArch64 架构,我使用 LLD 作为链接器。

# .cargo/config
[build]
target = "aarch64-unknown-none"

[target.aarch64-unknown-none]
rustflags = [
  # uncomment to use rustc LLD linker
   "-C", "link-arg=-Tlayout.ld",
   "-C", "linker=lld-link",
   "-Z", "linker-flavor=ld.lld",
]

启动后调用的第一个函数:(获取核心ID,让主继续,其他停止;为主内存和初始化内存设置堆栈)

#[link_section = ".reset_vector"]
#[no_mangle]
pub extern "C" fn _start() -> !{

    unsafe {
        // Halt all cores but the primary
        asm!(" mrs x1, mpidr_el1
                    and x1, x1, #3
                    cmp x1, #0
                    bne halt"::::"volatile");

        // Setup stack pointer
        asm!(" mov sp, #0x80000"::::"volatile");
    }

  init_runtime();

  main();
  loop{}
}

fn init_runtime() {
    extern "C" {
        static mut _sbss: u64;
        static mut _ebss: u64;

        static mut _sdata: u64;
        static mut _edata: u64;

        static _sidata: u64;
    }

    unsafe{
        // Zero the BSS section in RAM
        r0::zero_bss(&mut _sbss, &mut _ebss);
        // Copy variables in DATA section in FLASH to RAM
        r0::init_data(&mut _sdata, &mut _edata, &_sidata);
    } 
}

停止除主要核心之外的核心的功能:

#[no_mangle]
pub fn halt() {
    unsafe {asm!("wfe"::::"volatile");}
}

我正在使用 r0 crate 来初始化内存:

fn init_runtime() {
    extern "C" {
        static mut _sbss: u64;
        static mut _ebss: u64;

        static mut _sdata: u64;
        static mut _edata: u64;

        static _sidata: u64;
    }

    unsafe{
        // Zero the BSS section in RAM
        r0::zero_bss(&mut _sbss, &mut _ebss);
        // Copy variables in DATA section in FLASH to RAM
        r0::init_data(&mut _sdata, &mut _edata, &_sidata);
    } 
}

最后是链接描述文件:

ENTRY(_start)

SECTIONS {
  . = 0x80000;

  .text : {
      KEEP(*(.reset_vector));
      __reset_vector = ABSOLUTE(.);
      *(.text .text.* .gnu.linkonce.t*)
  }

  .rodata : {
    *(.rodata .rodata.* .gnu.linkonce.r*)
  }

  .data : {
    _sdata = .;
    *(.data .data.* .gnu.linkonce.d*)
    _edata = ALIGN(8);
  }

  .bss (NOLOAD) : {
    . = ALIGN(32);
    _bss = .;
    *(.bss .bss.*)
    *(COMMON)
    _ebss = ALIGN(8);
  }

  __bss_length = (__bss_end - __bss_start);

  /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}

下面是反汇编:

(gdb) disassemble 0x0000000000080000, 0x000000000008035c
Dump of assembler code from 0x80000 to 0x8035c:
=> 0x0000000000080000 <core::mem::uninitialized+0>:     sub     sp, sp, #0x10
   0x0000000000080004 <core::mem::uninitialized+4>:     ldr     x0, [sp, #8]
   0x0000000000080008 <core::mem::uninitialized+8>:     str     x0, [sp]
   0x000000000008000c <core::mem::uninitialized+12>:    ldr     x0, [sp]
   0x0000000000080010 <core::mem::uninitialized+16>:    add     sp, sp, #0x10
   0x0000000000080014 <core::mem::uninitialized+20>:    ret

来自函数 _start 的指令需要放置在@0x80000 处,但情况并非如此,因为有那些 core::mem::uninitialized

如何修改链接描述文件,使 mrs x1, mpidr_el1 成为第一个被执行的指令?

最佳答案

经过漫长的夜战,我想出了办法。

首先在链接器中创建一个新部分:

ENTRY(reset)
SECTIONS {

  . = 0x80000;
  .reset : {
      KEEP(*(.reset))
      . = ALIGN(8);
    }

  .text  : {
      *(.text .text.* .gnu.linkonce.t*)
  }
  ...

并修改代码:

#[link_section=".reset"]
#[no_mangle]
#[naked]
pub extern "C" fn reset () {
unsafe {
        // Halt all cores but the primary and set stack pointer
        asm!(" mrs x1, mpidr_el1
               and x1, x1, #3
               cmp x1, #0
               bne halt
               mov sp, #0x80000
               b init
             "::::"volatile");
    }
 }

其余的:

#[naked]
#[no_mangle]
pub fn init() { 
    extern "C" {
        static mut _sbss: u64;
        static mut _ebss: u64;

        static mut _sdata: u64;
        static mut _edata: u64;

        static _sidata: u64;
    }

    unsafe{
        // Zero the BSS section in RAM
        r0::zero_bss(&mut _sbss, &mut _ebss);
        // Copy variables in DATA section in FLASH to RAM
        r0::init_data(&mut _sdata, &mut _edata, &_sidata);
    }

    extern "Rust" {
        fn main() -> !;
    }

    unsafe { main(); }
}

通过拆分代码,重置中的初始化保持在 0x80000

Disassembly of section .reset:

0000000000080000 <reset>:
   80000:       d53800a1        mrs     x1, mpidr_el1
   80004:       92400421        and     x1, x1, #0x3
   80008:       f100003f        cmp     x1, #0x0
   8000c:       54001481        b.ne    8029c <halt>  // b.any
   80010:       b26d03ff        mov     sp, #0x80000                    // #524288
   80014:       1400008d        b       80248 <init>
   80018:       d65f03c0        ret
   8001c:       00000000        .inst   0x00000000 ; undefined

关于linker - 通过使用内联汇编的 Raspberry Pi3 的 Rust 启动代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52470249/

相关文章:

node.js - 如何从本地网络中的另一台电脑访问我的 React 应用程序?

rust - 如何获得副本类型的内部可变性?

c++ - 此处首先定义的多重定义 gcc

与交叉编译器的静态链接

visual-studio-2013 - Visual Studio 中的链接库,为什么有两种不同的方式?

javascript - JavaScript 应用程序拒绝向 Rust Rocket 服务器发出错误连接请求

rust - 无法为返回引用的闭包推断适当的生存期

python - 使用 python 扩展时链接到其他库(例如 boost)

raspberry-pi - HCI LE 连接——命令不允许

linux - 通过终端命令打开树莓派终端?