我正在使用Codesourcerys GCC arm EABI编译器为Beagleboard(ARM Cortex A8)编译裸机软件(无操作系统)。现在,这将编译为二进制或图像文件,我可以使用U-Boot引导加载程序加载。
问题是,我可以在运行时动态地将十六进制数据加载到内存中(这样我可以将其他图像文件加载到内存中)吗?我可以使用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
看起来像这样:
0000000 e321f0d3 e3a00000 e59f1078 e59f2078
0000020 e4810004 e1510002 3afffffc e59f006c
0000040 e3c0001f e321f0d2 e1a0d000 e2400a01
0000060 e321f0d1 e1a0d000 e2400a01 e321f0d7
......等等。
是否只需将每行20个字节加载到所需的内存地址即可,只需将PC分支到正确的地址即可。我忘了什么吗?
答案 0 :(得分: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和.data位于内存中的适当位置0x20000000,但字节是由可执行文件(elf加载器或-O二进制文件等)加载的到.text的结尾。通常,您使用更多的linkerscript魔法来确定链接器执行此操作的位置。在启动时,您的.text代码应该首先将.bss归零并将.data从.text空间复制到.data空间,然后您就可以正常运行。
uboot可能会处理.bin之外的格式吗?编写一个提取二进制文件不同部分并生成自己的.bins的精灵工具也很容易,而不是使用objcopy。编写从不依赖.bss为零的代码也没有.data也很容易。解决所有这些问题。
答案 1 :(得分:2)
如果您可以在没有操作系统的情况下写入随机地址,那么使用一些随机十六进制转储格式是没有意义的。只需将二进制数据直接加载到所需的地址即可。从十六进制转换为二进制以便存储在内存中,无需购买任何东西。当然,您可以使用普通read()
或fread()
将二进制数据加载到任何地址。
如果您正在加载完整的ELF文件(或类似文件),您当然需要实现特定格式从对象加载器中期望的任何任务,例如为BSS数据分配内存,可能解决任何未解析的地址。代码(跳转等),等等。
答案 2 :(得分:1)
是的,可以在运行时写入内存(在嵌入式系统上)。
许多引导加载程序将数据从只读存储器(例如闪存)复制到可写存储器(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.
另外,搜索Stack Overflow“嵌入式C写入内存”