如何构建和 link 项目共享 "system calls" 到引导加载程序作为单例对象?

How to build and link project sharing "system calls" to bootloader as a singleton object?

我正在尝试构建一个解决方案,其中有两个项目:'bootloader'(在重置后启动并执行 smth)和 'mainApplication' 从引导加载程序获取控制权。

最初我只是从这里复制了这个例子: https://visualgdb.com/tutorials/arm/bootloader/

本教程的最后一部分描述了 "system call" - 将指向驻留在引导加载程序中的某个函数的指针传递给主应用程序,然后从那里调用该函数。

目的不是传递指向函数的指针,而是传递指向 class.

对象的指针

教程中的修改示例如下所示:

引导程序:



//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 中,并以某种方式使内容不包含在最终二进制文件中?

另外,期待 - 如果谈论像显示的求和函数这样的简单工作人员,它只使用堆栈,那只是一个链接器问题,但如果我想创建一种 'system service',比如单例对象如果有一些堆使用,那么问题是 - 如果有任何好的方法来冻结从引导加载程序转移控制时该对象使用的堆部分,它是在主应用程序中创建的,应该使用它...

指向具有由引导加载程序实例化的数据成员的对象 的指针在应用程序中是无效的,除非引导加载程序的 RAM 是永久分配的而不是被应用程序重用。它本身需要 linker 进行内存分区。在没有这种内存分区的情况下,唯一有效的 class 类型是包含不使用静态数据的静态成员函数的类型,因此指向class 将有一个指向 collection if 函数的指针(这可能并非没有优点)。

无论哪种方式,虽然可以使用某种 linker 配置来管理您的需求,linker 脚本通常是神秘的并且不适合 table工具链。一个更简单的解决方案是创建一个 向量 table 并填充指向您的函数、classes 或对象的指针(尽管有先前的警告),并使用linker and/or 编译器 linker 指令将 table 定位到 ROM 中已知的保留位置。同样的 table 位置也可以放置在您的应用程序 link 地图中。然后通过访问 table 作为指针数组来简单地提供您的入口点,每个访问点都有一个已知的索引。

向量不必是指向函数的指针,您可以(通过强制转换)将它们解释为指向任何实体的指针。尽管有关于应用程序上下文中对象有效性的宝贵警告。

许多中间件软件组件都使用这种方法。示例之一是 SoftDevices BT NRF 中间件。在链接器脚本中,它为静态对象提供了一些 RAM,也为本地堆栈提供了一些 space。 "main" 程序已将此 RAM 排除在外(SDev 占用的闪存区域也被排除在外)。效果很好。

它不是真正的引导加载程序——引导加载程序是一个单独的存在,可以访问 SDev)因为 NRF 引导加载程序支持 OTA