Dan*_*Dan 5 memory embedded microcontroller linker arm
我正在ARM Cortex M4 ( STM32F4xxxx ) 中工作,我试图了解二进制文件 (*.elf和*.bin) 是如何在内存中构建和闪存的,特别是在内存位置方面。具体来说,我不明白的是如何LMA从实际的二进制文件偏移量“翻译”。让我用一个例子来解释:
我有一个*.elf文件,其(相关)部分如下:(从objdump -h)
my_file.elf: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000001c4 08010000 08010000 00020000 2**0
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .bootloader 00004000 08000000 08000000 00010000 2**0
CONTENTS, ALLOC, LOAD, DATA
Run Code Online (Sandbox Code Playgroud)
根据该文件,VMA 和 LMA 是0x8000000和0x8010000,这完全没问题,因为它们在链接器脚本文件中以这种方式定义。此外,根据该报告,这些部分的偏移量分别为0x10000和0x20000。接下来,我执行以下命令来转储对应的内存.bootloader:
xxd -s 0x10000 -l 16 my_file.elf
00010000: b007 c0de b007 c0de b007 c0de b007 c0de ................
Run Code Online (Sandbox Code Playgroud)
现在,创建要刷入内存的二进制文件:
arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_file.elf my_file.bin
Run Code Online (Sandbox Code Playgroud)
根据上面提供的信息,据我所知,生成的二进制文件应该有.bootloader位于0x8000000. 我知道这不是它的实际工作方式,因为文件会变得非常大,所以bootloader放在文件的开头,所以地址0x0(检查两个内存块是否相同,即使它们位于不同的地址):
xxd -s 0x00000 -l 16 my_file.bin
00000000: b007 c0de b007 c0de b007 c0de b007 c0de ................
Run Code Online (Sandbox Code Playgroud)
据我了解,当提到的二进制文件被刷入内存时,bootloader将在地址0x0,考虑到有问题的 MCU 在它开始工作时跳转到地址0x4(从 获取 SP 后0x0),这完全没问题,正如我在这里查看的(第 26 页):https : //www.st.com/content/ccc/resource/technical/document/application_note/76/f9/c8/10/8a/33/4b/f0/DM00115714。 pdf/files/DM00115714.pdf/jcr:content/translations/en.DM00115714.pdf
最后,我的问题是:
将bootloader实际被放置在0x0?如果是这样,在链接器文件中定义内存扇区的目的是什么?
是不是因为0x0属于flash memory,当MCU启动的时候,所有的flash都被拷贝到RAM了地址0x8000000?如果是这样,是否会bootloader从闪存中执行所有其余代码RAM?
考虑到上述问题,如果我还没有理解任何东西,theLMA和 the之间的关系/区别是File offset什么?
不,引导加载程序将位于 08000000,如 elf 文件中所定义。
图像将被刻录在闪存中的该地址并直接从那里执行(不会复制到其他地方)。
有一些未记录的行为,即在生成二进制图像时会跳过实际数据之前的统一区域。正如 BFDlib 源代码中的评论所述(https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=bfd/binary.c;h=37f5f9f7363e7349612cdfc8bc579369bbabbc0c;hb=HEAD#l238)
/* The lowest section LMA sets the virtual address of the start
of the file. We use this to set the file position of all the
sections. */
Run Code Online (Sandbox Code Playgroud)
.elf 中最低部分 (.bootloader) LMA 为 08000000,因此二进制文件将从该地址开始。
在确定图像中的地址时,您应该考虑该地址并将其添加到文件偏移量中。
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000001c4 08010000 08010000 00020000 2**0
/* ^^^^^^^^ */
/* this section will be at offset 10000 in image */
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .bootloader 00004000 08000000 08000000 00010000 2**0
/* ^^^^^^^^ */
/* this is the lowest LMA in your case it will be used */
/* as a start of an image, and this section will be placed */
/* directly at start of the image */
CONTENTS, ALLOC, LOAD, DATA
Memory layout: Bin. image layout:
000000000 \ skipped
... ________________ /
080000000 .bootloader 0
... ________________
080004000 <gap> 4000
... ________________
080010000 .text 10000
... ________________
0800101C4 101C4
Run Code Online (Sandbox Code Playgroud)
该地址在 ldscript 中定义,因此二进制图像应从固定位置开始。但是,在处理 ldscrip 和二进制图像时,您应该注意这种行为。
总结一下构建和刷新过程:
更新:STM32F4xxx启动过程。
从地址 0 开始的地址区域对于这些 MCU 来说是特殊的。它可以配置为映射其他区域,例如闪存、SRAM 或系统 ROM。它们是通过 pin 选择的BOOTSELx。从 CPU 端来看,闪存的第二个副本(SRAM 或系统 ROM)出现在地址 0 处。
CPU启动时,首先从地址0读取初始SP,从地址4读取初始PC。实际上,是从Flash存储器中读取。如果代码链接为从实际闪存位置运行,则初始 PC 将指向那里。在这种情况下,执行从实际闪存地址开始。
----- Mapped area (mimics contents as flash) ---
0: (02001000) ;
4: (0800ABCD) ----. ; CPU reads PC here
.... | ; (it points to flash)
----- FLASH ----- |
8000000: 20001000 | ; initial stack pointer
8000004: 0800ABCD --. | ; address of _start in flash
.... | |
800ABCD: <_start:> movw ... <-'<-' ; Code execution starts here
Run Code Online (Sandbox Code Playgroud)
(注意:这不适用于十六进制图像(如英特尔十六进制或 s-record),因为此类格式明确定义了加载地址,并且按原样使用)。