Chinaunix首页 | 论坛 | 博客
  • 博客访问: 178103
  • 博文数量: 20
  • 博客积分: 125
  • 博客等级: 入伍新兵
  • 技术积分: 985
  • 用 户 组: 普通用户
  • 注册时间: 2011-11-08 13:48
个人简介

热爱开源,喜欢分析操作系统架构

文章分类

全部博文(20)

文章存档

2013年(17)

2012年(3)

分类: 嵌入式

2013-04-19 16:43:35

本人看代码,无论多长,都习惯从最开始看起。一般的裸奔的程序,从main函数看起也就够了。可惜MQX是一个复杂的系统,源码都有几十兆,如果从main开始看的话就会忽略一些关键的步骤,因此我从代码最初运行的部分开始说起。

代码之始(请原谅我糟糕的命名品味)在哪呢,这个要问链接器了。本人的编译IDE用的是Keil,在工程选项linker里我们可以找到这个东西。 


Scatter File是链接器用来链接的编译好的文件的,简单的来说假设我们一个工程包含了一大堆*.c文件,每个*.c文件都会被编译器编译为*.o文件,之后链接器将这些文件链接组成一个可执行文件.elf。而scatter文件就是用来告诉链接器是如何把那些*.o文件按照一定的顺序组装起来的。当然我这也是简单说说,详细内容可参见 ARM? Compiler toolchain Version 4.1 Using the Linker
打开intflash.scf,就看见如下内容

点击(此处)折叠或打开

  1. #! armcc -E

  2. ; The balance of unused flash is used as user flash. Make sure this value
  3. ; matches the one in bsp/twrk60n512/twrk60n512.h. Change them as
  4. ; needed to match the flash image size. MAKE SURE THIS VALUE IS ALIGNED TO
  5. ; (is a multiple of) THE SECTOR SIZE - 0x800
  6. #define USERFLASH_BASE_ADDR 0x00060000
  7. #define INTFLASH_BASE_ADDR 0x00000000
  8. #define INTFLASH_SIZE (USERFLASH_BASE_ADDR - INTFLASH_BASE_ADDR)

  9. #define MY_ALIGN(address, alignment) ((address + (alignment-1)) AND ~(alignment-1))

  10. LOAD_REGION_INTFLASH INTFLASH_BASE_ADDR INTFLASH_SIZE
  11. {
  12.     VECTORS INTFLASH_BASE_ADDR
  13.     {
  14.         vectors.o (.vectors_rom,+FIRST)
  15.         vectors.o (.cfmconfig)
  16.     }

  17.     CODE +0
  18.     {
  19.         * (InRoot$$Sections) ; All library sections for example, __main.o,
  20.                                   ; __scatter*.o, __dc*.o, and * Region$$Table
  21.         * (KERNEL)
  22.         * (TEXT)
  23.         * (+RO)
  24.     }

  25.     RAM_VECTORS 0x1FFF0000 ; For ram vector table. Used when MQX_ROM_VECTORS is set to zero.
  26.     {
  27.         vectors.o (.vectors_ram)
  28.     }
  29.     
  30.     NOUSER +0
  31.     {
  32.         * (.nouser)
  33.     }

  34.     ROUSER MY_ALIGN(ImageLimit(NOUSER), 32)
  35.     {
  36.         * (.rouser)
  37.     }

  38.     RWUSER MY_ALIGN(ImageLimit(ROUSER), 32)
  39.     {
  40.         * (.rwuser)
  41.     }

  42.     DATA MY_ALIGN(ImageLimit(RWUSER), 32)
  43.     {
  44.         * (+RW)
  45.         * (+ZI)
  46.     }

  47.     USB_BDT MY_ALIGN(ImageLimit(DATA), 512)
  48.     {
  49.         * (.usb_bdt)
  50.     }

  51.     KERNEL_DATA_START MY_ALIGN(ImageLimit(USB_BDT), 0x10)
  52.     {
  53.         * (KERNEL_DATA_START) ; start of kernel data
  54.     }

  55.     KERNEL_DATA_END 0x2000FFF0 ; RAM_END
  56.     {
  57.         * (KERNEL_DATA_END) ; end of kernel data
  58.     }

  59.     ; mem_init writes a storeblock_struct at the end of kernel data,
  60.     ; max size 32 bytes, so use 0x100 offset
  61.     BOOT_STACK_ADDR 0x2000FEF0
  62.     {
  63.         * (BOOT_STACK)
  64.     }
  65. }
对于这个脚本,研究过linux编译的同学应该很熟悉了。最开始的0地址就是INTFLASH_BASE_ADDR,对应着VECTORS段。这个段由两个部分组成,这两个东西都是来自于vectors.c,一个叫vectors_rom,另一个叫cfmconfig。再来看vectors.c,不管cfmconfig,我们来研究最开始的vectors_rom。

