2012-03-18 169 views
2

我正在使用Codesourcerys GCC arm EABI编译器编译Beagleboard(ARM Cortex A8)的baremetal软件(无OS)。现在编译成一个二进制文件或图像文件,我可以使用U-Boot引导程序加载。将HEX数据加载到内存中

问题是,我可以在运行时动态加载hexdata到内存(这样我可以加载其他图像文件到内存中)?我可以使用gcc objcopy来生成一个hexdump的软件。我可以使用这些信息并将其加载到适当的地址吗?请按照链接器脚本中的说明正确加载.text .data .bss段的所有地址?通过

$(OBJCOPY) build/$(EXE).elf -O binary build/$(EXE).bin 
od -t x4 build/$(EXE).bin > build/$(EXE).bin.hex 

外观产生

的hexdata输出是这样的:

0000000 e321f0d3 e3a00000 e59f1078 e59f2078 
0000020 e4810004 e1510002 3afffffc e59f006c 
0000040 e3c0001f e321f0d2 e1a0d000 e2400a01 
0000060 e321f0d1 e1a0d000 e2400a01 e321f0d7 

...等等。

是否只需将每行20个字节加载到所需的内存地址,并且只需将PC分支到正确的地址即可工作?我忘了什么吗?

回答

3

当您使用-O二进制文件时,您几乎不会放弃.text,.data。 .bss控制。例如,如果在地址0x10000000处有一个单词0x12345678调用.text,并且在0x20000000,0xAABBCCDD处有一个单词为.data,并且您使用-O二进制,则将获得一个0x10000004字节长度的文件,该文件以0x12345678开始并以0xAABBCCDD结尾并具有0x0FFFFFFC字节的零。尝试将其转储到芯片中,并且可能会擦除引导加载程序(uboot等)或垃圾桶等等,更不用说处理潜在巨大的文件,并根据打算的方式将其永久转移到板上去做。

你可以做什么这是典型的基于ROM的引导程序,如果是使用gcc工具

MEMORY 
{ 
    bob : ORIGIN = 0x10000000, LENGTH = 16K 
    ted : ORIGIN = 0x20000000, LENGTH = 16K 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > bob 
    .bss : { *(.bss*) } > ted AT > bob 
    .data : { *(.data*) } > ted AT > bob 
} 

代码(的.text)将被链接仿佛.bss中和。数据是在其适当的位置在内存中,0x20000000,但字节由可执行文件(elf loader或-O binary等)加载到.text的末尾。通常情况下,你会使用更多的linkerscript魔术来确定链接器在哪里做到这一点。在启动时,您的.text代码应该首先将.bss清零,然后将.text从.text空间复制到.data空间,然后才能正常运行。

uboot可能可以处理.bin以外的格式是?编写一个精灵工具也很容易,该工具可以提取二进制文件的不同部分并创建自己的.bins文件,而不是使用objcopy。编写从不依赖于.bss为零且没有.data的代码也很容易。解决所有这些问题。

+0

我有点期待的是,随着连接器脚本我有过所有的部分应设完全控制。 Uboot使用loady命令为我加载这个文件。然而,我不知道如何加载我的软件后,在运行时加载另一个二进制文件的内容。只是阅读二进制文件的所有内容并将其加载到特定地址将不会工作,因为我从您的答案中了解到。猜猜我必须阅读一些精灵文件才能知道如何解析它! THx – MrGigu 2012-03-18 22:05:16

+1

如果你想让你的程序加载其他程序,是的,你需要制作一个加载程序。我建议intel hex格式首先或motorola srec,与objcopy -O ihex或-O srec,ascii格式,易于解析,并没有-O二元问题。 http://github.com/dwelch67我可能在模拟器中有多个intel十六进制解析器(再次超级简单)。请注意,对于每个目标类型的长度和地址定义以及ihex的末端更改,我不知道我为amber_samples做了什么,这基本上是arm,可能是ihex。 – 2012-03-18 22:36:14

+0

Thx,intel hex格式解决了问题!只需要转换数据的末端并将其解析为内存! – MrGigu 2012-03-20 19:53:13

2

如果你可以在没有操作系统阻碍的情况下写入随机地址,那么使用一些随机十六进制转储格式没有意义。只需将二进制数据直接加载到所需的地址即可。从十六进制转换为二进制存储在内存中并没有购买任何东西。当然,您可以使用普通的read()fread()将二进制数据加载到任何地址。

如果您正在加载完整的ELF文件(或类似文件),您当然需要实现特定格式期望从对象加载程序执行的任何任务,如为BSS数据分配内存,可能会解析任何未解析的地址代码(跳转等),等等。

1

是的,可以在运行时写入内存(在嵌入式系统上)。

许多引导程序将数据从只读存储器(例如Flash)复制到可写存储器(SRAM)中,然后将执行转移到该地址。

我曾参与其他系统,可以从一个端口(USB,SD卡)下载程序到可写内存,然后将执行转移到该位置。

我已经编写了从串口下载数据并将其编程到闪存(和EEPROM)器件中的函数。

对于内存到内存副本,请使用memcpy或自己写,使用指定了物理地址的指针。

为了将数据从端口复制到内存,找出如何从设备(如UART)获取数据,然后通过指针将数据从寄存器复制到所需的位置。

例子:

#define UART_RECEIVE_REGISTER_ADDR (0x2000) 
//... 
volatile uint8_t * p_uart_receive_reg = (uint8_t*) UART_RECEIVE_REGISTER_ADDR; 
*my_memory_location = *p_uart_receive_reg; // Read device and put into memory. 

而且,搜索栈溢出为“嵌入式C写内存”