esp32c3 no_std 工程的编译过程与程序的启动过程

  • 依赖关系

  • 构建过程

大量的构建过程都在各个库中的 build.rs 中实现,主要是通过不同的构建目录将预定点的链接文件复制到输出目录中,并通过 cargo:rustc-link-search= 指令将对应的目录加入到链接脚本的查询目录中,最后在构建是 通过 link-arg= 加上指定的入口链接脚本 构建完成的目标文件。

构建的目标文件的内存布局由链接脚本控制,所以可能也需要看看链接脚本的内容,脚本在hal库中 和对应的型号库中都有, 不过在生成后都会复制到输出目录中,在target/riscv32imc-unknown-none-elf/build 下对应的esp-hal 和 esp32c3 中会有复制过来的链接脚本,linkall.x 作为入口引入其他所需的脚本文件。

  • 执行过程

rust 代码入口在 esp-riscv-rt 库中的 lib.rs 中,通过一段内嵌宏实现的入口点,在引导程序bootloader执行完成后会跳转到 _start 入口处。在进入main方法前的代码需要结合 链接脚本中的符号定义进行分析。

跳转过程:

_start -》 _abs_start -》_start_rust

_start_rust 方法对应start_rust 方法,

start_rust方法中顺序调用 __post_init(); _setup_interrupts();main(a0, a1, a2);

fn main 对应到我们定义的main方法

__post_init 对应 default_post_init 方法,这个方法是一个外部方法,置未找到实现位置,

_setup_interrupts = default_setup_interrupts

default_setup_interrupts 中会调用 mtvec::write 设置中断入口为_start_trap

_start_trap = default_start_trap

default_start_trap 定义在汇编部分

代码执行流程大概如下:

通过_start 进入程序后跳转到 _start_rust 汇编处 ,start_rust 中会调用 _setup_interrupts() 设置中断入口,

然后通过main(a0, a1, a2);进入被#[entry]标记的方法中。当有中断触发时会进入default_start_trap

汇编处再跳到 start_trap_rust 中,通过mcause 寄存器判断出是异常还是中断,中断与异常会进入不同的处理方法,

异常会进入ExceptionHandler , 中断会判断中断类型进入不同的handler中,这些handler 都是与相应的中断名称相关联的,

在链接脚本当中会定义所有中断默认为 DefaultInterruptHandler ,这个默认处理中是一空loop,所以我们需要定义不同的

中断处理程序,比如GPIO 中断就定义一个GPIO方法并用 #[interrupt]标记, 中断标记与入口标记类似会导出相应的符号

由对应的程序调用。

  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值