当前位置:   article > 正文

CM0+启动文件及ld文件分析_dma0_channel3_irqhandler

dma0_channel3_irqhandler

一、.S文件的作用

启动文件.s文件的作用:
设置堆栈指针SP
程序计数器指针PC 指向 Reset_Handler
设置中断向量表的对应中断地址

配置时钟系统(之前还以为GPIO不需要时钟,原来是在启动文件就已经有了默认时钟)
设置程序入口函数为main
个人理解:在进入main函数前所进行的操作,主要是初始化SP与PC指针,以及中断向量表。之前刚接触bootloader以为这一块也需要自己去写。

二、.S文件代码解析

(当然汇编语言注释可不是//,而是;)

第一段代码:

  1. .syntax unified // 意思是下面的指令是ARM和THUMB通用格式的
  2. .cpu cortex-m0plus//CPU内核型号
  3. .fpu softvfp//选择使用的浮点单元,与-mfpu命令行选项的相同
  4. .thumb// 选择使用thumb指令

第二段

  1. //global使得可以如下函数被其他目标文件使用
  2. .global g_pfnVectors //在文件末尾定义的中断向量
  3. .global Default_Handler//是一个死循环,用来处理异常情况
  4. .global __Vectors

第三段

  1. //指示data bss段的起始位置,赋值在ld script文件中
  2. .word _sidata//初始值地址 放置一个标识data段在RAM中开始地址的word型内存位置
  3. //.data对应初始化了的全局变量,编译后将位于可执行文件中,由启动代码负责加载到数据区中(在单片机中这部分数据会存于flash中,
  4. //需要由启动代码把这部分内容拷贝到ram中
  5. .word _sdata//.data开始地址
  6. .word _edata//.data块的结束地址
  7. //.bss块的起始地址,.bss段是没有初始值的全局变量,由启动代码把这 部分内容全初始化为0
  8. .word _sbss
  9. .word _ebss//.bss块的结束地址

第四段,定义Reset_Handler函数

这是处理器在重置事件后首次开始执行时调用的代码。只执行绝对必要的设置,然后调用应用程序提供的main()例程。

  1. /*This is the code that gets called when the processor first starts execution following a reset event. Only the absolutely necessary set is performed, after which the application supplied main() routine is called.*/
  2. //定义Reset_Handler函数,该函数的作用1.设置堆栈指针;2.全局变量的初始化
  3. //这个text.Reset_Handler很有迷惑性,它就是一个段名,在ld script中有 *(.text*)
  4. .section .text.Reset_Handler//定义了一个代码段,名字叫 .Reset_Handler
  5. .weak Reset_Handler//弱定义一个符号,名字叫 Reset_Handler
  6. //声明 Reset_Handler是一个函数类型 (同时表示段以 Reset_Handler符号位开始)
  7. .type Reset_Handler, %function
  8. Reset_Handler: //标记 Reset_Handler符号位置
  9. /* Copy the data segment initializers from flash to SRAM */
  10. // ldr sp, =_estack /* set stack pointer */ /*设置栈指针*/
  11. //将data段从rom中拷贝到RAM中
  12. movs r1, #0//将r1初始化为0
  13. b LoopCopyDataInit
  14. CopyDataInit:
  15. ldr r3, =_sidata//使用ldr伪指令将初始数据地址加载到r3中
  16. ldr r3, [r3, r1]//寄存器间接寻址,将r3 + r1地址中的数据加载到r3中
  17. str r3, [r0, r1]//将r3的内容写入 r0 + r1地址中
  18. adds r1, r1, #4//后变址,将r1地址中的内容写入r1,然后令r1 + 4
  19. LoopCopyDataInit:
  20. ldr r0, =_sdata//使用ldr伪指令,在r0中写入.data的起始地址
  21. ldr r3, =_edata//在r3中写入.data的末尾地址
  22. adds r2, r0, r1//r2 = r0 + r1 ,操作影响条件标志位
  23. cmp r2, r3//比较r2和r3寄存器中的地址大小
  24. bcc CopyDataInit//如果r2 < r3,也就是还没有到达data数据段的末尾,则转跳CopyDataInit
  25. // 因为汇编语言顺序执行,上面代码会循环执行,直到复制到.data数据段结束
  26. ldr r2, =_sbss// r2中存储.bss数据区的首地址
  27. b LoopFillZerobss
  28. /* Zero fill the bss segment. */
  29. //将bss段RAM清零
  30. FillZerobss:
  31. movs r3, #0//将寄存器r3写0
  32. str r3, [r2]
  33. movs r3, #4
  34. add r2, r2, r3
  35. LoopFillZerobss:
  36. ldr r3, = _ebss
  37. cmp r2, r3
  38. bcc FillZerobss
  39. /* Call the clock system intitialization function.*/
  40. //进入用户程序准备阶段
  41. bl SystemInit
  42. ldr R0, =0x20080014
  43. ldr R1, =0xFFFF
  44. strh R1, [R0]
  45. ldr R0, =0x20080044
  46. ldr R1, =0xFFFF
  47. strh R1, [R0]
  48. ldr R0, =0x20080074
  49. ldr R1, =0x3FF
  50. strh R1, [R0]
  51. /* Call static constructors */
  52. /* bl __libc_init_array */
  53. /* Call the application's entry point.'*/
  54. bl main//转跳main函数执行
  55. bx lr
  56. //计算.Reset_Handler段的长度,同时表示.Reset_Handler段结束
  57. .size Reset_Handler, .-Reset_Handler

第五段:

  1. /**
  2. * @brief This is the code that gets called when the processor receives an
  3. * unexpected interrupt. This simply enters an infinite loop, preserving
  4. * the system state for examination by a debugger.
  5. * @param None
  6. * @retval None
  7. */
  8. //定义了一个代码段,名字叫.Default_Handler,该段a可分配,x可执行,段内包含数据
  9. .section .text.Default_Handler,"ax",%progbits
  10. Default_Handler://标记 Default_Handler符号位置
  11. Infinite_Loop:
  12. b Infinite_Loop
  13. //标记 Default_Handler符号位置
  14. .size Default_Handler, .-Default_Handler

第6段:

  1. /******************************************************************************
  2. *
  3. * The minimal vector table for a Cortex M3. Note that the proper constructs
  4. * must be placed on this to ensure that it ends up at physical address
  5. * 0x0000.0000.
  6. *
  7. *******************************************************************************/
  8. //定义了一个段,名字叫.isr_vector,该段a可分配,段内包含数据
  9. .section .isr_vector,"a",%progbits
  10. //声明 g_pfnVectors是一个数据对象 ,同时表示段以 g_pfnVectors符号位开始
  11. .type g_pfnVectors, %object
  12. //计算.isr_vector,同时表示.isr_vector段结束
  13. .size g_pfnVectors, .-g_pfnVectors
  14. g_pfnVectors://标记 g_pfnVectors符号位置
  15. //当前位置放置一个word型的值,这个值为_estack;已下同理
  16. .word _estack//ld script赋值,RAM的结尾地址
  17. .word Reset_Handler
  18. .word NMI_Handler
  19. .word HardFault_Handler
  20. .word 0
  21. .word 0
  22. .word 0
  23. .word 0
  24. .word 0
  25. .word 0
  26. .word 0
  27. .word SVC_Handler
  28. .word 0
  29. .word 0
  30. .word PendSV_Handler
  31. .word SysTick_Handler
  32. /* External interrupts */
  33. .word PWDT0_IRQHandler
  34. .word PWDT1_IRQHandler
  35. .word PWM0_IRQHandler
  36. .word PWM1_IRQHandler
  37. .word ACMP0_IRQHandler
  38. .word UART0_IRQHandler
  39. .word UART1_IRQHandler
  40. .word UART2_IRQHandler
  41. .word WDG_IRQHandler
  42. .word SPI0_IRQHandler
  43. .word SPI1_IRQHandler
  44. .word I2C0_IRQHandler
  45. .word I2C1_IRQHandler
  46. .word DMA0_Channel0_IRQHandler
  47. .word DMA0_Channel1_IRQHandler
  48. .word DMA0_Channel2_IRQHandler
  49. .word DMA0_Channel3_IRQHandler
  50. .word TIMER_Channel0_IRQHandler
  51. .word TIMER_Channel1_IRQHandler
  52. .word TIMER_Channel2_IRQHandler
  53. .word TIMER_Channel3_IRQHandler
  54. .word RTC_IRQHandler
  55. .word PVD_IRQHandler
  56. .word SPM_IRQHandler
  57. .word CAN0_Handler
  58. .word ADC0_IRQHandler
  59. .word ECC_SRAM_IRQHandler
  60. .word EXTI0_IRQHandler
  61. .word EXTI1_IRQHandler
  62. .word EXTI2_IRQHandler
  63. .word EXTI3_8_IRQHandler
  64. .word EXTI9_15_IRQHandler
  65. __Vectors_End = .
  66. __Vectors = g_pfnVectors

第7段

  1. /*******************************************************************************
  2. *
  3. * Provide weak aliases for each Exception handler to the Default_Handler.
  4. * As they are weak aliases, any function with the same name will override
  5. * this definition.
  6. *
  7. *******************************************************************************/
  8. //弱定义一个符号,名字叫 NMI_Handler
  9. //如果没有重写这个弱定义的符号,则执行 Default_Handler,反之则执行重写的NMI_Handler,已下同理
  10. .weak NMI_Handler
  11. .thumb_set NMI_Handler,Default_Handler
  12. .weak HardFault_Handler
  13. .thumb_set HardFault_Handler,Default_Handler
  14. .weak SVC_Handler
  15. .thumb_set SVC_Handler,Default_Handler
  16. .weak PendSV_Handler
  17. .thumb_set PendSV_Handler,Default_Handler
  18. .weak SysTick_Handler
  19. .thumb_set SysTick_Handler,Default_Handler
  20. .weak PWDT0_IRQHandler
  21. .thumb_set PWDT0_IRQHandler,Default_Handler
  22. .weak PWDT1_IRQHandler
  23. .thumb_set PWDT1_IRQHandler,Default_Handler
  24. .weak PWM0_IRQHandler
  25. .thumb_set PWM0_IRQHandler,Default_Handler
  26. .weak PWM1_IRQHandler
  27. .thumb_set PWM1_IRQHandler,Default_Handler
  28. .weak ACMP0_IRQHandler
  29. .thumb_set ACMP0_IRQHandler,Default_Handler
  30. .weak UART0_IRQHandler
  31. .thumb_set UART0_IRQHandler,Default_Handler
  32. .weak UART1_IRQHandler
  33. .thumb_set UART1_IRQHandler,Default_Handler
  34. .weak UART2_IRQHandler
  35. .thumb_set UART2_IRQHandler,Default_Handler
  36. .weak WDG_IRQHandler
  37. .thumb_set WDG_IRQHandler,Default_Handler
  38. .weak SPI0_IRQHandler
  39. .thumb_set SPI0_IRQHandler,Default_Handler
  40. .weak SPI1_IRQHandler
  41. .thumb_set SPI1_IRQHandler,Default_Handler
  42. .weak I2C0_IRQHandler
  43. .thumb_set I2C0_IRQHandler,Default_Handler
  44. .weak I2C1_IRQHandler
  45. .thumb_set I2C1_IRQHandler,Default_Handler
  46. .weak DMA0_Channel0_IRQHandler
  47. .thumb_set DMA0_Channel0_IRQHandler,Default_Handler
  48. .weak DMA0_Channel1_IRQHandler
  49. .thumb_set DMA0_Channel1_IRQHandler,Default_Handler
  50. .weak DMA0_Channel2_IRQHandler
  51. .thumb_set DMA0_Channel2_IRQHandler,Default_Handler
  52. .weak DMA0_Channel3_IRQHandler
  53. .thumb_set DMA0_Channel3_IRQHandler,Default_Handler
  54. .weak TIMER_Channel0_IRQHandler
  55. .thumb_set TIMER_Channel0_IRQHandler,Default_Handler
  56. .weak TIMER_Channel1_IRQHandler
  57. .thumb_set TIMER_Channel1_IRQHandler,Default_Handler
  58. .weak TIMER_Channel2_IRQHandler
  59. .thumb_set TIMER_Channel2_IRQHandler,Default_Handler
  60. .weak TIMER_Channel3_IRQHandler
  61. .thumb_set TIMER_Channel3_IRQHandler,Default_Handler
  62. .weak RTC_IRQHandler
  63. .thumb_set RTC_IRQHandler,Default_Handler
  64. .weak PVD_IRQHandler
  65. .thumb_set PVD_IRQHandler,Default_Handler
  66. .weak SPM_IRQHandler
  67. .thumb_set SPM_IRQHandler,Default_Handler
  68. .weak CAN0_Handler
  69. .thumb_set CAN0_Handler,Default_Handler
  70. .weak ADC0_IRQHandler
  71. .thumb_set ADC0_IRQHandler,Default_Handler
  72. .weak ECC_SRAM_IRQHandler
  73. .thumb_set ECC_SRAM_IRQHandler,Default_Handler
  74. .weak EXTI0_IRQHandler
  75. .thumb_set EXTI0_IRQHandler,Default_Handler
  76. .weak EXTI1_IRQHandler
  77. .thumb_set EXTI1_IRQHandler,Default_Handler
  78. .weak EXTI2_IRQHandler
  79. .thumb_set EXTI2_IRQHandler,Default_Handler
  80. .weak EXTI3_8_IRQHandler
  81. .thumb_set EXTI3_8_IRQHandler,Default_Handler
  82. .weak EXTI9_15_IRQHandler
  83. .thumb_set EXTI9_15_IRQHandler,Default_Handler

参考资料:gcc编译环境下stm32H750 startup.S汇编文件注解_yoyotansa的博客-CSDN博客_stratup.s .thumb .thumb_func .syntax unifiedhttps://blog.csdn.net/oDongQing/article/details/104188494

第十六章:STM32处理器启动代码的理解_qq_33553024的博客-CSDN博客_g_pfnvectors

三、ld文件作用

1.定义程序入口地址
2.定义Flash、RAM中代码和数据的存放位置

四、ld文件代码解释

  1. /* Entry Point */
  2. /* 程序入口——程序将从Reset Handler开始执行,而该函数定义在stm32fxxx.s启动文件中。
  3. ENTRY(Reset_Handler)
  4. /* Highest address of the user mode stack */
  5. /* end of stack 堆栈末尾 = RAM起始地址 + RAM空间大小 */
  6. _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
  7. /* 程序所必须的堆、栈空间大小定义 */
  8. _Min_Heap_Size = 0x200 ; /* required amount of heap */
  9. _Min_Stack_Size = 0x400 ; /* required amount of stack */
  10. /* Memories definition */
  11. /* 单片机内部存储空间 RAM FLASH起始位置和大小的声明 */
  12. MEMORY
  13. {
  14. RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K
  15. FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
  16. }
  17. /* Sections */
  18. SECTIONS
  19. {
  20. /* The startup code into "FLASH" Rom type memory */
  21. /* 中断向量表定义于 .s启动文件中,应位于Flash的最前端,也就是从0x8000000的位置开始 */
  22. .isr_vector :
  23. {
  24. /* 字对齐 */
  25. . = ALIGN(4);
  26. /* 将中断向量的内容链接到该地址 */
  27. KEEP(*(.isr_vector)) /* Startup code */
  28. . = ALIGN(4);
  29. } >FLASH
  30. /* The program code and other data into "FLASH" Rom type memory */
  31. /* .text对应程序的可执行代码 */
  32. .text :
  33. {
  34. /* 字对齐 */
  35. . = ALIGN(4);
  36. *(.text) /* .text sections (code) */
  37. *(.text*) /* .text* sections (code) */
  38. *(.glue_7) /* glue arm to thumb code */
  39. *(.glue_7t) /* glue thumb to arm code */
  40. *(.eh_frame)
  41. /* KEEP() 的作用是当启用连接器的--gc-sections垃圾回收选项时,这部分不能被回收
  42. 参考链接 https://blog.csdn.net/wangbinyantai/article/details/79001303 */
  43. KEEP (*(.init))
  44. KEEP (*(.fini))
  45. . = ALIGN(4);
  46. /* _etext是链接器的预定义变量,代表程序正文段结束的第一个地址 */
  47. _etext = .; /* define a global symbols at end of code */
  48. } >FLASH
  49. /* Constant data into "FLASH" Rom type memory */
  50. /* .rodata代表程序中使用的常量表格数据等 */
  51. .rodata :
  52. {
  53. /* 前后字对齐 */
  54. . = ALIGN(4);
  55. *(.rodata) /* .rodata sections (constants, strings, etc.) */
  56. *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
  57. . = ALIGN(4);
  58. } >FLASH
  59. /* ?如果有朋友清楚下面这段定义的含义请评论告诉我,多谢!*/
  60. .ARM.extab : {
  61. . = ALIGN(4);
  62. *(.ARM.extab* .gnu.linkonce.armextab.*)
  63. . = ALIGN(4);
  64. } >FLASH
  65. .ARM : {
  66. . = ALIGN(4);
  67. __exidx_start = .;
  68. *(.ARM.exidx*)
  69. __exidx_end = .;
  70. . = ALIGN(4);
  71. } >FLASH
  72. /* .preinit_array和.init_array部分包含指向将在初始化时调用的函数的指针数组。
  73. 参考链接:https://stackoverflow.com/questions/40532180/understanding-the-linkerscript-for-an-arm-cortex-m-microcontroller */
  74. .preinit_array :
  75. {
  76. . = ALIGN(4);
  77. PROVIDE_HIDDEN (__preinit_array_start = .);
  78. KEEP (*(.preinit_array*))
  79. PROVIDE_HIDDEN (__preinit_array_end = .);
  80. . = ALIGN(4);
  81. } >FLASH
  82. .init_array :
  83. {
  84. . = ALIGN(4);
  85. PROVIDE_HIDDEN (__init_array_start = .);
  86. KEEP (*(SORT(.init_array.*)))
  87. KEEP (*(.init_array*))
  88. PROVIDE_HIDDEN (__init_array_end = .);
  89. . = ALIGN(4);
  90. } >FLASH
  91. .fini_array :
  92. {
  93. . = ALIGN(4);
  94. /* PROVIDE_HIDDEN 表示 :Similar to PROVIDE. For ELF targeted ports,
  95. the symbol will be hidden and won’t be exported.
  96. 表示符号在目标文件中被定义但不会被导出 */
  97. PROVIDE_HIDDEN (__fini_array_start = .);
  98. KEEP (*(SORT(.fini_array.*)))
  99. KEEP (*(.fini_array*))
  100. PROVIDE_HIDDEN (__fini_array_end = .);
  101. . = ALIGN(4);
  102. } >FLASH
  103. /* Used by the startup to initialize data */
  104. /* 以变量_sidata存储.data块的起始地址,.data对应初始化了的全局变量 */
  105. _sidata = LOADADDR(.data);
  106. /* Initialized data sections into "RAM" Ram type memory */
  107. /* .data对应初始化了的全局变量,编译后将位于可执行文件中,由启动代码负责加载到数据区中(在单片机中这部分数据会存于flash中,需要由启动代码把这部分内容拷贝到ram中)*/
  108. .data :
  109. {
  110. . = ALIGN(4);
  111. _sdata = .; /* create a global symbol at data start */
  112. *(.data) /* .data sections */
  113. *(.data*) /* .data* sections */
  114. . = ALIGN(4);
  115. /* edata的地址是初始化数据区后面的第1个地址 */
  116. _edata = .; /* define a global symbol at data end */
  117. } >RAM AT> FLASH
  118. /* Uninitialized data section into "RAM" Ram type memory */
  119. . = ALIGN(4);
  120. /* .bss段是没有初始值的全局变量,由启动代码把这部分内容全初始化为0 */
  121. .bss :
  122. {
  123. /* This is used by the startup in order to initialize the .bss section */
  124. _sbss = .; /* define a global symbol at bss start */
  125. __bss_start__ = _sbss;
  126. *(.bss)
  127. *(.bss*)
  128. /* COMMON数据段仅在.o文件中存在,当代码中的全局变量没有赋初值时存储在该数据段中 */
  129. https://stackoverflow.com/questions/16835716/bss-vs-common-what-goes-where */
  130. *(COMMON)
  131. . = ALIGN(4);
  132. _ebss = .; /* define a global symbol at bss end */
  133. __bss_end__ = _ebss;
  134. } >RAM
  135. /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */
  136. ._user_heap_stack :
  137. {
  138. . = ALIGN(8);
  139. /* 同PROVIDE_HIDDEN的作用类似,定义内部变量而不导出 */
  140. PROVIDE ( end = . );
  141. PROVIDE ( _end = . );
  142. . = . + _Min_Heap_Size;
  143. . = . + _Min_Stack_Size;
  144. . = ALIGN(8);
  145. } >RAM
  146. /* Remove information from the compiler libraries */
  147. /DISCARD/ :
  148. {
  149. libc.a ( * )
  150. libm.a ( * )
  151. libgcc.a ( * )
  152. }
  153. .ARM.attributes 0 : { *(.ARM.attributes) }
  154. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/319512
推荐阅读
相关标签
  

闽ICP备14008679号