试图了解 ARM 二进制映像中的加载内存地址 (LMA) 和二进制文件偏移量 [英] Trying to understand the load memory address (LMA) and the binary file offset in an ARM binary image

查看:34
本文介绍了试图了解 ARM 二进制映像中的加载内存地址 (LMA) 和二进制文件偏移量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 ARM Cortex M4 (STM32F4xxxx) 并且我正在尝试了解二进制文件 (*.elf*.bin) 在内存中构建和闪存,特别是关于内存位置.具体来说,我不明白的是 LMA 如何从实际的二进制文件偏移量中翻译".让我用一个例子来解释:

I'm working in an ARM Cortex M4 (STM32F4xxxx) and I'm trying to understand how exactly the binaries (*.elf and *.bin) are built and flashed in memory, specially with regards to the memory locations. Specifically, what I don't understand is how the LMA gets 'translated' from the actual binary file offset. Let me explain with an example:

我有一个 *.elf 文件,其(相关)部分如下:(从 objdump -h 获得)

I have an *.elf file whose (relevant) sections are the following ones:(obtained from 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

根据该文件,VMA 和 LMA 是 0x80000000x8010000,这很好,因为它们在链接描述文件中是这样定义的.此外,根据该报告,这些部分的偏移量分别为 0x100000x20000.接下来,我执行以下命令来dump .bootloader 对应的内存:

According to that file, the VMA and LMA are 0x8000000 and 0x8010000, what is perfectly fine since they are defined that way in the linker script file. In addition, according to that report, the offsets of those sections are 0x10000 and 0x20000 respectively. Next, I execute the following command for dumping the memory corresponding to the .bootloader:

xxd -s 0x10000 -l 16 my_file.elf
00010000: b007 c0de b007 c0de b007 c0de b007 c0de  ................ 

现在,创建要刷入内存的二进制文件:

Now, create the binary file to be flashed into memory:

arm-none-eabi-objcopy -O binary --gap-fill 0xFF -S my_file.elf my_file.bin 

根据上面提供的信息,据我所知,生成的二进制文件应该有位于 0x8000000.bootloader 部分.我知道这不是它的实际工作方式,因为文件会变得非常大,所以 bootloader 放在文件的开头,所以地址 0x0(检查两个内存块是否相同,即使它们位于不同的地址):

According to the information provided above, and as far as I understand, the generated binary file should have the .bootloader section located at 0x8000000. I understand that this is not how it actually works, inasmuch as the file would get extremely big, so the bootloader is placed at the beginning of the file, so the address 0x0 (check that both memory chunks are identical, even though the are at different addresses):

xxd -s 0x00000 -l 16 my_file.bin
00000000: b007 c0de b007 c0de b007 c0de b007 c0de  ................

据我所知,当提到的二进制文件被刷入内存时,bootloader 将位于地址 0x0,考虑到有问题的 MCU 在开始工作时会跳转到地址 0x4(从 0x0 获取 SP 后),正如我在此处检查的(第 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

As far as I understand, when the mentioned binary file is flashed into memory, the bootloader will be at address 0x0, what is perfectly fine taking into account that the MCU in question jumps to the address 0x4 (after getting the SP from 0x0) when it starts working, as I have checked here (page 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 上吗?如果是这样,在链接器文件中定义内存扇区的目的是什么?

Will the bootloader actually be placed at 0x0? If so, what's the purpose of defining the memory sectors in the linker file?

这是不是因为0x0属于flash memory,当MCU启动时,所有flash都被拷贝到RAM地址0x8000000?如果是这样,bootloader 是否会从闪存中执行,而所有其余代码会从 RAM 中执行?

Is this because 0x0 belongs to flash memory, and when the MCU starts, all the flash is copied into RAM at address 0x8000000? If so, will the bootloader be executed from flash memory and all the rest of the code from RAM?

综合以上问题,如果我还没有理解什么,LMAFile offset之间的关系/区别是什么?

Taking into account the above questions, if I have not understood anything, what's the relation/difference between the LMA and the File offset?

推荐答案

不,引导加载程序将在 08000000,如 elf 文件中所定义.

No, bootloader will be at 08000000, as defined in elf file.

图像将在该地址的闪存中烧录并直接从那里执行(不会复制到其他地方).

Image will be burned in flash at that address and executed directly from there (not copied somewhere else or so).

有些未记录的行为,即在生成二进制图像时跳过实际数据之前的单元化区域.作为 BFDlib 源代码中的注释(https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=bfd/binary.c;h=37f5f9f7363e7349612cdfc8bc577903c;hb=HEAD#l238)

There's somewhat undocumented behaviour, that unitialized area before actual data is skipped when producing binary image. As comment in BFDlib source states (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.  */

.elf 中的最低部分 (.bootloader) LMA 为 08000000,因此二进制文件将从该地址开始.
在确定图像中的地址时,您应该考虑此地址并将其添加到文件偏移量中.

Lowest section (.bootloader) LMA is 08000000 in your .elf, so binary file will start at this address.
You should take this address into account and add it to file offset when determining address in the image.

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

ldscript 中定义的那个地址,所以二进制图像应该从固定位置开始.但是,在处理 ldscrips 和二进制图像时,您应该注意这种行为.

That address defined in ldscript, so binary image should start at fixed location. However you should be aware of this behaviour when dealing with ldscrips and binary images.

总结构建和刷写过程:

  1. 链接时,起始地址在 ldscript 中定义,并且 elf 中的第一部分位于那里.
  2. 转换为二进制时,起始地址由 LMA 确定,二进制图像从该地址开始.
  3. 闪烁图像时,将相同的地址作为参数提供给 flasher,因此图像被放置在正确的位置(在 ldscript 中定义).

更新:STM32F4xxx 启动过程.

Update: STM32F4xxx booting process.

从地址 0 开始的地址区域对于那些 MCU 来说是特殊的.它可以配置为映射其他区域,即闪存、SRAM 或系统 ROM.它们由引脚 BOOTSELx 选择.从 CPU 方面看,第二个闪存副本(SRAM 或系统 ROM)出现在地址 0.

Address region starting at address 0 is special to those MCUs. It can be configured to map other regions, which are flash, SRAM, or system ROM. They're selected by pins BOOTSELx. From CPU side it looks like second copy of flash (SRAM or system ROM) appears at address 0.

当CPU启动时,它首先从地址0读取初始SP,从地址4读取初始PC.实际上是从闪存中读取.如果代码链接到从实际闪存位置运行,那么初始 PC 将指向那里.在这种情况下,执行从实际闪存地址开始.

When CPU starts, it first reads initial SP from adress 0 and initial PC from address 4. Actually, reads from the flash memory are performed. If the code is linked to run from actual flash location, then initial PC will point there. In this case execution starts at actual flash address.

----- 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

(注意:这不适用于十六进制图像(如 intel hex 或 s-record),因为此类格式明确定义了加载地址,并按原样使用).

(Note: this does not apply to hex images (like intel hex or s-record) as such formats define loading address explicitly and it is used as is there).

这篇关于试图了解 ARM 二进制映像中的加载内存地址 (LMA) 和二进制文件偏移量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