返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[开发工具] 高效嵌入式开发:APM32的链接(.ld)与启动文件概述

[复制链接]
 楼主| DKENNY 发表于 2024-11-19 19:33 | 显示全部楼层 |阅读模式
<
本帖最后由 DKENNY 于 2024-11-19 19:32 编辑

#技术资源# #申请原创# @21小跑堂

前言
      在嵌入式系统开发中,APM32微控制器的应用日益广泛。为了确保程序高效运行,理解链接文件和启动文件的关系至关重要。链接文件(Linker Script)定义了程序的内存布局及各个段的起始地址和大小,而启动文件(Startup File)负责初始化系统环境,包括堆栈和全局变量的设置。这两者紧密配合,确保固件在微控制器上顺利执行。
      在APM32微控制器的开发中,链接文件和启动文件是固件编写的关键组成部分。它们相辅相成,确保程序从上电到运行的每个环节都能顺利进行。接下来,我们将详细分析这两个文件的内容及其相互关联。
bb539ef9743f914a6e075d1614f2245d

1. 链接文件分析
      链接文件的主要功能是定义程序的内存布局,包括程序代码、数据、堆栈和其他重要段的起始地址和大小。如下是 startup_apm32f40xxG.ld源码。
  1. /* Entry Point */
  2. ENTRY(Reset_Handler)

  3. /* Flash Configuration*/
  4. /* Flash Base Address */
  5. _rom_base = 0x8000000;
  6. /*Flash Size (in Bytes) */
  7. _rom_size = 0x0100000;

  8. /* Embedded RAM Configuration */
  9. /* RAM Base Address           */
  10. _ram_base = 0x20000000;
  11. /* RAM Size (in Bytes) */
  12. _ram_size = 0x00020000;

  13. /* CCMRAM Base Address    */
  14. _ccmram_base = 0x10000000;
  15. /* CCMRAM Size (in Bytes) */
  16. _ccmram_size = 0x00010000;

  17. /* Stack / Heap Configuration */
  18. _end_stack = 0x20020000;
  19. /* Heap Size (in Bytes) */
  20. _heap_size = 0x200;
  21. /* Stack Size (in Bytes) */
  22. _stack_size = 0x400;

  23. MEMORY
  24. {
  25. FLASH (rx)      : ORIGIN = _rom_base,    LENGTH = _rom_size
  26. RAM (xrw)       : ORIGIN = _ram_base,    LENGTH = _ram_size
  27. CCMRAM (xrw)    : ORIGIN = _ccmram_base, LENGTH = _ccmram_size
  28. }

  29. SECTIONS
  30. {
  31.   .apm32_isr_vector :
  32.   {
  33.     . = ALIGN(4);
  34.     KEEP(*(.apm32_isr_vector))
  35.     . = ALIGN(4);
  36.   } >FLASH

  37.   .text :
  38.   {
  39.     . = ALIGN(4);
  40.     *(.text)
  41.     *(.text*)
  42.     *(.glue_7)
  43.     *(.glue_7t)
  44.     *(.eh_frame)

  45.     KEEP (*(.init))
  46.     KEEP (*(.fini))

  47.     . = ALIGN(4);
  48.     _etext = .;
  49.   } >FLASH

  50.   .rodata :
  51.   {
  52.     . = ALIGN(4);
  53.     *(.rodata)
  54.     *(.rodata*)
  55.     . = ALIGN(4);
  56.   } >FLASH

  57.   .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  58.   .ARM : {
  59.     __exidx_start = .;
  60.     *(.ARM.exidx*)
  61.     __exidx_end = .;
  62.   } >FLASH

  63.   .preinit_array     :
  64.   {
  65.     PROVIDE_HIDDEN (__preinit_array_start = .);
  66.     KEEP (*(.preinit_array*))
  67.     PROVIDE_HIDDEN (__preinit_array_end = .);
  68.   } >FLASH
  69.   .init_array :
  70.   {
  71.     PROVIDE_HIDDEN (__init_array_start = .);
  72.     KEEP (*(SORT(.init_array.*)))
  73.     KEEP (*(.init_array*))
  74.     PROVIDE_HIDDEN (__init_array_end = .);
  75.   } >FLASH
  76.   .fini_array :
  77.   {
  78.     PROVIDE_HIDDEN (__fini_array_start = .);
  79.     KEEP (*(SORT(.fini_array.*)))
  80.     KEEP (*(.fini_array*))
  81.     PROVIDE_HIDDEN (__fini_array_end = .);
  82.   } >FLASH

  83.   _start_address_init_data = LOADADDR(.data);

  84.   .data :
  85.   {
  86.     . = ALIGN(4);
  87.     _start_address_data = .;
  88.     *(.data)
  89.     *(.data*)

  90.     . = ALIGN(4);
  91.     _end_address_data = .;
  92.   } >RAM AT> FLASH

  93.   _siccmram = LOADADDR(.ccmram);

  94.   .ccmram :
  95.   {
  96.     . = ALIGN(4);
  97.     _sccmram = .;
  98.     *(.ccmram)
  99.     *(.ccmram*)
  100.    
  101.     . = ALIGN(4);
  102.     _eccmram = .;
  103.   } >CCMRAM AT> FLASH
  104.   
  105.   . = ALIGN(4);
  106.   .bss :
  107.   {

  108.     _start_address_bss = .;
  109.     __bss_start__ = _start_address_bss;
  110.     *(.bss)
  111.     *(.bss*)
  112.     *(COMMON)

  113.     . = ALIGN(4);
  114.     _end_address_bss = .;
  115.     __bss_end__ = _end_address_bss;
  116.   } >RAM

  117.   ._user_heap_stack :
  118.   {
  119.     . = ALIGN(8);
  120.     PROVIDE ( end = . );
  121.     PROVIDE ( _end = . );
  122.     . = . + _heap_size;
  123.     . = . + _stack_size;
  124.     . = ALIGN(8);
  125.   } >RAM

  126.   /DISCARD/ :
  127.   {
  128.     libc.a ( * )
  129.     libm.a ( * )
  130.     libgcc.a ( * )
  131.   }

  132.   .ARM.attributes 0 : { *(.ARM.attributes) }
  133. }
     链接文件通过 MEMORY 指令定义了内存的使用情况,包括 FLASH、RAM 和 CCMRAM 的基本信息。例如:
  1. MEMORY
  2. {
  3.     FLASH (rx)      : ORIGIN = _rom_base,    LENGTH = _rom_size
  4.     RAM (xrw)       : ORIGIN = _ram_base,    LENGTH = _ram_size
  5.     CCMRAM (xrw)    : ORIGIN = _ccmram_base, LENGTH = _ccmram_size
  6. }
     这里定义了各内存区域的属性:
      - FLASH:
          - rx:表示该区域可读并可执行,适合存储程序代码。
          - ORIGIN:指定 FLASH 的起始地址(如 _rom_base)。
          - LENGTH:指定 FLASH 的大小(如 _rom_size)。
      - RAM:
          - xrw:表示该区域可读、可写并可执行,适合存储变量和数据。
          - ORIGIN:指定 RAM 的起始地址(如 _ram_base)。
          - LENGTH:指定 RAM 的大小(如 _ram_size)。
      - CCMRAM:
          - 同样具有 xrw 属性,表示可读、可写并可执行。
          - ORIGIN 和 LENGTH 属性分别指定 CCMRAM 的起始地址和大小。
      通过这些定义,程序在内存中能够找到合适的位置来存储数据和代码,从而确保系统的正常运行和高效访问。

