Memory 试图了解ARM二进制映像中的加载内存地址(LMA)和二进制文件偏移量
我在ARM Cortex M4(STM32F4xxxx)中工作,我试图了解二进制文件(Memory 试图了解ARM二进制映像中的加载内存地址(LMA)和二进制文件偏移量,memory,linker,arm,embedded,microcontroller,Memory,Linker,Arm,Embedded,Microcontroller,我在ARM Cortex M4(STM32F4xxxx)中工作,我试图了解二进制文件(*.elf和*.bin)是如何在内存中构建和闪存的,特别是在内存位置方面。具体地说,我不明白的是LMA如何从实际的二进制文件偏移量“转换”而来。让我举例说明: 我有一个*.elf文件,其(相关)部分如下:(从objdump-h获取) 根据该文件,VMA和LMA分别是0x8000000和0x801000,这是非常好的,因为它们在链接器脚本文件中以这种方式定义。此外,根据该报告,这些部分的偏移量分别为0x10000
*.elf
和*.bin
)是如何在内存中构建和闪存的,特别是在内存位置方面。具体地说,我不明白的是LMA
如何从实际的二进制文件偏移量“转换”而来。让我举例说明:
我有一个*.elf
文件,其(相关)部分如下:(从objdump-h
获取)
根据该文件,VMA和LMA分别是0x8000000
和0x801000
,这是非常好的,因为它们在链接器脚本文件中以这种方式定义。此外,根据该报告,这些部分的偏移量分别为0x10000
和0x20000
。接下来,我执行以下命令以转储与.bootloader
对应的内存:
xxd -s 0x10000 -l 16 my_file.elf
00010000: b007 c0de b007 c0de b007 c0de b007 c0de ................
现在,创建要闪存到内存中的二进制文件:
arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_file.elf my_file.bin
根据上面提供的信息,据我所知,生成的二进制文件应该有.bootloader
部分位于0x8000000
。我知道这不是它实际的工作方式,因为文件会变得非常大,所以引导加载程序
放在文件的开头,所以地址0x0
(检查两个内存块是否相同,即使它们位于不同的地址):
据我所知,当提到的二进制文件被闪存到内存中时,bootloader
将位于地址0x0
,考虑到问题中的MCU在开始工作时跳到地址0x4
(从0x0
获取SP后),这是非常好的,正如我在这里检查的那样(第26页):
最后,我的问题是:
bootloader
是否实际位于0x0
?如果是,在链接器文件中定义内存扇区的目的是什么
这是因为0x0
属于闪存,当MCU启动时,所有闪存都复制到地址0x8000000
处的RAM
中?如果是,是否从闪存执行bootloader
,并从RAM执行所有剩余的代码
考虑到上述问题,如果我没有理解任何东西,LMA
和文件偏移量之间的关系/区别是什么?否,引导加载程序将为08000000,如elf文件中所定义
图像将在该地址的闪存中烧录,并直接从该地址执行(而不是复制到其他地方)
有一些未记录的行为,即在生成二进制图像时跳过实际数据之前的单位化区域
最低部分(.bootloader)LMA在.elf中为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
(注意:这不适用于十六进制图像(如intel hex或s-record),因为这类格式明确定义加载地址,并按原样使用)。文档非常清楚stm32的应用程序代码的地址空间在哪里,即0x08000000(竞争供应商如0x01000000,等等)。并且当以特定模式引导时,0x08000000映射到地址0x00000000,这可以通过调试器轻松看到(在两个空间中)
0x00000000处映射到0x08000000的地址空间小于0x08000000处的潜在地址空间,具体取决于芯片。因此,明智的做法是为0x08000000而不是0x00000000构建和使用0x08000000,但对于小型程序,您可以选择其中之一
由于cortex-m是一个向量表机器,当逻辑读取地址0x00000004(在正常引导模式下映射到0x08000004)时,它会看到0x0800xxxxx,然后退出0x00000000内存空间,从而避免任何限制
当您使用boot0/boot1引脚时,您可以使0x00000000映射到Burn-in引导加载程序所在的其他位置。该引导加载程序当然可以轻松读取0x08000000并通过分支轻松模拟重置,或者它可以更改逻辑并实际重置(如果你要求它,尽管我不知道引导加载程序是否支持运行程序)。谁知道我们是否在那里工作,我们不一定要说。很可能它总是引导到引导加载程序,然后它会根据条带更改映射
与mmu类似,但解码地址和别名非常简单。如果boot0==0且地址[31:16]=0x0000,则地址[31:16]=0x0800,并且内存系统在不同的地址对其进行解码,就像用C编写一样简单,在HDL中即使不容易也很容易
这在微控制器和其他微控制器中并不少见,但由于微控制器通常从闪存/rom启动,但某些体系结构上相同的启动空间也是RTO可能要操纵的向量或异常表,有时您会看到ram可以交换到该空间中,以便cpu“看到”控制寄存器更改后的某个ram在引导时“看到”闪存上的向量表。或者,您将闪存上的代码分支到ram中某个位置,用于非重置向量,然后RTO或任何其他关心此操作的应用程序可以在运行时更改针对这些异常或中断实际运行的代码
ARM对代码可以在哪里执行、数据可以在哪里生存、您可能希望在哪里启动外围地址空间以及ARM为核心内的资源保留的地址空间施加了地址空间规则。因此,有时您会看到ram具有
xxd -s 0x00000 -l 16 my_file.bin
00000000: b007 c0de b007 c0de b007 c0de b007 c0de ................
/* 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. */
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
----- 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