多个独立编译的二进制文件/ hex文件之间的代码共享

问题描述 投票:3回答:2

我正在寻找有关如何在为Cortex-m / 0/4/7架构编译的多个二进制文件之间共享信息/代码的文档/信息。这两个二进制文件将位于同一芯片和相同的架构上。它们在不同的位置闪烁并设置主堆栈指针并重置程序计数器,以便一个二进制文件“跳转”到另一个二进制文件。我想在这两个二进制文件之间共享代码。

我已经将一个函数指针数组的简单副本完成到链接器脚本中定义到RAM中的部分。然后读取另一个二进制文件中的RAM并将其转换为数组,然后使用索引调用另一个二进制文件中的函数。这确实可以作为一个概念验证,但我认为我正在寻找的东西有点复杂。因为我想要一些描述两个二进制文件之间兼容性的方法。我想要一些共享库的功能,但我不确定我是否需要与位置无关的代码。

作为一个例子,当前的复制过程是如何完成的,它基本上是:

来源二进制:

void copy_func()
{
   memncpy(array_of_function_pointers, fixed_size, address_custom_ram_section)
}

从源二进制文件中跳过的二进制文件:

array_fp_type get_funcs()
{
   memncpy(adress_custom_ram_section, fixed_size, array_of_fp)
   return array_of_fp;
}

然后我可以使用array_of_fp从跳转二进制文件中调用驻留在源二进制文件中的函数。

所以我正在寻找的是为实施类似系统的人提供的一些资源或输入。就像我希望不必拥有自定义RAM部分,我将函数指针复制到其中。

我可以使用源二进制文件的编译步骤输出可以包含在跳转二进制文件的编译步骤中的内容。但是,它需要是可重现的,并且重新编译源二进制文件不应该破坏与跳转二进制文件的兼容性(即使它包含与现在输出的文件不同的文件),只要您不更改接口即可。

澄清源二进制文件不应该要求有关跳转二进制文件的任何特定知识。代码不应该驻留在两个二进制文件中,因为这会破坏此机制的目的。这个机制的总体目标是在cortex-m处理器上创建多重二进制应用程序时节省空间的方法。

欢迎任何想法或资源链接。如果您有任何其他问题,请随时评论该问题,我会尽力回答。

embedded cortex-m cortex-m3
2个回答
0
投票

我很难想象你想做什么,但是如果你对引导加载程序/ ROM的应用程序链接感兴趣,那么请参阅Loading symbol file while linking以获得有关你可以做什么的提示。

构建你的“源”(?)图像,抓取它的mapfile并制作一个符号文件,然后当你链接你的“跳转”(?)图像时使用它。

这意味着您需要将“跳转”图像与特定版本的“源”图像相关联。

如果您需要它们是半版本独立的(即您定义了一组导出的函数,但您可以在任何一侧重建),那么您需要在“源”图像中的已知位置导出函数指针并链接你的“跳转”图像中的那些函数指针。您可以通过使函数指针的结构通过任何一方访问函数来简化簿记。

例如:

shared_functions.h:

struct FunctionPointerTable
{
  void(*function1)(int);
  void(*function2)(char);
};

extern struct FunctionPointerTable sharedFunctions;

“源”图像中的源文件:

void function1Implementation(int a) 
{
    printf("You sent me an integer:  %d\r\n", a);

    function2Implementation((char)(a%256)) 
    sharedFunctions.function2((char)(a%256));
}

void function2Implementation(char b) 
{
    printf("You sent me an char:  %c\r\n", b);
}

struct FunctionPointerTable sharedFunctions = 
{
    function1Implementation,
    function2Implementation,
};

“跳转”图像中的源文件:

#include "shared_functions.h"

sharedFunctions.function1(1024);
sharedFunctions.function2(100);

编译/链接“源”时,获取其mapfile并提取sharedFunctions的位置,并创建一个与源“jump”图像链接的符号文件。

注意:printfs(或共享函数直接调用的任何东西)将来自“源”图像(而不是“跳转”图像)。

如果你需要它们来自“跳转”图像(或可以覆盖),那么你需要通过相同的函数指针表访问它们,并且“跳转”图像需要修复函数指针表及其版本的相关功能。我更新了function1()来显示这个。对function2的直接调用将始终是“源”版本。它的共享函数调用版本将通过跳转表并调用“源”版本,除非“跳转”图像更新函数表以指向其实现。

你可以远离结构,但是你需要逐个导出函数指针(不是一个大问题),但你想保持它们的顺序和固定位置,这意味着将它们显式地放在链接描述符中文件等等。我展示了结构方法,将其提炼到最简单的例子。

正如你所看到的,事情变得非常毛茸茸,并且有一些惩罚(通过函数指针调用较慢,因为你需要加载地址才能跳转到)


0
投票

正如评论中所解释的那样,我们可以想象一个应用程序和一个依赖于相同动态库的引导加载程序。因此应用程序和引导程序依赖于库,可以在不影响库或引导的情况下更改应用程序。

我没有找到一个简单的方法来使用arm-none-eabi-gcc来创建共享库。然而,this document提供了共享库的一些替代方案。我的情况,我建议跳转表解决方案。

编写一个库,其中包含需要在bootloader和applicative中使用的函数。

“库”代码

typedef void (*genericFunctionPointer)(void)

// use the linker script to set MySection at a known address
// I think this could be a structure like Russ Schultz solution but struct may or may not compile identically in lib and boot. However yes struct would be much easyer and avoiding many function pointer cast. 
const genericFunctionPointer FpointerArray[] __attribute__ ((section ("MySection")))=
{
     (genericFunctionPointer)lib_f1,
     (genericFunctionPointer)lib_f2,
}

void lib_f1(void)
{
     //some code
}

uint8_t lib_f2(uint8_t param)
{
     //some code
}

applicative和/或bootloader代码

typedef void (*genericFunctionPointer)(void)

// Use the linker script to set MySection at same address as library was compiled
// in linker script also put this section as `NOLOAD` because it is init by library and not by our code
//volatile is needed here because you read in flash memory and compiler may initialyse usage of this array to NULL pointers
volatile const genericFunctionPointer FpointerArray[NB_F] __attribute__ ((section ("MySection")));

enum 
{
    lib_f1,
    lib_f2,
    NB_F,

}

int main(void)
{
    (correctCastF1)(FpointerArray[lib_f1])();
    uint8_t a = (correctCastF2)(FpointerArray[lib_f2])(10);
}
© www.soinside.com 2019 - 2024. All rights reserved.