1.2 段的定义
      接下来,链接文件通过 SECTIONS 指令定义了程序的各个段。这些段包括 .text、.data、.bss 等等,分别用于存储程序代码、已初始化的全局变量和未初始化的全局变量。例如:
  1. .text :
  2. {
  3.     . = ALIGN(4);
  4.     *(.text)
  5.     *(.text*)
  6.     *(.glue_7)
  7.     *(.glue_7t)
  8.     *(.eh_frame)

  9.     KEEP (*(.init))
  10.     KEEP (*(.fini))

  11.     . = ALIGN(4);
  12.     _etext = .;
  13. } > FLASH
     在这个段定义中:
      - .text 段:存储程序的所有可执行代码。
      - ALIGN(4):确保段的起始地址是4字节对齐,以满足处理器的对齐要求。
      - *(.text):将所有 .text 段的内容,包括各个翻译单元中的代码,合并到这个段中。
      - KEEP (*(.init)) 和 KEEP (*(.fini)):确保初始化和清理函数在链接时不会被丢弃。
      - _etext:用于标记 .text 段的结束地址,以便在程序中进行引用。

1.3 其他段的定义
      除了 .text 段,链接文件还定义了其他多个重要段,例如:
      .data 段:
  1. .data :
  2. {
  3.     . = ALIGN(4);
  4.     _start_address_data = .;
  5.     *(.data)
  6.     *(.data*)
  7.     . = ALIGN(4);
  8.     _end_address_data = .;
  9. } > RAM AT> FLASH
     存储已初始化的全局变量,程序运行时将这些数据从 Flash 复制到 RAM 中。
      使用 AT> FLASH 指定数据在 Flash 中的存储位置。
      .bss 段:
  1. .bss :
  2. {
  3.     _start_address_bss = .;
  4.     *(.bss)
  5.     *(.bss*)
  6.     *(COMMON)
  7.     . = ALIGN(4);
  8.     _end_address_bss = .;
  9. } > RAM
     存储未初始化的全局变量和静态变量,这些变量在程序启动时会被自动初始化为零。

      .rodata 段:
  1. .rodata :
  2. {
  3.     . = ALIGN(4);
  4.     *(.rodata)
  5.     *(.rodata*)
  6.     . = ALIGN(4);
  7. } > FLASH
     存储只读数据,通常是字符串常量和查找表。

      .ccmram 段:
  1. .ccmram :
  2. {
  3.     . = ALIGN(4);
  4.     _sccmram = .;
  5.     *(.ccmram)
  6.     *(.ccmram*)
  7.     . = ALIGN(4);
  8.     _eccmram = .;
  9. } > CCMRAM AT> FLASH
     存储需要快速访问的变量,配置在 CCMRAM 中以提高访问速度。

