Skip to main content
  1. Documentation/

MCU的启动分析

162 words·1 min· loading · loading · ·
new docs
Table of Contents

Bootloader 负责在设备启动时初始化MCU的核心硬件设置。这包括配置时钟系统、电源管理、设置内存接口、初始化输入/输出端口等。这是运行应用程序之前必须完成的,以确保硬件处于预期的状态。Bootloader 的核心任务之一是从非易失性存储器(如闪存)中加载主应用程序到RAM中,并开始执行。这允许设备在每次启动时自动执行其主功能,而不需要外部干预。

41000    0x00001000 csrr    a0, mhartid            #; mhartid = 0, (wrb) a0  <-- 0
65000    0x00001004 auipc   a1, 0x0                #; (wrb) a1  <-- 4100
89000    0x00001008 addi    a1, a1, 32             #; a1  = 4100, (wrb) a1  <-- 4132
113000   0x0000100c auipc   t0, 0x0                #; (wrb) t0  <-- 4108
137000   0x00001010 lw      t0, 20(t0)             #; t0  = 4108, t0  <~~ Word[0x00001020]
148000                                              #; (lsu) t0  <-- 0x80000000
161000    0x00001014 jalr    t0         #; t0  = 0x80000000, (wrb) ra  <-- 4120, goto 0x80000000

Screenshot 2024-03-24 at 23.21.31

ELF(可执行与可链接格式,Executable and Linkable Format)是一种广泛使用的文件格式,用于定义程序、库文件和其他编译产物的结构。它是在UNIX系统中最常见的二进制文件格式,被用于不仅是可执行文件,还包括对象文件和共享库文件。ELF格式的设计旨在具有高度的灵活性和可扩展性,以适应各种系统架构和操作系统需求。一个ELF文件主要包含以下部分:

1. 文件头(ELF Header)
#

文件头位于文件的最开始部分,包含了描述整个文件的重要信息,比如:

  • 文件类型:指明这是一个可执行文件、一个可重定位的对象文件还是一个共享对象文件。
  • 机器类型:定义了生成该文件的目标机器架构,如x86、ARM等。
  • 入口点地址(如果是可执行文件):程序开始执行的内存地址。
  • ELF标识符:包括魔数、版本、操作系统/ABI及其版本等,用于验证文件格式和兼容性。

2. 程序头表(Program Header Table)
#

这个表列出了文件中所有段(segments)的信息,系统加载器使用它来加载程序到内存。每个表项提供了段的类型、文件中的偏移位置、内存中的虚拟地址、段的物理地址(如果有)、以及与权限相关的信息等。

3. 节头表(Section Header Table)
#

节头表描述了文件中的所有节(sections),这些节包括了代码、数据、符号表、重定位信息等。每个节头表项指明了节的名称、类型、大小、文件中的偏移、运行时的地址等信息。

4. 节(Sections)
#

ELF文件中的节包括代码(.text)、数据(.data.bss)、符号表(.symtab)、字符串表(.strtab)、重定位信息(.rel.text.rel.data)以及调试信息等。这些节按照节头表中的描述进行排列。

5. 符号表(Symbol Table)
#

符号表存储了程序中定义和引用的各种符号(如函数、变量等)的信息,这对于链接和调试都非常重要。

6. 重定位表(Relocation Table)
#

重定位表包含了必要的信息,用于在链接过程中调整代码和数据的引用。这对于生成可以在内存中任意位置运行的可执行文件是必需的。

7. 动态链接信息(Dynamic Linking Tables)
#

如果文件是动态库或需要动态链接,会包含动态链接信息,如所需库的路径、符号解析和重定位的额外信息。

ELF格式由于其高度的灵活性和广泛的支持,在Unix-like系统(如Linux)中是标准的二进制文件格式。它支持不同的数据编码方式(如小端和大端),并可以通过使用节和段的方式灵活地组织信息。

Screenshot 2024-03-24 at 23.08.29

当Bootloader处理ELF格式的文件进行开机过程时,它遵循一系列步骤来确保正确地加载和执行程序。这个过程通常包括读取ELF文件的不同部分,并将其正确地映射到内存中。以下是Bootloader针对ELF文件进行的开机加载过程的一般步骤:

1. 读取ELF文件头
#

Bootloader首先读取位于ELF文件开始的文件头(ELF Header)。通过文件头,Bootloader可以确定文件的类型(如可执行文件、共享对象文件等)、入口点地址(即程序的起始执行点)、程序头表(Program Header Table)的位置和大小,以及其他关键信息。

2. 解析程序头表
#

接下来,Bootloader读取程序头表,这个表列出了文件中的所有段(segments)。每个段描述中包含了该段的类型、文件中的偏移、内存中的虚拟地址、段的大小等信息。这些信息告诉Bootloader哪些部分需要被加载到内存,以及它们应该被加载到哪里。

3. 将段加载到内存
#

Bootloader按照程序头表中的指示,将文件中的各个段加载到内存指定的位置。通常,这包括代码段(.text)、数据段(.data)、以及可能的只读数据段(.rodata)等。对于未初始化的数据段(.bss),Bootloader通常会在内存中为其分配空间并清零。

4. 处理重定位表
#

如果ELF文件包含重定位表(Relocation Table),Bootloader需要处理这些表项以调整程序中的符号地址。这一步是必需的,因为虽然程序被设计为可以在内存中的任意位置运行,但在链接时生成的地址还需要根据实际加载到内存的位置进行调整。

5. 设置堆栈
#

为了程序能够正常运行,Bootloader需要在内存中设置一个堆栈空间。堆栈的起始地址和大小往往会预先定义,或根据程序的需求动态配置。

6. 跳转到入口点执行
#

一旦所有必需的段都被加载到内存,并且所有必要的重定位处理完成后,Bootloader通过跳转到ELF文件头指定的入口点地址来启动程序的执行。这通常涉及到设置程序计数器(PC)到入口点。

7. 转交控制权
#

控制权完全转交给加载的程序后,Bootloader的任务就结束了。此时,操作系统或应用程序开始执行其初始化序列,继续自我配置并进入正常操作状态。

Bootloader处理ELF文件的这一系列步骤确保了从非易失性存储介质中有效、安全地加载程序到内存,并成功执行。这个过程对于确保系统启动的可靠性和安全性至关重要。

Screenshot 2024-03-24 at 23.43.49

Screenshot 2024-03-25 at 00.01.39

Related

环境配置入门
40 words·1 min· loading · loading
new docs
VlSI1回顾: FPGA组成 与 Dedicated Processor 架构
309 words·2 mins· loading · loading
new docs