使用arm-none-eabi-gcc (Sourcery G++ Lite For AMR)编译STM32的C++程序后的.ld .map文件的理解
以stm32f030rct6为例,在stm32f0_stm32f030xc.ld,有如下一段脚本。
/* Entry Point */ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _estack = 0x20008000; /* end of 32K RAM */ /* Generate a link error if heap and stack don't fit into RAM */ _Min_Heap_Size = 0; /* required amount of heap */ _Min_Stack_Size = 0x200; /* required amount of stack */ /* Specify the memory areas */ /*ORIGIN = 0x08006000, LENGTH = 232K*/ MEMORY { FLASH (rx) : ORIGIN = 0x08006000, LENGTH = 232K RAM (xrw) : ORIGIN = 0x200000C0, LENGTH = 32K MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K }
这里就指定了程序的入口就是在Reset_Handler,指定栈顶空间为0x20008000;堆栈大小,定义Flash起始地址0x08006000,原本0x08000000,分出0x6000作为BootLoader的引导程序。剩余的flash大小 256 – (0x6000/1024)=232 (f030rct6只有256KB的flash)。原因请查看这里
在生成的.map文件,我们可以在Linker script and memory map(链接器脚本和内存映射)段查找到
0x20008000 _estack = 0x20008000 0x00000000 _Min_Heap_Size = 0x0 0x00000200 _Min_Stack_Size = 0x200
接下来继续看在stm32f0_stm32f030xc.ld,有如下一段脚本。
/* The startup code goes first into FLASH */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH /* The program code and other data goes into FLASH */ .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 (*(.init)) KEEP (*(.fini)) . = ALIGN(4); _etext = .; /* define a global symbols at end of code */ } >FLASH
这里指定开始文件编译生成的文件放在 .isr_vector段,其实这一段就是存放的F030RC的47个中断向量地址,具体的可以在启动文件startup_stm32f030xc.s中查找,字节对齐后就是188字节(0xbc),编译后在map文件,我也可以看到如下描述,.isr_vector开始地址为0x08006000,4字节对齐,大小0xbc,与我们计算的吻合。.text代码段起始地址为 0x080060c0(为啥呢 ,这里有什么占用了4个字节目前不清楚,如果哪位大佬看到了请给我说下)这里代码段占用0x1a6a8字节,接下来map文件就会接受那个函数编译后占用的flash大小了,
.isr_vector 0x08006000 0xbc 0x08006000 . = ALIGN (0x4) *(.isr_vector) .isr_vector 0x08006000 0xbc OutPut/startup_stm32f030xc.o 0x08006000 g_pfnVectors 0x080060bc . = ALIGN (0x4) .text 0x080060c0 0x1a6a8 0x080060c0 . = ALIGN (0x4)
可以看到前面与我们的配置信息相同。比如下面是/syscalls.c文件编译出syscalls.o文件,其中_exit函数起始地址 0x08019e5c,大小0x4,要访问函数_exit,访问地址0x08019e5c即可。
.text._exit 0x08019e5c 0x4 OutPut/syscalls.o 0x08019e5c _exit .text._getpid 0x08019e60 0x4 OutPut/syscalls.o 0x08019e60 _getpid .text._sbrk 0x08019e64 0x30 OutPut/syscalls.o 0x08019e64 _sbrk
继续看stm32f0_stm32f030xc.ld,就会定义.rodata、.ARM.extab、.preinit_array、.init_array、.fini_array、.data、.bss、._user_heap_stack等数据段
其中.rodata段存放只读数据如常量、字符串等。.ARM.extab,.preinit_array、.init_array、.fini_array母鸡呀。.data属于已经初始化好的数据段,.bss是未初始化的数据段。这些信息都可以在map文件看到,下面来看看编译链接后的信息
section size addr .isr_vector 188 134242304 .text 108200 134242496 .rodata 11084 134350696 .ARM.extab 1280 134361780 .ARM 1448 134363060 .init_array 24 134364508 .fini_array 4 134364532 .data 2272 536871104 .bss 7152 536873376 ._user_heap_stack 512 536880528 .ARM.attributes 41 0
可以看到.isr_vecto起始地址134242304(0x8000000),大小都与map文件吻合。.data段的既会存放在flash中,也会存放在RAM中,起始地址就是536871104(0x200000C0)与前面的描述也吻合。
存放在flash的有.isr_vector、.text、.rodata、.ARM.extab、.preinit_array、.init_array、.fini_array、.data,他们的总和就是生成的bin文件大小,该是188+4(前面提了这个疑问)+108200+11084+1280+1448+24+4+2272+7152=124504个字节(≈122KB)不能大于flash大小256KB,但是由于使用了IAP,所以不能大于前面计算的232KB。
占用的RAM就是.data,.bss的总和总计2272+7152=9424字节(不能大于f030的RAM32KB)