1.4 堆栈的配置
      链接文件还定义了堆和栈的大小和位置:
  1. ._user_heap_stack :
  2. {
  3.     . = ALIGN(8);
  4.     PROVIDE ( end = . );
  5.     PROVIDE ( _end = . );
  6.     . = . + _heap_size;
  7.     . = . + _stack_size;
  8.     . = ALIGN(8);
  9. } > RAM
     这部分定义了堆的起始位置,堆和栈的大小由 _heap_size 和 _stack_size 指定。PROVIDE 用于在其他部分引用堆和栈的结束地址。

1.5 丢弃不需要的部分
  1. /DISCARD/ :
  2. {
  3.     libc.a ( * )
  4.     libm.a ( * )
  5.     libgcc.a ( * )
  6. }
     这一部分用于指定在链接时丢弃不需要的库文件,减小最终生成的可执行文件的大小。

1.6 结论
      通过对链接文件的结构和各部分功能的分析,可以看出其在嵌入式系统中的重要性。链接文件通过对内存的合理配置和段的清晰定义,确保了程序在运行时的稳定性和效率。

2. 启动文件分析
  1. /*!
  2. * [url=home.php?mod=space&uid=288409]@file[/url]       startup_apm32f40x.S
  3. *
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]      APM32F40xxx Devices vector table for GCC based toolchains.
  5. *             This module performs:
  6. *                 - Set the initial SP
  7. *                 - Set the initial PC == Reset_Handler,
  8. *                 - Set the vector table entries with the exceptions ISR address
  9. *                 - Branches to main in the C library (which eventually
  10. *                 calls main()).
  11. *             After Reset the Cortex-M4 processor is in Thread mode,
  12. *             priority is Privileged, and the Stack is set to Main.
  13. *
  14. * [url=home.php?mod=space&uid=895143]@version[/url]     V1.0.0
  15. *
  16. * [url=home.php?mod=space&uid=212281]@date[/url]        2023-03-02
  17. *
  18. * @attention
  19. *
  20. *  Copyright (C) 2021-2023 Geehy Semiconductor
  21. *
  22. *  You may not use this file except in compliance with the
  23. *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
  24. *
  25. *  The program is only for reference, which is distributed in the hope
  26. *  that it will be useful and instructional for customers to develop
  27. *  their software. Unless required by applicable law or agreed to in
  28. *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
  29. *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
  30. *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
  31. *  and limitations under the License.
  32. */

  33.   .syntax unified
  34.   .cpu cortex-m4
  35.   .fpu softvfp
  36.   .thumb

  37. .global  g_apm32_Vectors
  38. .global  Default_Handler

  39. /* start address for the initialization values of the .data section.
  40. defined in linker script */
  41. .word  _start_address_init_data
  42. /* start address for the .data section. defined in linker script */
  43. .word  _start_address_data
  44. /* end address for the .data section. defined in linker script */
  45. .word  _end_address_data
  46. /* start address for the .bss section. defined in linker script */
  47. .word  _start_address_bss
  48. /* end address for the .bss section. defined in linker script */
  49. .word  _end_address_bss
  50. /* stack used for SystemInit_ExtMemCtl; always internal RAM used */

  51.     .section  .text.Reset_Handler
  52.   .weak  Reset_Handler
  53.   .type  Reset_Handler, %function
  54. // Reset handler routine
  55. Reset_Handler:
  56.   ldr   sp, =_end_stack

  57. /* Copy the data segment initializers from flash to SRAM */
  58.   ldr r0, =_start_address_data
  59.   ldr r1, =_end_address_data
  60.   ldr r2, =_start_address_init_data
  61.   movs r3, #0
  62.   b L_loop0_0

  63. L_loop0:
  64.   ldr r4, [r2, r3]
  65.   str r4, [r0, r3]
  66.   adds r3, r3, #4

  67. L_loop0_0:
  68.   adds r4, r0, r3
  69.   cmp r4, r1
  70.   bcc L_loop0

  71.   ldr r2, =_start_address_bss
  72.   ldr r4, =_end_address_bss
  73.   movs r3, #0
  74.   b L_loop1

  75. L_loop2:
  76.   str  r3, [r2]
  77.   adds r2, r2, #4

  78. L_loop1:
  79.   cmp r2, r4
  80.   bcc L_loop2

  81.   bl  SystemInit
  82.   bl __libc_init_array
  83.   bl  main
  84.   bx  lr
  85. .size  Reset_Handler, .-Reset_Handler

  86. // This is the code that gets called when the processor receives an unexpected interrupt.
  87.     .section  .text.Default_Handler,"ax",%progbits
  88. Default_Handler:
  89. Infinite_Loop:
  90.   b  Infinite_Loop
  91.   .size  Default_Handler, .-Default_Handler
  92. // The minimal vector table for a Cortex M4.
  93.    .section  .apm32_isr_vector,"a",%progbits
  94.   .type  g_apm32_Vectors, %object
  95.   .size  g_apm32_Vectors, .-g_apm32_Vectors

  96. // Vector Table Mapped to Address 0 at Reset
  97. g_apm32_Vectors:
  98.   .word  _end_stack                        // Top of Stack
  99.   .word  Reset_Handler                     // Reset Handler
  100.   .word  NMI_Handler                       // NMI Handler
  101.   .word  HardFault_Handler                 // Hard Fault Handler
  102.   .word  MemManage_Handler                 // MPU Fault Handler
  103.   .word  BusFault_Handler                  // Bus Fault Handler
  104.   .word  UsageFault_Handler                // Usage Fault Handler
  105.   .word  0                                 // Reserved
  106.   .word  0                                 // Reserved
  107.   .word  0                                 // Reserved
  108.   .word  0                                 // Reserved
  109.   .word  SVC_Handler                       // SVCall Handler
  110.   .word  DebugMon_Handler                  // Debug Monitor Handler
  111.   .word  0                                 // Reserved
  112.   .word  PendSV_Handler                    // PendSV Handler
  113.   .word  SysTick_Handler                   // SysTick Handler

  114.   /* External Interrupts */
  115.   .word     WWDT_IRQHandler                   // Window WatchDog
  116.   .word     PVD_IRQHandler                    // PVD through EINT Line detection
  117.   .word     TAMP_STAMP_IRQHandler             // Tamper and TimeStamps through the EINT line
  118.   .word     RTC_WKUP_IRQHandler               // RTC Wakeup through the EINT line
  119.   ........
  120.   .word     Default_IRQHandler               // Default exception/interrupt handler

  121.    .weak      NMI_Handler
  122.    .thumb_set NMI_Handler,Default_Handler

  123.    .weak      HardFault_Handler
  124.    .thumb_set HardFault_Handler,Default_Handler

  125.    .weak      MemManage_Handler
  126.    .thumb_set MemManage_Handler,Default_Handler

  127.    .weak      BusFault_Handler
  128.    .thumb_set BusFault_Handler,Default_Handler

  129.    .weak      UsageFault_Handler
  130.    .thumb_set UsageFault_Handler,Default_Handler

  131.    .weak      SVC_Handler
  132.    .thumb_set SVC_Handler,Default_Handler

  133.    .weak      DebugMon_Handler
  134.    .thumb_set DebugMon_Handler,Default_Handler

  135.    .weak      PendSV_Handler
  136.    .thumb_set PendSV_Handler,Default_Handler

  137.    .weak      SysTick_Handler
  138.    .thumb_set SysTick_Handler,Default_Handler

  139.    .weak      WWDT_IRQHandler
  140.    .thumb_set WWDT_IRQHandler,Default_Handler

  141.    .weak      PVD_IRQHandler
  142.    .thumb_set PVD_IRQHandler,Default_Handler

  143.    .weak      TAMP_STAMP_IRQHandler
  144.    .thumb_set TAMP_STAMP_IRQHandler,Default_Handler

  145.    .weak      RTC_WKUP_IRQHandler
  146.    .thumb_set RTC_WKUP_IRQHandler,Default_Handler

  147.    .....
     启动文件负责初始化系统和处理器的状态,包括设置堆栈指针、数据段的拷贝和调用main()函数。

