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

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

本文关键字:链接 构建 对象 程序 加载 单例 项目 共享 system calls      更新时间:2023-10-16

我正在尝试构建一个解决方案,其中将有两个项目:"bootloader"(在重置后启动并执行smth)和"mainApplication"从bootloader获得控制。

最初,我只是从这里复制了这个例子: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中,并以某种方式使内容不包含在最终二进制文件中吗?

此外,展望未来——如果谈论像所示的sum函数这样只使用堆栈的简单人员,这只是一个链接器问题,但如果我想创建一种"系统服务",比如说使用了一些堆的singleton对象,那么问题是——如果有什么好的方法可以在从bootloader传输控制时冻结该对象使用的堆部分,它被创建到主应用程序的位置,主应用程序应该使用它…

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

无论哪种方式,虽然可以使用某种链接器配置来管理您的需求,但链接器脚本通常是神秘的,并且不能在工具链之间移植。一个更简单的解决方案是创建一个向量表,其中填充了指向函数、类或对象的指针(尽管有以前的注意事项),并使用链接器和/或编译器链接器指令在ROM中的已知和保留位置定位表。同样的表位置也可以放在应用程序链接映射中。然后,通过将该表作为指针数组进行访问,为每个访问点提供一个已知的索引,就可以简单地提供入口点。

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

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

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