为什么 __start 是处理器执行的第一条指令?

(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)

为什么 __start 是处理器执行的第一条指令?

转载请注明出处: http://blog.csdn.net/zhumaill/article/details/23426605

在《 NuttX 启动流程》一文中提到, __start 是处理器执行的第一条指令。那么,为什么在 NuttX 中 __start 是处理器执行的第一条指令?为什么我要把 __start 称为“处理器执行的第一条指令”,而不是称为“程序入口点”?

nuttx/configs/shenzhou/scripts/ld.script:
......
OUTPUT_ARCH(arm)
ENTRY(_stext)
SECTIONS
......
这里的 ENTRY(_stext) 定义的程序入口点是 _stext。

nuttx/arch/arm/src/Makefile:
......
nuttx$(EXEEXT): $(HEAD_OBJ) board/libboard$(LIBEXT)
    $(Q) echo "LD: nuttx"
    $(Q) $(LD) --entry=__start $(LDFLAGS) $(LIBPATHS) $(EXTRA_LIBPATHS) \
        -o $(NUTTX) $(HEAD_OBJ) $(EXTRA_OBJS) \
        --start-group $(LDLIBS) $(EXTRA_LIBS) $(LIBGCC) --end-group
......
这里的 --entry=__start 在链接时重新指定了程序入口点为 __start。
xxx@xxx-desktop ~ $ readelf -h nuttx
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x80003d1
  Start of program headers:          52 (bytes into file)
  Start of section headers:          145184 (bytes into file)
  Flags:                             0x5000202, has entry point, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         3
  Size of section headers:           40 (bytes)
  Number of section headers:         18
  Section header string table index: 15
在编译生成的 elf 文件 nuttx 的文件头中可以找到这个程序入口点的地址0x80003d1。

但是,这个程序入口点只对 elf 格式的文件有用,在非 elf 格式的祼机程序中,这个程序入口点不起作用,我们烧写到芯片 flash 中的格式为 .bin 或 .hex 的文件中没有这个程序入口点的定义。把这里的 __start 改成其它函数一样可以正常运行。

根据 cortex-m3 的定义,系统从 flash 启动时,0x08000004中的值就是 PC(程序计数器)的初始值,这才是真正起作用的,它决定了处理器执行的第一条指令。

nuttx.S:
......
08000000 <_vectors>:
 8000000:    20005db4     .word    0x20005db4
 8000004:    080003d1     .word    0x080003d1       <---PC 初始值
 8000008:    08000159     .word    0x08000159
......
080003d0 <__start>:
 80003d0:    b510          push    {r4, lr}         <---处理器执行的第一条指令
 80003d2:    f000 f827     bl    8000424 
 80003d6:    f000 f967     bl    80006a8 
 80003de:    4b0c          ldr    r3, [pc, #48]    ; (8000410 <__start+0x40>)
......
使用《 NuttX 安装脚本》一文中的方法安装 NuttX 后,反汇编文件 nuttx.S 位于 Linux 当前用户的主目录。这里的 PC 初始值是0x080003d1,指向 __start 函数的起始地址。

顺便说一下,向量表中的跳转地址都是奇数,这是因为 cortex-m3 是在Thumb状态下执行的。在向量表以外的地方,32位指令的跳转地址是奇数,16位指令的跳转地址是偶数。但指令的实际地址都是偶数,如0x080003d0。

nuttx/arch/arm/src/stm32/stm32_vectors.S:
......
_vectors:

/* Processor Exceptions */

    .word    IDLE_STACK            /* Vector  0: Reset stack pointer */
    .word    __start                /* Vector  1: Reset vector */
    .word    stm32_nmi            /* Vector  2: Non-Maskable Interrupt (NMI) */
    .word    stm32_hardfault        /* Vector  3: Hard fault */
......
这里的 .word    __start 定义了 PC 的初始值。

__start 函数的声明与定义如下:

nuttx/arch/arm/src/stm32/stm32_vectors.S:
......
    .globl        __start
......
在汇编代码中声明了全局符号 __start,相当于声明了函数。

nuttx/arch/arm/src/stm32/stm32_start.c:
......
void __start(void)
{
  const uint32_t *src;
  uint32_t *dest;

  /* Configure the uart so that we can get debug output as soon as possible */

  stm32_clockconfig();
  stm32_fpuconfig();
  stm32_lowsetup();
......
}
......
在 C 语言代码中定义了 __start 函数。

你可能感兴趣的:(NuttX)