当前位置:   article > 正文

Cortex-M3 启动代码(GCC)详解_cortex-m3的启动汇编代码

cortex-m3的启动汇编代码

本篇文章使用的芯片为 LPC1768, 对于内核为 Cortex-M3 的其他芯片, 也可参考, 不同之处在于外围器件的中断, 使用GCC编译器 GNU Arm Embedded Toolchain


基础语法
符号(Symbol)

形如下面以冒号结尾的符号被称为标签(label), 表示符号出现位置的地址

__StackLimit:
    .space	Stack_Size
    .size	__StackLimit, . - __StackLimit
  • 1
  • 2
  • 3

. 是一个特殊的符号, 表示当前位置的地址

符号的值通常为 32 bits, 全局符号可用于链接器和调试器

汇编指令(Directive)

所有的汇编指令均以 . 开头, 其余部分通常是小写字母


启动代码
建立栈

本节所用到的汇编指令

指令格式描述
.equ symbol, expression设置 symbol 的值为 expression
.global symbol使得 symbol 对链接器(ld) 可见
.space size , fill使用 fill 填充 size 字节的空间, 可以省略 fill(默认为 0)

栈用于函数调用过程中保存局部变量

    .section	".stack", "w"
    .align	3
#ifdef __STACK_SIZE
    .equ	Stack_Size, __STACK_SIZE
#else
    .equ	Stack_Size, 0x00000400
#endif
    .global	__StackTop
    .global	__StackLimit
__StackLimit:
    .space	Stack_Size
    .size	__StackLimit, . - __StackLimit
__StackTop:
    .size	__StackTop, . - __StackTop
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

建立堆

堆用于 malloc 函数动态分配内存

    .section	".heap", "w"
    .align	3
#ifdef __HEAP_SIZE
    .equ	Heap_Size, __HEAP_SIZE
#else
    .equ	Heap_Size, 0x00000C00
#endif
    .global	__HeapBase
    .global	__HeapLimit
__HeapBase:
    .if		Heap_Size
    .space	Heap_Size
    .endif
    .size	__HeapBase, . - __HeapBase
__HeapLimit:
	.size	__HeapLimit, . - __HeapLimit
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

中断向量表

在链接时, 中断向量表需要放在代码区的最前面

.long 指令用于分配 4 字节的内存, 并填充值

    .section	".interrupt_vector"
    .align	2
    .global	__interrupt_vector
    .type	__interrupt_vector, %object

__interrupt_vector:
    .long	__StackTop					/* Top of Stack                 */
    .long	Reset_Handler				/* Reset Handler                */
    .long	NMI_Handler                 /* NMI Handler                  */
    .long	HardFault_Handler           /* Hard Fault Handler           */
    .long	MemManage_Handler           /* MPU Fault Handler            */
    .long	BusFault_Handler            /* Bus Fault Handler            */
    .long	UsageFault_Handler          /* Usage Fault Handler          */
    .long	0                           /* Reserved                     */
    .long	0                           /* Reserved                     */
    .long	0                           /* Reserved                     */
    .long	0                           /* Reserved                     */
    .long	SVC_Handler                 /* SVCall Handler               */
    .long	DebugMon_Handler            /* Debug Monitor Handler        */
    .long	0                           /* Reserved                     */
    .long	PendSV_Handler              /* PendSV Handler               */
    .long	SysTick_Handler             /* SysTick Handler              */

	/* External Interrupts */
    .long	WDT_IRQHandler              /* 16: Watchdog Timer               */
    .long	TIMER0_IRQHandler           /* 17: Timer0                       */
    .long	TIMER1_IRQHandler           /* 18: Timer1                       */
    .long	TIMER2_IRQHandler           /* 19: Timer2                       */
    .long	TIMER3_IRQHandler           /* 20: Timer3                       */
    .long	UART0_IRQHandler            /* 21: UART0                        */
    .long	UART1_IRQHandler            /* 22: UART1                        */
    .long	UART2_IRQHandler            /* 23: UART2                        */
    .long	UART3_IRQHandler            /* 24: UART3                        */
    .long	PWM1_IRQHandler             /* 25: PWM1                         */
    .long	I2C0_IRQHandler             /* 26: I2C0                         */
    .long	I2C1_IRQHandler             /* 27: I2C1                         */
    .long	I2C2_IRQHandler             /* 28: I2C2                         */
    .long	SPI_IRQHandler              /* 29: SPI                          */
    .long	SSP0_IRQHandler             /* 30: SSP0                         */
    .long	SSP1_IRQHandler             /* 31: SSP1                         */
    .long	PLL0_IRQHandler             /* 32: PLL0 Lock (Main PLL)         */
    .long	RTC_IRQHandler              /* 33: Real Time Clock              */
    .long	EINT0_IRQHandler            /* 34: External Interrupt 0         */
    .long	EINT1_IRQHandler            /* 35: External Interrupt 1         */
    .long	EINT2_IRQHandler            /* 36: External Interrupt 2         */
    .long	EINT3_IRQHandler            /* 37: External Interrupt 3         */
    .long	ADC_IRQHandler              /* 38: A/D Converter                */
    .long	BOD_IRQHandler              /* 39: Brown-Out Detect             */
    .long	USB_IRQHandler              /* 40: USB                          */
    .long	CAN_IRQHandler              /* 41: CAN                          */
    .long	DMA_IRQHandler              /* 42: General Purpose DMA          */
    .long	I2S_IRQHandler              /* 43: I2S                          */
    .long	ENET_IRQHandler             /* 44: Ethernet                     */
    .long	RIT_IRQHandler              /* 45: Repetitive Interrupt Timer   */
    .long	MCPWM_IRQHandler            /* 46: Motor Control PWM            */
    .long	QEI_IRQHandler              /* 47: Quadrature Encoder Interface */
    .long	PLL1_IRQHandler             /* 48: PLL1 Lock (USB PLL)          */

    .size	__interrupt_vector, . - __interrupt_vector
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

