Как построить и связать совместное использование проекта "системные вызовы" с загрузчиком в виде одноэлементного объекта?

Я пытаюсь создать решение, в котором будет два проекта: "загрузчик" (запуск после сброса и выполнение чего-л.) И "основное приложение", получающее управление из загрузчика.

Первоначально я только что воспроизвел пример отсюда: https://visualgdb.com/tutorials/arm/bootloader/

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

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

Модифицированный пример из учебника выглядит так:

Загрузчик:



//sys.h

class SysCalls
{
public:
    SysCalls();
    int sum(int, int);
};



//sys.cpp

#include "sys.h"

SysCalls::SysCalls()
{
}

int SysCalls::sum(int a, int b)
{
    return a + b;
}


// main.cpp

#include <sys.h>

...

SysCalls _sys;

void *g_Syscalls[] __attribute__((section(".syscalls"))) = { (void *)&_sys };



Основное применение:

//main.cpp

#include <sys.h> // the same header as in bootloader

extern "C" void *g_Syscalls[];

SysCalls *_sys = (SysCalls*) g_Syscalls[0];

int main(void)
{

...

    int sum = _sys->sum(1, 2);
...



Я получаю ошибку компоновщика:

undefined reference to `SysCalls::sum(int, int)'

что предсказуемо, но...

Интересно, есть ли хороший способ построить это? какой-нибудь конфиг линкера? или я должен также включить sys.cpp в mainApplication и сделать так, чтобы содержимое не было каким-либо образом включено в окончательный двоичный файл?

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

2 ответа

Решение

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

В любом случае, хотя для управления вашими требованиями можно использовать какую-то конфигурацию компоновщика, сценарии компоновщика часто бывают загадочными и не переносимы между цепями инструментов. Более простым решением было бы создать векторную таблицу, заполненную указателями на ваши функции, классы или объекты (несмотря на предыдущие предостережения), и использовать директивы компоновщика и / или компоновщика компилятора, чтобы найти таблицу в ПЗУ в известном и зарезервированном месте, То же самое местоположение таблицы может быть затем помещено в карту ссылок вашего приложения. Ваши точки входа затем просто обеспечиваются путем доступа к этой таблице в виде массива указателей с известным индексом для каждой точки доступа.

Векторы не обязательно должны быть указателями на функции, их можно интерпретировать (путем приведения) как указатель на любую сущность. Снова драгоценные предостережения о валидности объекта в контексте приложения.

Этот подход используется многими компонентами программного обеспечения промежуточного программного обеспечения. Одним из примеров является промежуточное программное обеспечение SoftDevices BT NRF. В сценариях компоновщика он дает некоторое ОЗУ для статических объектов и некоторое пространство для локального стека. "Основная" программа исключает эту оперативную память из памяти (область флэш-памяти, занятая SDev, также исключается). Это работает очень хорошо.

Это не настоящий загрузчик - загрузчик - это отдельное существо, имеющее доступ к SDev), поскольку загрузчик NRF поддерживает OTA

Другие вопросы по тегам