2.1 文件头和基本指令
  1. .syntax unified
  2. .cpu cortex-m4
  3. .fpu softvfp
  4. .thumb
     - .syntax unified:指明使用统一语法,这在 ARM 汇编中是常用的语法形式。
      - .cpu cortex-m4:指定目标处理器为 Cortex-M4。
      - .fpu softvfp:指定所使用的浮点单元(FPU),这里表示使用软件浮点运算。
      - .thumb:启用 Thumb 模式,Cortex-M4 支持 Thumb 和 ARM 两种指令集,但 Thumb 模式通常用于嵌入式开发。

2.2 全局符号
  1. .global  g_apm32_Vectors
  2. .global  Default_Handler
     这些指令将 g_apm32_Vectors 和 Default_Handler 符号标记为全局,以便其他文件可以访问这些符号。

2.3 内存地址指定
  1. .word  _start_address_init_data
  2. .word  _start_address_data
  3. .word  _end_address_data
  4. .word  _start_address_bss
  5. .word  _end_address_bss
     这些 .word 指令定义了与链接文件中定义的地址相关的符号。这些符号用于在程序中引用数据段(.data)和未初始化数据段(.bss)的起始和结束地址。

2.4 重置处理程序定义
  1. .section  .text.Reset_Handler
  2. .weak  Reset_Handler
  3. .type  Reset_Handler, %function

  4. Reset_Handler:
  5.   ldr   sp, =_end_stack
     - .section .text.Reset_Handler:定义一个名为 .text.Reset_Handler 的代码段,所有代码将被放置在这个段中。
      - .weak Reset_Handler:将 Reset_Handler 定义为弱链接符号,允许它在其他地方被重定义。
      - .type Reset_Handler, %function:标记 Reset_Handler 为函数类型。