点击(此处)折叠或打开

  1. #ifdef __ICCARM__
  2.     #pragma language = extended
  3.     #pragma segment = "CSTACK"

  4.     #pragma location = ".intvec"
  5.     #pragma segment = ".intvec"
  6.     const intvec_elem __vector_table[] =
  7. #elif defined(__CC_ARM) || defined(__GNUC__)
  8.     __attribute__((section(".vectors_rom"))) const vector_entry __vector_table[256] __attribute__((used)) =
  9. #else /* CodeWarrior compiler assumed */
  10.     #pragma define_section vectors_rom ".vectors_rom" ".vectors_rom" ".vectors_rom" far_abs R
  11.     __declspec(vectors_rom) vector_entry rom_vector[] =
  12. #endif /* CodeWarrior compiler assumed */
  13. {
  14.     (vector_entry)__BOOT_STACK_ADDRESS,
  15.     BOOT_START, /* 0x01 0x00000004 - ivINT_Initial_Program_Counter */
  16.     DEFAULT_VECTOR, /* 0x02 0x00000008 - ivINT_NMI */
  17.     DEFAULT_VECTOR, /* 0x03 0x0000000C - ivINT_Hard_Fault */
  18.     DEFAULT_VECTOR, /* 0x04 0x00000010 - ivINT_Mem_Manage_Fault */
  19.     DEFAULT_VECTOR, /* 0x05 0x00000014 - ivINT_Bus_Fault */
  20.     DEFAULT_VECTOR, /* 0x06 0x00000018 - ivINT_Usage_Fault */
  21.     0, /* 0x07 0x0000001C - ivINT_Reserved7 */
  22.     0, /* 0x08 0x00000020 - ivINT_Reserved8 */
  23.     0, /* 0x09 0x00000024 - ivINT_Reserved9 */
  24.     0, /* 0x0A 0x00000028 - ivINT_Reserved10 */
  25.     _svc_handler, /* 0x0B 0x0000002C - ivINT_SVCall */
  26.     DEFAULT_VECTOR, /* 0x0C 0x00000030 - ivINT_DebugMonitor */
  27.     0, /* 0x0D 0x00000034 - ivINT_Reserved13 */
  28.     _pend_svc, /* 0x0E 0x00000038 - ivINT_PendableSrvReq */
  29.     DEFAULT_VECTOR, /* 0x0F 0x0000003C - ivINT_SysTick */
  30.     /* Cortex external interrupt vectors */
  31.     DEFAULT_VECTOR, /* 0x10 0x00000040 - ivINT_DMA0 */

注意 __attribute__((section(".vectors_rom"))) const vector_entry __vector_table[256] __attribute__((used)) ,其实vectors_rom就是一个包含256个中断向量的中断向量表__vector_table[256],这个表是被链接器放在CPU总线地址为0-1024的内部flash上面。根据cortex m4的特性,cpu复位时,会从0x0处取出堆栈指针SP,从0x4处取出复位跳转指令的位置。我们可以发现__vector_table[0]是__BOOT_STACK_ADDRESS而__vector_table[1]是BOOT_START。如果有人记忆力好的话会发现__BOOT_STACK_ADDRESS在之前的scatter文件出现过,如果没注意的话可以回过头来看(之后你会对这个动作习以为常的),BOOT_STACK_ADDR就是最后一个段,其值为0x2000FEF0,这个就是cpu复位运行时堆栈的地址。而BOOT_START在vectors.c有一个宏定义

#define BOOT_START __boot

而这个__boot就是boot.S最开始的部分。


点击(此处)折叠或打开

  1. ASM_COMP_SPECIFIC_DIRECTIVES

  2.  ASM_CODE_SECTION(.text)
  3.  SET_FUNCTION_ALIGNMENT

  4.  ASM_PUBLIC(__boot)
  5.  ASM_PUBLIC(__set_MSP)

  6.  ASM_PUBLIC_BEGIN(__boot)
  7.  ASM_PUBLIC_FUNC(__boot)
  8. ASM_LABEL(__boot)


  9. #if MQX_AUX_CORE
  10.         msr MSP, r0
  11.         isb #15
  12. #endif

  13.         /* disable interrupts and clear pending flags */
  14.         ldr r0, =0xe000e180 /* NVIC_ICER0 - Interrupt Clear-Enable Registers */
  15.         ldr r1, =0xe000e280 /* NVIC_ICPR0 - Interrupt Clear-Pending Registers */
  16.         ldr r2, =0xffffffff
  17.         mov r3, #8

就这样我们说了半天才找到程序开始运行的地方,目前真正的主角MQX还没有运行,可以说MQX是一个浩大的工程,内容之多会让人生畏,不过它的确值得我们花时间去研究。在此我想说一下,要想研究一个拥有如此庞大代码量的系统,一个好的编辑工具是必须的。本人用的是vim,具体好处就不说了,本文说提到的各种变量的关系都是我用其中的vimgrep命令搜出来的,幸好有这个工具,不然我根本不可能在在这几十兆的代码中找出互相对应的文件。此外我也推荐使用source insight,也是文本编辑的一大神器。

最后看一下keil的运行界面,来证实我们上述的分析。


阅读(5084) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~