Как построить и связать совместное использование проекта «системные вызовы» с загрузчиком в виде одноэлементного объекта? - PullRequest
0 голосов
/ 12 января 2019

Я пытаюсь создать решение, в котором будет два проекта: «загрузчик» (запуск после сброса и выполнение чего-либо) и «mainApplication», получающий элемент управления из загрузчика.

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

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

Ответы [ 2 ]

0 голосов
/ 12 января 2019

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

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

0 голосов
/ 12 января 2019

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

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

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

...