2.4.1 重置处理程序逻辑
  1. /* Copy the data segment initializers from flash to SRAM */
  2. ldr r0, =_start_address_data
  3. ldr r1, =_end_address_data
  4. ldr r2, =_start_address_init_data
  5. movs r3, #0
  6. b L_loop0_0

  7. L_loop0:
  8.   ldr r4, [r2, r3]
  9.   str r4, [r0, r3]
  10.   adds r3, r3, #4

  11. L_loop0_0:
  12.   adds r4, r0, r3
  13.   cmp r4, r1
  14.   bcc L_loop0
     - 这部分代码负责将 Flash 中的初始化数据复制到 SRAM 中。
      - 使用 Load 和 Store 指令将数据从一个地址复制到另一个地址,直到复制完成。

2.4.2 BSS 段初始化
  1. ldr r2, =_start_address_bss
  2. ldr r4, =_end_address_bss
  3. movs r3, #0
  4. b L_loop1

  5. L_loop2:
  6.   str  r3, [r2]
  7.   adds r2, r2, #4

  8. L_loop1:
  9.   cmp r2, r4
  10.   bcc L_loop2
     - 这段代码将未初始化的 BSS 段(全局变量和静态变量)初始化为零。
      - 使用循环将值 0 写入 BSS 段的每个位置。

2.4.3 系统初始化和主程序调用
  1. bl  SystemInit
  2. bl __libc_init_array
  3. bl  main
  4. bx  lr
     - bl 指令用于调用其他函数,依次调用 SystemInit(用于系统初始化)、__libc_init_array(初始化 C 库)和 main 函数。
      - bx lr 指令用于返回到调用者。

