Memory 试图了解ARM二进制映像中的加载内存地址(LMA)和二进制文件偏移量

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

我在ARM Cortex M4STM32F4xxxx)中工作,我试图了解二进制文件(
*.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