所有以 _IRQHandler 结尾的符号在下面的代码中被定义, 表示中断函数的起始地址


.macro 是汇编指令中的宏定义

    .macro	IRQ	handler
    .align	1
    .thumb_func
    .weak	\handler
    .type	\handler, %function
\handler:
	b	.
	.size	\handler, . - \handler
    .endm

    IRQ     NMI_Handler
    IRQ     HardFault_Handler
    IRQ     MemManage_Handler
    IRQ     BusFault_Handler
    IRQ     UsageFault_Handler
    IRQ     SVC_Handler
    IRQ     DebugMon_Handler
    IRQ     PendSV_Handler
    IRQ     SysTick_Handler

    IRQ     WDT_IRQHandler
    IRQ     TIMER0_IRQHandler
    IRQ     TIMER1_IRQHandler
    IRQ     TIMER2_IRQHandler
    IRQ     TIMER3_IRQHandler
    IRQ     UART0_IRQHandler
    IRQ     UART1_IRQHandler
    IRQ     UART2_IRQHandler
    IRQ     UART3_IRQHandler
    IRQ     PWM1_IRQHandler
    IRQ     I2C0_IRQHandler
    IRQ     I2C1_IRQHandler
    IRQ     I2C2_IRQHandler
    IRQ     SPI_IRQHandler
    IRQ     SSP0_IRQHandler
    IRQ     SSP1_IRQHandler
    IRQ     PLL0_IRQHandler
    IRQ     RTC_IRQHandler
    IRQ     EINT0_IRQHandler
    IRQ     EINT1_IRQHandler
    IRQ     EINT2_IRQHandler
    IRQ     EINT3_IRQHandler
    IRQ     ADC_IRQHandler
    IRQ     BOD_IRQHandler
    IRQ     USB_IRQHandler
    IRQ     CAN_IRQHandler
    IRQ     DMA_IRQHandler
    IRQ     I2S_IRQHandler
    IRQ     ENET_IRQHandler
    IRQ     RIT_IRQHandler
    IRQ     MCPWM_IRQHandler
    IRQ     QEI_IRQHandler
    IRQ     PLL1_IRQHandler
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

这里仅仅是定义了一系列默认的中断函数, 由于使用了 .weak 声明, 可以在 C 代码中定义相同的函数进行覆盖

默认的中断函数被实现为 b ., 即死循环


系统复位

芯片上电后首先执行系统复位(Reset_Handler)

系统复位需要处理全局变量的值, 对于有初始值的全局变量, 需要从 Flash 拷贝初始值到 RAM, 对于没有初始值的全局变量, 需要把值清零

	.text
    .thumb
	.thumb_func
    .align	2
    .global	Reset_Handler
    .type	Reset_Handler, %function
Reset_Handler:
	ldr		r1, = __etext
	ldr		r2, = __data_start__
	ldr		r3, = __data_end__

FLASH2RAM:
	cmp		r2, r3
	ittt	lt
	ldrlt	r0, [r1], #4
	strlt	r0, [r2], #4
	blt		FLASH2RAM


 	ldr		r1, = __bss_start__
	ldr		r2, = __bss_end__

	movs	r0, 0
CLEAR_BSS:
	cmp		r1, r2
	itt		lt
	strlt	r0, [r1], #4
	blt		CLEAR_BSS

	bl		SystemInit
	bl		_start

    .pool
    .size	Reset_Handler, . - Reset_Handler
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

__etext, __data_start__, __data_end__ 等符号是在链接脚本中定义的, 因为代码段和数据段的地址是在链接阶段才确定下来

_start 是标准库中的符号, 它会调用 main 函数, 当然也可以像下面这样, 跳过 _start 直接调用 main 函数

	bl		SystemInit
	bl		main

    .pool
    .size	Reset_Handler, . - Reset_Handler
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号