原创 WINARM中的CRT0.S代码分析

2006-12-13 11:36 5130 7 5 分类: MCU/ 嵌入式
 

CRT0.S代码分析

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


                                                  jupiter 2006.08.20


        .global main                    // int main(void)


        .global _etext                  // -> .data initial values in ROM


        .global _data                   // -> .data area in RAM


        .global _edata                  // end of .data area


        .global __bss_start             // -> .bss area in RAM


        .global __bss_end__             // end of .bss area


        .global _stack                  // top of stack


.global symbol


GNU AS.global使ld能够看见这个符号。如果你在程序的某个部分中定义了symbol,那么在与它一起链接的其它程序中,这个符号也是可见的。


在这部分中定义了几个符号,其中包括main,这是我们所写的C程序的入口;_etext,即end of texttext段的末尾也就是data段的开始,从此处开始是.data段,.data段存放的是需要被初始化的数据,例如那些带有初始化值的全局变量;_data_edata指明了数据段的起始和结束位置;同理__bss_start__bss_end__指明了bss段的起始和结束位置;_stack指明了栈顶,对于ARM处理器来说,栈一般是满递减的,即full descending


/************


在这里我简单的介绍一下程序的装载与执行过程。程序一般可以分成textdatabss段,我们必须把程序放在非易失性存储器(NVM)中,试着想一下,如果你把程序放在RAM中,那么系统掉电之后,你还能运行你的程序吗?而每个段又有自己的装载地址和运行地址,装载地址和运行地址可能相同,也可能不同。但是对于data段来说,这两个地址肯定是不相同的,因为我们一般不能在程序运行的过程中修改NVM的内容,我们需要在程序的初始化代码中将data段的内容从它的装载地址拷贝到它的运行地址处(我们稍后就能看到这是如何做到的)。回到上面的问题,_etext就是data段在NVM中的起始地址,而_data就是data段运行时的起始地址。这里有一个常识,在可执行文件中,一般首先存放text段,紧接着是data段,最后才是bss段,当然对于bss段来说还有一个技巧以后再谈。


************/


//定义各个异常模式的堆栈大小


        .set  UND_STACK_SIZE, 0x00000004


        .set  ABT_STACK_SIZE, 0x00000004


        .set  FIQ_STACK_SIZE, 0x00000004


        .set  IRQ_STACK_SIZE, 0X00000080


        .set  SVC_STACK_SIZE, 0x00000004


//定义标准模式位和PSR中的中断(I & F)标志


.set  MODE_USR, 0x10            // User Mode


        .set  MODE_FIQ, 0x11            // FIQ Mode


        .set  MODE_IRQ, 0x12            // IRQ Mode


        .set  MODE_SVC, 0x13            // Supervisor Mode


        .set  MODE_ABT, 0x17            // Abort Mode


        .set  MODE_UND, 0x1B            // Undefined Mode


        .set  MODE_SYS, 0x<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />1F            // System Mode


.set symbol, expression


设置symbol的值为expression。这会改变symbol的值和类型以与expression保持一致。如果symbol具有external标志,那么此标志保持不变。可以在汇编语句中多次.set一个符号。如果你.set一个全局符号,那么保存在目标文件中的将是最后一次设置的值。


        .equ  I_BIT, 0x80               // when I bit is set, IRQ is disabled


        .equ  F_BIT, 0x40               // when F bit is set, FIQ is disabled


.equ symbol, expression


.equ的用法和作用与.set相同。


        .text


        .code 32


        .align 2


 


        .global _boot


        .func   _boot


_boot:


 


// Runtime Interrupt Vectors


// -------------------------


