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

时间:2021-12-14 01:06:18
(嵌入式 实时操作系统 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:
[cpp] view plain copy print?(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)
  1. ......  
  2. OUTPUT_ARCH(arm)  
  3. ENTRY(_stext)  
  4. SECTIONS  
  5. ......  
这里的 ENTRY(_stext) 定义的程序入口点是 _stext。

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

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

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

nuttx.S:
[cpp] view plain copy print?(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)
  1. ......  
  2. 08000000 <_vectors>:  
  3.  8000000:    20005db4     .word    0x20005db4  
  4.  8000004:    080003d1     .word    0x080003d1       <---PC 初始值  
  5.  8000008:    08000159     .word    0x08000159  
  6. ......  
  7. 080003d0 <__start>:  
  8.  80003d0:    b510          push    {r4, lr}         <---处理器执行的第一条指令  
  9.  80003d2:    f000 f827     bl    8000424 <stm32_clockconfig>  
  10.  80003d6:    f000 f967     bl    80006a8 <stm32_lowsetup>  
  11.  80003de:    4b0c          ldr    r3, [pc, #48]    ; (8000410 <__start+0x40>)  
  12. ......  
使用《 NuttX 安装脚本》一文中的方法安装 NuttX 后,反汇编文件 nuttx.S 位于 Linux 当前用户的主目录。这里的 PC 初始值是0x080003d1,指向 __start 函数的起始地址。

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

nuttx/arch/arm/src/stm32/stm32_vectors.S:
[cpp] view plain copy print?(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)
  1. ......  
  2. _vectors:  
  3.   
  4. /* Processor Exceptions */  
  5.   
  6.     .word    IDLE_STACK            /* Vector  0: Reset stack pointer */  
  7.     .word    __start                /* Vector  1: Reset vector */  
  8.     .word    stm32_nmi            /* Vector  2: Non-Maskable Interrupt (NMI) */  
  9.     .word    stm32_hardfault        /* Vector  3: Hard fault */  
  10. ......  
这里的 .word    __start 定义了 PC 的初始值。

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

nuttx/arch/arm/src/stm32/stm32_vectors.S:
[cpp] view plain copy print?(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)
  1. ......  
  2.     .globl        __start  
  3. ......  
在汇编代码中声明了全局符号 __start,相当于声明了函数。

nuttx/arch/arm/src/stm32/stm32_start.c:
[cpp] view plain copy print?(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)(嵌入式 实时操作系统 rtos nuttx 7.1 stm32 源代码分析)
  1. ......  
  2. void __start(void)  
  3. {  
  4.   const uint32_t *src;  
  5.   uint32_t *dest;  
  6.   
  7.   /* Configure the uart so that we can get debug output as soon as possible */  
  8.   
  9.   stm32_clockconfig();  
  10.   stm32_fpuconfig();  
  11.   stm32_lowsetup();  
  12. ......  
  13. }  
  14. ......  
在 C 语言代码中定义了 __start 函数。