Совместное использование кода между несколькими независимо скомпилированными двоичными / шестнадцатеричными файлами - PullRequest
3 голосов
/ 29 марта 2019

Я ищу документацию / информацию о том, как делиться информацией / кодом между несколькими двоичными файлами, скомпилированными для архитектур Cortex-m / 0/4/7. Два двоичных файла будут на одном чипе и той же архитектуре. Они вспыхивают в разных местах и ​​устанавливают указатель основного стека и сбрасывают счетчик программ, так что один двоичный файл «переходит» к другому двоичному. Я хочу поделиться кодом между этими двумя двоичными файлами.

Я сделал простое копирование массива указателей функций в раздел, определенный в скрипте компоновщика, в RAM. Затем считайте RAM из другого двоичного файла и приведите его к массиву, затем используйте индекс для вызова функций из другого двоичного файла. Это работает как доказательство концепции, но я думаю, что то, что я ищу, немного сложнее. Как я хочу некоторый способ описания совместимости между двумя двоичными файлами. Я хочу кое-что с функциональностью разделяемых библиотек, но я не уверен, что мне нужен независимый от позиции код.

Например, как выполняется текущий процесс копирования:

Исходный бинарный файл:

void copy_func()
{
   memncpy(array_of_function_pointers, fixed_size, address_custom_ram_section)
}

Двоичный файл, который тоже перепрыгивает из исходного двоичного файла:

array_fp_type get_funcs()
{
   memncpy(adress_custom_ram_section, fixed_size, array_of_fp)
   return array_of_fp;
}

Затем я могу использовать array_of_fp для вызова функций, находящихся в исходном двоичном файле из двоичного файла перехода.

Итак, я ищу некоторые ресурсы или материалы для тех, кто внедрил подобную систему. Как будто я не хотел бы иметь собственный раздел оперативной памяти, куда я копирую указатели функций.

Я бы согласился с этапом компиляции исходного двоичного файла, выводящего что-то, что может быть включено в этап компиляции двоичного файла перехода. Однако он должен быть воспроизводимым, и перекомпиляция исходного двоичного файла не должна нарушать совместимость с двоичным файлом перехода (даже если он включает файл, отличный от того, что выводится сейчас), если вы не измените интерфейс.

Для уточнения исходного двоичного файла не требуется каких-либо специальных знаний о двоичном файле перехода. Код не должен находиться в обоих двоичных файлах, поскольку это противоречит цели этого механизма. Общая цель, если этот механизм - это способ сэкономить место при создании мультибинарных приложений на процессорах cortex-m.

Любые идеи или ссылки на ресурсы приветствуются. Если у вас есть еще вопросы, не стесняйтесь комментировать вопрос, и я постараюсь ответить на него.

Ответы [ 2 ]

0 голосов
/ 30 марта 2019

Как объяснено в комментарии, мы могли бы представить приложение и загрузчик, полагаясь на одну и ту же динамическую библиотеку.Таким образом, приложение и загрузчик полагаются на библиотеку, приложение может быть изменено без ущерба для библиотеки или загрузки.

Я не нашел простого способа создать общую библиотеку с помощью arm-none-eabi-gcc.Однако этот документ дает некоторые альтернативы разделяемым библиотекам.В вашем случае я бы порекомендовал решение для таблицы переходов.

Напишите библиотеку с функциями, которые необходимо использовать в загрузчике и в аппликативном.

код "библиотеки"

typedef void (*genericFunctionPointer)(void)

// use the linker script to set MySection at a known address
// I think this could be a structure like Russ Schultz solution but struct may or may not compile identically in lib and boot. However yes struct would be much easyer and avoiding many function pointer cast. 
const genericFunctionPointer FpointerArray[] __attribute__ ((section ("MySection")))=
{
     (genericFunctionPointer)lib_f1,
     (genericFunctionPointer)lib_f2,
}

void lib_f1(void)
{
     //some code
}