2.5 默认处理程序定义
  1. .section  .text.Default_Handler,"ax",%progbits
  2. Default_Handler:
  3. Infinite_Loop:
  4.   b  Infinite_Loop
  5. .size  Default_Handler, .-Default_Handler
     - .section .text.Default_Handler:定义默认处理程序的代码段。
      - Default_Handler 是在发生未定义的中断时调用的处理程序,进入无限循环。

2.6 中断向量表
  1. .section  .apm32_isr_vector,"a",%progbits
  2. .type  g_apm32_Vectors, %object
  3. .size  g_apm32_Vectors, .-g_apm32_Vectors

  4. g_apm32_Vectors:
  5.   .word  _end_stack                        // Top of Stack
  6.   .word  Reset_Handler                     // Reset Handler
  7.   .word  NMI_Handler                       // NMI Handler
  8.   .word  HardFault_Handler                 // Hard Fault Handler
  9.   .word  MemManage_Handler                 // MPU Fault Handler
  10.   .word  BusFault_Handler                  // Bus Fault Handler
  11.   .word  UsageFault_Handler                // Usage Fault Handler
  12.   .word  0                                 // Reserved
  13.   ...
  14.   .word     Default_Handler               // Default exception/interrupt handler
     - 这部分定义了中断向量表,包含了不同中断源对应的处理程序的地址。
      - 向量表的第一个条目是堆栈的顶部地址,第二个是重置处理程序的地址,后面跟着其他中断处理程序的地址。

2.7 弱链接中断处理程序
  1. .weak      NMI_Handler
  2. .thumb_set NMI_Handler,Default_Handler
     - 使用 .weak 指令声明多个中断处理程序为弱链接符号,允许用户在其他地方定义它们的实际实现。
      - 如果没有提供自定义的实现,系统将使用 Default_Handler 作为中断处理程序。

2.8 结论
      这个汇编文件是为 APM32F40xx 系列微控制器编写的启动代码,包含了设备的重置处理程序、默认中断处理程序和中断向量表。通过对不同内存段的初始化和中断处理的定义,文件确保了设备在上电或复位后的正常启动和运行。理解这些内容对于嵌入式系统的开发和调试至关重要。

3. 链接文件与启动文件的关联
3.1 整体文件编译
      在编译和链接过程中,startup_apm32f40xxG.ld(链接脚本文件)和startup_apm32f40x.S(汇编源文件)的处理顺序如下。

3.1.1 编译顺序
      - 汇编 (.S 文件):
          - 首先,startup_apm32f40x.S 文件会被编译成目标文件 .o。在这个步骤中,汇编器将汇编语言转换为机器代码并生成目标文件。
          - 在汇编过程中,处理器指令和数据段会按照汇编源文件中的定义生成相应的机器代码
      - 链接 (.ld 文件):
          - 然后,链接器会使用 startup_apm32f40xxG.ld 文件来链接不同的目标文件。在这个步骤中,链接器根据链接脚本的定义将 .o 文件中的各个段合并,并分配它们在内存中的位置
          - 链接器会根据 .ld 文件中的 MEMORY 和 SECTIONS 指令安排各个段的位置,同时处理符号解析和重定位。

3.1.2 总体流程
      - 步骤 1: 先编译汇编源文件 startup_apm32f40x.S,生成目标文件(如 startup_apm32f40x.o)。
      - 步骤 2: 接着,链接器读取 startup_apm32f40xxG.ld 文件,链接 startup_apm32f40x.o 和其他相关的目标文件,生成最终的可执行文件。

3.1.3 重要性
      汇编文件中的 Reset_Handler 函数会作为程序的入口点,而链接脚本文件则定义了程序的内存布局,确保代码和数据在运行时的位置正确。
      因此,首先编译汇编文件是重要的,因为链接的过程依赖于汇编后的目标文件内容。

3.1.4 总结
      整体编译顺序是先汇编 .S 文件生成目标文件,然后使用 .ld 文件进行链接。这种顺序确保了程序在内存中的各个段能够按照预定的布局正确运行。

3.2 文件段编译
      在 startup_apm32f40xxG.ld(链接脚本)和 startup_apm32f40x.S(汇编源文件)中,各个段的编译顺序如下。

