Загрузка данных HEX в память - PullRequest
2 голосов
/ 19 марта 2012

Я собираю программное обеспечение (без ОС) для Beagleboard (ARM Cortex A8) с компилятором Codesourcerys GCC arm EABI. Теперь это компилируется в двоичный файл или файл образа, который я могу загрузить с загрузчиком U-Boot.

Вопрос в том, могу ли я динамически загружать hexdata в память во время выполнения (чтобы я мог загружать в память другие файлы изображений)? Я могу использовать gcc objcopy для генерации hexdump программного обеспечения. Могу ли я использовать эту информацию и загрузить ее по соответствующему адресу? Будут ли все адреса разделов .text .data .bss загружены правильно, как указано в сценарии компоновщика?

Вывод hexdata, сгенерированный

$(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 байтов для каждой строки в нужный адрес памяти, и все будет работать, просто разветвив ПК по правильному адресу? Я что-то забыл?

Ответы [ 3 ]

3 голосов
/ 19 марта 2012

когда вы используете -O двоичный файл, вы в значительной степени отказываетесь от .text, .data..bss control.Например, если у вас есть одно слово 0x12345678 по адресу 0x10000000, вызовите этот .text и одно слово .data по адресу 0x20000000, 0xAABBCCDD, и вы используете -O-двоичный файл, вы получите файл длиной 0x10000004 байта, который начинается с 0x12345678 и заканчивается 0xAABBCCDDи имеет 0x0FFFFFFC байтов нулей.попробуйте выгрузить это в чип, и вы можете стереть ваш загрузчик (uboot и т. д.) или уничтожить кучу регистров и т. д., не говоря уже о работе с потенциально огромными файлами и вечностью для передачи на плату в зависимости от того, как вы намереваетесьсделать это.

То, что вы можете сделать, что типично для загрузчиков на основе rom, - это использовать gcc tools

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.Обычно вы используете больше магии линкерскрипта, чтобы определить, где линкер сделал это.При загрузке ваш .text-код должен сначала обнулить .bss и скопировать .data из пространства .text в пространство .data, а затем вы сможете нормально работать.

uboot, вероятно, может обрабатывать форматы, отличные от .binда?Также довольно просто написать инструмент elf, который извлекает различные части двоичных файлов и создает ваши собственные .bins, не используя objcopy.Также довольно легко написать код, который никогда не полагается на ноль .bss и не имеет данных .data.решение всех этих проблем.

2 голосов
/ 19 марта 2012

Если вы можете писать по случайным адресам, не мешая операционной системе, нет смысла использовать какой-либо формат случайного шестнадцатеричного дампа. Просто загрузите двоичные данные прямо на нужный адрес. Преобразование на лету из шестнадцатеричной формы в двоичную для хранения в памяти ничего не дает. Вы можете загрузить двоичные данные на любой адрес, используя, конечно, read() или fread().

Если вы загружаете полноформатные файлы ELF (или аналогичные), вам, конечно, необходимо реализовать любые задачи, которые данный формат ожидает от загрузчика объектов, такие как выделение памяти для данных BSS, возможно разрешение любых неразрешенных адресов в код (прыжки и тому подобное) и т. д.

1 голос
/ 19 марта 2012

Да, можно выполнять запись в память (во встроенной системе) во время выполнения.

Многие загрузчики копируют данные из постоянной памяти (например, 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 в память»

...