![]() |
1
1
不,bootloader将位于08000000,如elf文件中所定义。 图像将在该地址的闪存中烧录,并直接从该地址执行(不复制到其他地方)。 有一些未记录的行为,即在生成二进制图像时跳过实际数据之前的统一区域。作为bfdlib源状态中的注释( https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=bfd/binary.c;h=37f5f9f7363e7349612cdfc8bc579369bbabbc0c;hb=HEAD#l238 )
最低部分(.bootloader)lma是.elf中的08000000,因此二进制文件将从这个地址开始。
在ldscript中定义的地址,所以二进制图像应该从固定位置开始。但是,在处理ldscrips和二进制图像时,应该注意这种行为。 总结建筑和泛水过程:
更新:stm32f4xxx启动过程。
从地址0开始的地址区域对于那些MCU是特殊的。它可以配置为映射其他区域,如闪存、SRAM或系统ROM。这些区域由管脚选择。
当CPU启动时,它首先从地址0读取初始SP,从地址4读取初始PC。实际上,执行从闪存读取。 如果代码链接到从实际闪存位置运行,则初始PC将指向该位置。在这种情况下,执行从实际的闪存地址开始。
(注意:这不适用于十六进制图像(如IntelHex或S-Record),因为这样的格式显式定义了加载地址,并且像现在这样使用)。 |
![]() |
2
2
文档非常清楚STM32的应用程序代码的地址空间在何处,即0x0800000(竞争供应商类似于0x1000000,等等)。当以特定模式启动时,0x0800000映射到地址0x00000000,这在调试器中很容易看到(在两个空格中)。 映射到0x0800000的0x00000000的地址空间小于潜在的0x0800000的地址空间,具体取决于芯片。因此,构建和使用0x0800000而不是0x00000000是明智的,但是对于小型程序,您可以选择其中之一。 因为Cortex-M是一个向量表机器,当逻辑读取地址0x0000004(在正常启动模式下映射到0x080000004)时,它会看到0x080XXXXX,然后从0x00000000内存空间中取出,从而避免了任何限制。 当您使用boot0/boot1带管脚时,您可以使0x00000000映射到烧坏的bootloader所在的其他地方。当然,这个引导加载程序可以很容易地读取0x0800000,并且通过分支很容易地模拟重置,或者它可以更改逻辑并实际重置(如果您要求,尽管我不知道这个引导加载程序是否支持运行程序)。谁知道我们是否在那里工作,我们不一定说。很有可能它总是引导到引导加载程序中,然后根据条带更改映射。 类似于MMU,但解码地址和给地址加别名要简单得多。如果boot0==0和address[31:16]=0x0000,那么address[31:16]=0x0800,内存系统会在不同的地址对其进行解码,就像用C编写一样简单,如果不容易,在HDL中也很容易。 这在微控制器和其他微控制器中并不少见,但由于微控制器通常是从闪存/ROM启动的,但在某些体系结构中,相同的启动空间也是RTO可能希望操作的向量或异常表,有时您会看到RAM可以交换到该空间中,因此CPU可以在一个控制寄存器在启动时在flash上“看到”矢量表的地方被改变。或者您将flash上的代码转移到RAM中的某个地方,以用于非重置向量,然后RTOS或任何其他关心此操作的应用程序可以对这些异常或中断实际运行的代码进行运行时更改。 ARM对代码可以在哪里执行、数据可以在哪里生存、您可能希望在哪里启动外围地址空间以及ARM为核心内的资源保留了什么地址空间都施加了地址空间规则。因此,有时您会看到RAM在较低的地址有一个别名,这意味着如果您想在RAM中运行一个程序,您需要使用较低的地址来执行,但可以使用其中一个地址来复制代码。 这取决于芯片设计人员如何简单或复杂地制作。对于ST来说,它非常简单,然后在包上有一个或多个引导管脚,至少可以让您在应用程序和片上引导加载程序之间进行选择,到目前为止,我所看到的所有STM32应用程序闪存空间都被视为生存在0x0800000,对于其中一种引导模式,它被映射/别名为0x00000000。当暴露了两个引导插脚时,最多可以存在四种可能的引导条件,其中一种是别名为0x00000000到0x0800000的应用程序。 至于如何将比特放入闪存,这一点因工具而异。像GNU这样的工具链当然会构建一个.bin文件,其中文件的第一个字节是ELF的第一个字节,我们希望它是0x0800000(如果是这样构建的,如果是为0x0200000构建的,它仍然是第一个字节,并且该代码可能无法工作)。有一些工具,你当然可以自己写,知道可以加载一个.bin文件在所需的位置0x0800000,或者你可以让你的太写地址0x00000000在正确的模式下为一个不是太大的程序,并让它仍然在正确的位置执行重置。同样,也可以编写工具来解析.elf文件、intel hex、motorola srecord和其他文件,并根据这些二进制文件中的信息,将数据加载到所需的地址空间中,前提是一切都没有错误。 你可能试图将其过度复杂化,这并不是什么神奇的事情,工具需要做理智的事情,理智的事情是从编译器中取出二进制文件,把它放在我们想要的芯片中。当然,我们要负责链接器脚本和引导程序代码/向量表,但是如果我们做的对,如果设计正确的工具将把位放在芯片中的正确位置,如果芯片设计正确,那么它将引导并运行。
理想情况下,您希望您的应用程序或引导装载程序位于处理器地址空间中的地址0x0800000处。在某些引导模式(boot0/boot1)中,该地址的别名也为0x00000000,因此您可以同时在两个位置看到向量表。如果您没有处于正确的启动模式,那么只有0x0800000会显示您的代码。
芯片中的逻辑设计为获取处理器在其地址总线上的地址,并在应用程序闪存上有多个地址地,如果它的一个16kbyte闪存只有一个从0x0000到0xffff的地址,则应用程序闪存不在0x0800000。例如,当您访问0x08001234时,它实际上向闪存控制器发送了0x1234。如果知道它应该处理这个请求,那么ller和或flash控制器就会把顶部切掉。0x00000000、0x0800000是地址空间的处理器视图,实际情况是对高位进行解码,并将请求路由到它所属的任何人,最终处理程序将查看低位以确定要寻址的内容。 就像你送一封信一样,信上有名字,街道地址,城市州邮政编码。一旦它以正确的状态到达正确的邮局,那么街道地址就是对邮政人员最重要的。一旦找到合适的房子,通常第一个名字就是最重要的,剩下的就可以忽略了。这里没有区别。地址的一部分(通常可以)变得不关心,因为负责检查该地址的逻辑将请求指向正确的一方。
ELF文件格式是通用的,对微控制器来说太过简单了,但是却得到了很好的支持,并且很容易使用。在加载内存地址中,程序员希望代码相对于处理器的世界视图存活。从readelf的角度来看,文件中的偏移量就是elf文件中该信息的偏移量,并且它就在工具放置它的任何位置,它没有其他有趣的关系。或者至少不需要。objcopy将把数据从文件中提取出来,对于-o二进制文件,将其放入一种内存映像文件中,其中被复制出来的最低地址是该文件中的偏移量0,大小由所有可加载块的总地址空间决定(除非使用更多的命令行参数)。正如您所暗示的,但是如果您考虑到它,并且有一个链接器脚本错误,如果您甚至有一条位于0x0800000的单指令和一个位于0x20000000的单字节的.data,但没有执行at>操作,那么您的文件尽管只有三个相关字节,但其长度将为0x20000001-0x0800000字节。(在-o二进制之后)在调试链接器脚本之前,最好不要将objcopy放在make文件中。假设有一个目标,其中flash是0x00000000,内存是0xE0000000,相当大的.bin文件,直到你得到链接器脚本。 |
![]() |
JeffreyH · 需要解释InvenSenses运动驱动程序 6 年前 |
|
gotti123 · 在MCU上查找Pin 6 年前 |
![]() |
frank_010 · 在32位字存储器中连续读取3个字节 7 年前 |
![]() |
LOSnel · 干扰irq将我从睡眠模式唤醒 7 年前 |
![]() |
Juliano · ili9341不处理STM32f4发现 7 年前 |
![]() |
yun · USB音频缓冲区欠载 7 年前 |
![]() |
puzzled · 全球结构不起作用[关闭] 7 年前 |
![]() |
Aimal · Elf十六进制表示法 7 年前 |
![]() |
girikks · 结构值未在主源文件中更新 7 年前 |
|
user8235882 · 未在操作系统C中执行的for循环 7 年前 |