3.2.1 链接脚本 (startup_apm32f40xxG.ld) 中的段顺序
      在链接脚本中,段的定义顺序决定了它们在生成的可执行文件中的顺序和在内存中的分布。以下是主要段的顺序:
      - .apm32_isr_vector: 存放中断向量表,优先加载,以确保在复位时可以找到正确的中断服务程序。
      - .text: 存放程序的执行代码,包括Reset_Handler和其他初始化代码。
      - .rodata: 存放只读数据,如字符串常量等。
      - .ARM.extab: 存放异常处理相关数据。
      - .preinit_array: 存放在程序开始运行前需要调用的初始化函数的地址
      - .init_array: 存放在main函数之前需要调用的初始化函数
      - .fini_array: 存放在程序结束后需要调用的清理函数的地址
      - .data: 存放初始化后的全局变量,从FLASH复制到RAM。
      - .ccmram: 存放特定数据或代码,位于CCMRAM区域。
      - .bss: 存放未初始化的全局变量,分配在RAM中。
      - ._user_heap_stack: 定义堆和堆栈的大小和位置。

3.2.2 汇编源文件 (startup_apm32f40x.S) 中的段顺序
      在汇编文件中,虽然汇编器会将各个指令和数据段放置在不同的段中,但它们的顺序通常与链接脚本一致,主要包括:
      - .section .text.Reset_Handler
          - 定义了Reset_Handler函数,作为程序的入口点
      - .section .text.Default_Handler:
          - 定义了默认的中断处理程序
      - .section .apm32_isr_vector:
          - 定义了中断向量表,包括各个中断处理程序的地址。
      - 数据段的初始化:
          - 在Reset_Handler中,包含了从FLASH复制.data段初始化数据到RAM的代码,以及清零.bss段的代码

3.2.3 总结
      - 在链接过程中,首先处理中断向量表以确保系统重置时能正确跳转到Reset_Handler。
      - 然后是程序主代码段.text,接着是只读数据段.rodata,再到初始化数据段.data。
      - 最后处理未初始化数据段.bss和动态分配的堆栈区域。

      这种顺序确保了系统启动时能够按照预定义的流程和内存布局正常运行。
      其链接关系可见如下图。
f8865b536abae494ad7485bb63ee1a9c

4. 结论
      通过对APM32的链接文件和启动文件的分析,我们可以看到它们在嵌入式系统开发中的重要性和相互依赖性。链接文件负责定义内存布局,明确各个段(如代码段、数据段、未初始化段等)在内存中的位置和大小,从而确保系统能够正确地执行程序。它确保了在将程序加载到设备内存时,各个部分能够按照预期的顺序和位置进行分布。
      启动文件则负责在设备上电时进行必要的初始化,包括设置堆栈指针、清零未初始化的数据段以及调用用户的初始化函数。启动文件通常包含复位处理程序(Reset_Handler)和默认的中断处理程序,确保系统在复位后能够顺利启动,并在中断发生时有正确的处理机制。
      这两个文件的相互依赖性体现在,链接文件所定义的内存布局必须与启动文件中的初始化逻辑相匹配。例如,启动文件中的代码需要按照链接文件定义的地址来执行,从而确保系统能够正确运行。此外,链接文件中的 .isr_vector 段需要指向启动文件中的复位处理程序,以确保在复位时能够正确跳转。
      总结来说,链接文件和启动文件在嵌入式系统的开发中是密不可分的。它们共同确保了系统的正常启动和运行,提供了基础的环境支持,使得开发者能够更方便地进行后续的应用开发。


     

打赏榜单

21小跑堂 打赏了 100.00 元 2024-11-21
理由:恭喜通过原创审核!期待您更多的原创作品~~~

评论

一篇文章,带你详解单片机开发中的启动文件和链接文件,让我们从底层了解单片机。文章段落清晰,描述详细,值得一看。  发表于 2024-11-21 14:20
呐咯密密 发表于 2024-11-20 09:48 | 显示全部楼层
总结的这么详细啊,楼主可靠
我想看大海 发表于 2024-11-20 20:33 | 显示全部楼层
一般就是拿来看代码中的变量大小
 楼主| DKENNY 发表于 2024-11-21 14:47 | 显示全部楼层
我想看大海 发表于 2024-11-20 20:33
一般就是拿来看代码中的变量大小

链接文件和启动文件用于定义和管理代码的内存布局和初始化过程,而不仅仅是查看变量的大小~
lulugl 发表于 2024-11-25 09:20 | 显示全部楼层
确实是非常详细介绍启动配置的好文章!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

59

主题

104

帖子

16

粉丝
快速回复 在线客服 返回列表 返回顶部