Cortex-M3 启动代码(GCC)详解

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


基础语法
符号(Symbol)

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

__StackLimit:
    .space	Stack_Size
    .size	__StackLimit, . - __StackLimit

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

符号的值通常为 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

建立堆

堆用于 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

中断向量表

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

.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

所有以 _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

这里仅仅是定义了一系列默认的中断函数, 由于使用了 .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

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

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

	bl		SystemInit
	bl		main

    .pool
    .size	Reset_Handler, . - Reset_Handler
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值