uint8_t lib_f2(uint8_t param)
{
     //some code
}

аппликативный и / или код загрузчика

typedef void (*genericFunctionPointer)(void)

// Use the linker script to set MySection at same address as library was compiled
// in linker script also put this section as `NOLOAD` because it is init by library and not by our code
//volatile is needed here because you read in flash memory and compiler may initialyse usage of this array to NULL pointers
volatile const genericFunctionPointer FpointerArray[NB_F] __attribute__ ((section ("MySection")));

enum 
{
    lib_f1,
    lib_f2,
    NB_F,

}

int main(void)
{
    (correctCastF1)(FpointerArray[lib_f1])();
    uint8_t a = (correctCastF2)(FpointerArray[lib_f2])(10);
}
0 голосов
/ 29 марта 2019

Мне очень трудно представить, что вы хотите сделать, но если вы заинтересованы в наличии ссылки на приложение для вашего загрузчика / ПЗУ, см. Загрузка файла символов при ссылке для подсказкичто ты мог сделать.

Создайте свое «исходное» (?) Изображение, очистите его mapfile и создайте файл символов, а затем используйте его при связывании своего «прыжкового» (?) Изображения.

Это означает, что вынеобходимо связать ваше изображение «прыжок» с конкретной версией вашего «исходного» изображения.

Если вам нужно, чтобы они были независимыми от полуверсии (т.е. вы определяете набор экспортируемых функций, но вы можете перестроить их с любой стороны), то вам нужно экспортировать указатели функций в известные места в вашем "Исходное изображение и ссылка на эти функциональные указатели в вашем изображении «прыжка».Вы можете упростить бухгалтерию, сделав структуру указателей на функции доступными к функциям с обеих сторон.

Например:

shared_functions.h:

struct FunctionPointerTable
{
  void(*function1)(int);
  void(*function2)(char);
};

extern struct FunctionPointerTable sharedFunctions;

Источникфайл в «исходном» изображении:

void function1Implementation(int a) 
{
    printf("You sent me an integer:  %d\r\n", a);

    function2Implementation((char)(a%256)) 
    sharedFunctions.function2((char)(a%256));
}

void function2Implementation(char b) 
{
    printf("You sent me an char:  %c\r\n", b);
}

struct FunctionPointerTable sharedFunctions = 
{
    function1Implementation,
    function2Implementation,
};

Исходный файл в «исходном» изображении:

#include "shared_functions.h"

sharedFunctions.function1(1024);
sharedFunctions.function2(100);

Когда вы компилируете / ссылаетесь на «исходный код», возьмите его файл карты и извлеките местоположениеof sharedFunctions и создайте файл символов, который связан с исходным изображением «прыжка».

Примечание: printf s (или все, что напрямую вызывается совместно используемыми функциями) будет происходить из изображения «источника»(а не изображение "прыжка").

Если вам нужно, чтобы они исходили из изображения «jump» (или были переопределены), то вам нужно получить к ним доступ через ту же таблицу указателей функций, а изображение «jump» должно исправить таблицу указателей функцийс его версией соответствующей функции.Я обновил function1 (), чтобы показать это.Прямой вызов функции 2 всегда будет «исходной» версией.Его версия вызова совместно используемой функции будет проходить через таблицу переходов и будет вызывать версию «source», если только изображение «jump» не обновит таблицу функций, чтобы указать на ее реализацию.

Вы МОЖЕТЕ уйти от структуры,но затем вам нужно экспортировать указатели на функции один за другим (не большая проблема), но вы хотите сохранить их в порядке и в фиксированном месте, что означает явное размещение их в файле дескриптора компоновщика и т. д. и т. д. Я показалметод структуры, чтобы отогнать это до самого простого примера.

Как вы можете видеть, все становится довольно проблематично, и есть некоторый штраф (вызов через указатель функции медленнее, потому что вам нужно загрузить адрес, чтобы перейти к нему)

...