-3

我正在尝试构建一个解决方案,其中将有两个项目:“引导加载程序”(在重置后开始并执行 smth)和“主应用程序”从引导加载程序获取控制。

最初我刚刚从这里复制了这个例子: 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 函数,它只使用堆栈,这只是一个链接器问题,但如果我想创建一种“系统服务”,比如使用一些堆的单例对象,那么问题是 - 如果有任何好的方法可以在将控制权从引导加载程序转移到主应用程序时冻结该对象使用的堆部分,主应用程序应该使用它......

4

2 回答 2

1

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

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

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

于 2019-01-12T08:58:07.020 回答
0

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

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

于 2019-01-12T10:29:10.813 回答