Vectors:


        b     _start                    // reset - _start


        ldr   pc,_undf                  // undefined - _undf


        ldr   pc,_swi                   // SWI - _swi


        ldr   pc,_pabt                  // program abort - _pabt


        ldr   pc,_dabt                  // data abort - _dabt


        nop                             // reserved


        ldr   pc,[pc,#-0xFF0]           // IRQ - read the VIC


        ldr   pc,_fiq                   // FIQ - _fiq


 


#if 0


// Use this group for production


_undf:  .word _reset                    // undefined - _reset


_swi:   .word _reset                    // SWI - _reset


_pabt:  .word _reset                    // program abort - _reset


_dabt:  .word _reset                    // data abort - _reset


_irq:   .word _reset                    // IRQ - _reset


_fiq:   .word _reset                    // FIQ - _reset


 


#else


// Use this group for development


_undf:  .word __undf                    // undefined


_swi:   .word __swi                     // SWI


_pabt:  .word __pabt                    // program abort


_dabt:  .word __dabt                    // data abort


_irq:   .word __irq                     // IRQ


_fiq:   .word __fiq                     // FIQ


 


__undf: b     .                         // undefined


__swi:  b     .                         // SWI


__pabt: b     .                         // program abort


__dabt: b     .                         // data abort


__irq:  b     .                         // IRQ


__fiq:  b     .                         // FIQ


#endif


        .size _boot, . - _boot


        .endfunc


这个部分定义了异常向量表。


.func name [,label]


.func为函数name添加调试信息,但是除非在汇编的时候使能调试信息否则这些信息被忽略。目前仅支持—gstabs选项。Label是函数的入口点,如果省略,那么必须给name添加一个前缀字符,这个字符通常是一个下划线(_)或者为空,这依赖于目标平台。目前所有的函数的返回类型都被定义为void。函数必须以.endfunc结束。


编译器生成.size这个命令符是为了在符号表中包含辅助调试信息。它仅在.def/.endef对中才是允许的。.size仅仅在生成COFF格式时才有意义;当as生成b.out时,虽然它可以接收这个命令符,但只是忽略它。(这里我们可以认为它不存在)


// Setup the operating mode & stack.


// ---------------------------------


        .global _start, start, _mainCRTStartup


        .func   _start


 


_start:


start:


_mainCRTStartup:


 


// Initialize Interrupt System


// - Set stack location for each mode


// - Leave in System Mode with Interrupts Disabled


// -----------------------------------------------


        ldr   r0,=_stack


        msr   CPSR_c,#MODE_UND|I_BIT|F_BIT // Undefined Instruction Mode


        mov   sp,r0


        sub   r0,r0,#UND_STACK_SIZE


        msr   CPSR_c,#MODE_ABT|I_BIT|F_BIT // Abort Mode


        mov   sp,r0


        sub   r0,r0,#ABT_STACK_SIZE


        msr   CPSR_c,#MODE_FIQ|I_BIT|F_BIT // FIQ Mode


        mov   sp,r0


        sub   r0,r0,#FIQ_STACK_SIZE


        msr   CPSR_c,#MODE_IRQ|I_BIT|F_BIT // IRQ Mode


        mov   sp,r0


        sub   r0,r0,#IRQ_STACK_SIZE


        msr   CPSR_c,#MODE_SVC|I_BIT|F_BIT // Supervisor Mode


        mov   sp,r0


        sub   r0,r0,#SVC_STACK_SIZE


        msr   CPSR_c,#MODE_SYS|I_BIT|F_BIT // System Mode


        mov   sp,r0


这一步主要是设置各个异常模式的堆栈,注意在设置的时候需要禁止IRQFIQ。这段代码也是系统复位后执行的第一段代码。执行完这段代码后系统处于系统模式,并且IRQFIQ都是禁止的。


// Copy initialized data to its execution address in RAM


// -----------------------------------------------------


#ifdef ROM_RUN


        ldr   r1,=_etext                // -> ROM data start


        ldr   r2,=_data                 // -> data start


        ldr   r3,=_edata                // -> end of data


1:      cmp   r2,r3                     // check if data to move


        ldrlo r0,[r1],#4                // copy it


        strlo r0,[r2],#4


        blo   1b                        // loop until done


#endif


// Clear .bss


// ----------


        mov   r0,#0                     // get a zero


        ldr   r1,=__bss_start           // -> bss start


        ldr   r2,=__bss_end__           // -> bss end


2:      cmp   r1,r2                     // check if data to clear


        strlo r0,[r1],#4                // clear 4 bytes


        blo   2b                        // loop until done


这两段代码主要完成data段的搬运和bss段的清零。


// Call main program: main(0)


// --------------------------


        mov   r0,#0                     // no arguments (argc = 0)


        mov   r1,r0


        mov   r2,r0


        mov   fp,r0                     // null frame pointer


        mov   r7,r0                     // null frame pointer for thumb


        ldr   r10,=main


        mov   lr,pc


        bx    r10                       // enter main()


 


        .size   _start, . - _start


        .endfunc


这段代码完成到C语言main函数的跳转。


        .global _reset, reset, exit, abort


        .func   _reset


_reset:


reset:


exit:


abort:


#if 0


// Disable interrupts, then force a hardware reset by driving P23 low


// -------------------------------------------------------------------


        mrs   r0,cpsr                   // get PSR


        orr   r0,r0,#I_BIT|F_BIT        // disable IRQ and FIQ


        msr   cpsr,r0                   // set up status register


 


        ldr   r1,=(PS_BASE)             // PS Base Address


        ldr   r0,=(PS_PIO)              // PIO Module


        str   r0,[r1,#PS_PCER_OFF]      // enable its clock


        ldr   r1,=(PIO_BASE)            // PIO Base Address


        ldr   r0,=(1<<23)               // P23


        str   r0,[r1,#PIO_PER_OFF]      // make sure pin is contolled by PIO


        str   r0,[r1,#PIO_CODR_OFF]     // set the pin low


        str   r0,[r1,#PIO_OER_OFF]      // make it an output


#endif


        b     .                         // loop until reset


 


        .size _reset, . - _reset


        .endfunc


 


        .end

文章评论0条评论)

登录后参与讨论
我要评论
0
7
关闭 站长推荐上一条 /2 下一条