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


(嵌入式 实时操作系统 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:
  1. ......  
  2. OUTPUT_ARCH(arm)  
  3. ENTRY(_stext)  
  4. SECTIONS  
  5. ......  
......
OUTPUT_ARCH(arm)
ENTRY(_stext)
SECTIONS
......
这里的 ENTRY(_stext) 定义的程序入口点是 _stext。

nuttx/arch/arm/src/Makefile:
  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. ......  
......
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。
  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  
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:
  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. ......  
......
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 <stm32_clockconfig>
 80003d6:    f000 f967     bl    80006a8 <stm32_lowsetup>
 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:
  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. ......  
......
_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:
  1. ......  
  2.     .globl        __start  
  3. ......  
......
    .globl        __start
......
在汇编代码中声明了全局符号 __start,相当于声明了函数。

nuttx/arch/arm/src/stm32/stm32_start.c:
  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. ......  
......
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 函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值