完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
.ld文件的作用
1.定义程序入口地址 2.定义Flash、RAM中代码和数据的存放位置 /* Entry Point */ /* 程序入口——程序将从Reset Handler开始执行,而该函数定义在stm32fxxx.s启动文件中。 ENTRY(Reset_Handler) /* Highest address of the user mode stack */ /* end of stack 堆栈末尾 = RAM起始地址 + RAM空间大小 */ _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ /* 程序所必须的堆、栈空间大小定义 */ _Min_Heap_Size = 0x200 ; /* required amount of heap */ _Min_Stack_Size = 0x400 ; /* required amount of stack */ /* Memories definition */ /* 单片机内部存储空间 RAM FLASH起始位置和大小的声明 */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K } /* Sections */ SECTIONS { /* The startup code into "FLASH" Rom type memory */ /* 中断向量表定义于 .s启动文件中,应位于Flash的最前端,也就是从0x8000000的位置开始 */ .isr_vector : { /* 字对齐 */ . = ALIGN(4); /* 将中断向量的内容链接到该地址 */ KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH /* The program code and other data into "FLASH" Rom type memory */ /* .text对应程序的可执行代码 */ .text : { /* 字对齐 */ . = ALIGN(4); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.glue_7) /* glue arm to thumb code */ *(.glue_7t) /* glue thumb to arm code */ *(.eh_frame) /* KEEP() 的作用是当启用连接器的--gc-sections垃圾回收选项时,这部分不能被回收 参考链接 https://blog.csdn.net/wangbinyantai/article/details/79001303 */ KEEP (*(.init)) KEEP (*(.fini)) . = ALIGN(4); /* _etext是链接器的预定义变量,代表程序正文段结束的第一个地址 */ _etext = .; /* define a global symbols at end of code */ } >FLASH /* Constant data into "FLASH" Rom type memory */ /* .rodata代表程序中使用的常量表格数据等 */ .rodata : { /* 前后字对齐 */ . = ALIGN(4); *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ . = ALIGN(4); } >FLASH /* ?如果有朋友清楚下面这段定义的含义请评论告诉我,多谢!*/ .ARM.extab : { . = ALIGN(4); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } >FLASH .ARM : { . = ALIGN(4); __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; . = ALIGN(4); } >FLASH /* .preinit_array和.init_array部分包含指向将在初始化时调用的函数的指针数组。 参考链接:https://stackoverflow.com/questions/40532180/understanding-the-linkerscript-for-an-arm-cortex-m-microcontroller */ .preinit_array : { . = ALIGN(4); PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(4); } >FLASH .init_array : { . = ALIGN(4); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(4); } >FLASH .fini_array : { . = ALIGN(4); /* PROVIDE_HIDDEN 表示 :Similar to PROVIDE. For ELF targeted ports, the symbol will be hidden and won’t be exported. 表示符号在目标文件中被定义但不会被导出 */ PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(4); } >FLASH /* Used by the startup to initialize data */ /* 以变量_sidata存储.data块的起始地址,.data对应初始化了的全局变量 */ _sidata = LOADADDR(.data); /* Initialized data sections into "RAM" Ram type memory */ /* .data对应初始化了的全局变量,编译后将位于可执行文件中,由启动代码负责加载到数据区中(在单片机中这部分数据会存于flash中,需要由启动代码把这部分内容拷贝到ram中)*/ .data : { . = ALIGN(4); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(4); /* edata的地址是初始化数据区后面的第1个地址 */ _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH /* Uninitialized data section into "RAM" Ram type memory */ . = ALIGN(4); /* .bss段是没有初始值的全局变量,由启动代码把这部分内容全初始化为0 */ .bss : { /* This is used by the startup in order to initialize the .bss section */ _***ss = .; /* define a global symbol at bss start */ __bss_start__ = _***ss; *(.bss) *(.bss*) /* COMMON数据段仅在.o文件中存在,当代码中的全局变量没有赋初值时存储在该数据段中 */ https://stackoverflow.com/questions/16835716/bss-vs-common-what-goes-where */ *(COMMON) . = ALIGN(4); _ebss = .; /* define a global symbol at bss end */ __bss_end__ = _ebss; } >RAM /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ ._user_heap_stack : { . = ALIGN(8); /* 同PROVIDE_HIDDEN的作用类似,定义内部变量而不导出 */ PROVIDE ( end = . ); PROVIDE ( _end = . ); . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(8); } >RAM /* Remove information from the compiler libraries */ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } .ARM.attributes 0 : { *(.ARM.attributes) } } |
|
|
|
.s启动文件
gcc工具链和armcc的.s启动文件内容差别很大,我感觉都不像ARM汇编… .syntax unified /* 意思是下面的指令是ARM和THUMB通用格式的 */ .cpu cortex-m7 /* CPU内核型号 */ .fpu softvfp /* 选择使用的浮点单元,与-mfpu命令行选项的相同 */ .thumb /* 选择使用thumb指令 */ /* 声明可以被汇编器使用的符号 */ .global g_pfnVectors /* 在文件末尾定义的中断向量 */ .global Default_Handler /* 是一个死循环,用来处理异常情况 */ /* start address for the initialization values of the .data section. defined in linker script */ .word _sidata /* 初始值地址 */ /* start address for the .data section. defined in linker script */ .word _sdata /* .data 开始地址,.data对应初始化了的全局变量,编译后将位于可执行文件中,由启动代码负责加载到数据区中(在单片机中这部分数据会存于flash中,需要由启动代码把这部分内容拷贝到ram中) */ /* end address for the .data section. defined in linker script */ .word _edata /* .data块的结束地址 */ /* start address for the .bss section. defined in linker script */ .word _***ss /* .bss块的起始地址,.bss段是没有初始值的全局变量,由启动代码把这 部分内容全初始化为0 */ /* end address for the .bss section. defined in linker script */ .word _ebss /* .bss块的结束地址 */ /* stack used for SystemInit_ExtMemCtl; always internal RAM used */ /** * @brief 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. * @param None * @retval : None */ /* 定义Reset_Handler函数,该函数的作用1.设置堆栈指针;2.全局变量的初始化 */ .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: ldr sp, =_estack /* set stack pointer */ /* Copy the data segment initializers from flash to SRAM */ movs r1, #0 /* 将r1初始化为0 */ b LoopCopyDataInit /* 下面一段初始化在用户程序中指定初始值的全局变量 */ CopyDataInit: ldr r3, =_sidata /* 使用ldr伪指令将初始数据地址加载到r3中 */ ldr r3, [r3, r1] /* 寄存器间接寻址,将r3 + r1地址中的数据加载到r3中 */ str r3, [r0, r1] /* 将r3的内容写入 r0 + r1地址中 */ adds r1, r1, #4 /* 后变址,将r1地址中的内容写入r1,然后令r1 + 4 */ LoopCopyDataInit: ldr r0, =_sdata /* 使用ldr伪指令,在r0中写入.data的起始地址 */ ldr r3, =_edata /* 在r3中写入.data的末尾地址 */ adds r2, r0, r1 /* r2 = r0 + r1 ,操作影响条件标志位 */ cmp r2, r3 /* 比较r2和r3寄存器中的地址大小 */ bcc CopyDataInit /* 如果r2 < r3,也就是还没有到达data数据段的末尾,则转跳CopyDataInit */ /* 因为汇编语言顺序执行,上面代码会循环执行,直到复制到.data数据段结束 */ ldr r2, =_***ss /* r2中存储.bss数据区的首地址*/ b LoopFillZerobss /* Zero fill the bss segment. */ FillZerobss: movs r3, #0 /* 将寄存器r3写0 */ str r3, [r2], #4 /* 采用后变址,先将r3中的值写入r2,也就是bss数据区首地址中,然后r2自加4 */ LoopFillZerobss: ldr r3, = _ebss /* 将bss数据区的末尾地址写入r3 */ cmp r2, r3 /* 比较r2和r3的内容,看是否已经到达数据区的末尾 */ bcc FillZerobss /* 如果r2 < r3也就是没有到达末尾,则转跳FillZerobss继续写0操作 */ /* Call the clock system initialization function.*/ // bl SystemInit /* 转跳SystemInit函数 */ /* Call static constructors */ bl __libc_init_array /* Call the application's entry point.*/ bl main /* 转跳main函数执行 */ bx lr .size Reset_Handler, .-Reset_Handler /** * @brief This is the code that gets called when the processor receives an * unexpected interrupt. This simply enters an infinite loop, preserving * the system state for examination by a debugger. * @param None * @retval None */ .section .text.Default_Handler,"ax",%progbits Default_Handler: /* 默认异常处理代码段,是一段死循环 */ Infinite_Loop: b Infinite_Loop .size Default_Handler, .-Default_Handler /****************************************************************************** * * The minimal vector table for a Cortex M7. Note that the proper constructs * must be placed on this to ensure that it ends up at physical address * 0x0000.0000. * *******************************************************************************/ .section .isr_vector,"a",%progbits .type g_pfnVectors, %object .size g_pfnVectors, .-g_pfnVectors g_pfnVectors: .word _estack .word Reset_Handler .word NMI_Handler .word HardFault_Handler .word MemManage_Handler .word BusFault_Handler .word UsageFault_Handler .word 0 .word 0 .word 0 .word 0 .word SVC_Handler .word DebugMon_Handler .word 0 .word PendSV_Handler .word SysTick_Handler /* External Interrupts */ .word WWDG_IRQHandler /* Window WatchDog */ .word PVD_IRQHandler /* PVD through EXTI Line detection */ .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ .word FLASH_IRQHandler /* FLASH */ .word RCC_IRQHandler /* RCC */ .word EXTI0_IRQHandler /* EXTI Line0 */ .word EXTI1_IRQHandler /* EXTI Line1 */ .word EXTI2_IRQHandler /* EXTI Line2 */ .word EXTI3_IRQHandler /* EXTI Line3 */ .word EXTI4_IRQHandler /* EXTI Line4 */ .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ /***节省篇幅,其他类似定义略***/ /******************************************************************************* * * Provide weak aliases for each Exception handler to the Default_Handler. * As they are weak aliases, any function with the same name will override * this definition. * *******************************************************************************/ .weak NMI_Handler .thumb_set NMI_Handler,Default_Handler /***节省篇幅,其他类似定义略***/ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1804 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1629 浏览 1 评论
1097 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
736 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1686 浏览 2 评论
1944浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
748浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
583浏览 3评论
604浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
565浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 00:53 , Processed in 0.891058 second(s), Total 78, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号