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

Embedded 多个独立编译的二进制文件/十六进制文件之间的代码共享,embedded,cortex-m,cortex-m3,Embedded,Cortex M,Cortex M3,我正在寻找关于如何在为Cortex-m/0/4/7体系结构编译的多个二进制文件之间共享信息/代码的文档/信息。这两个二进制文件将在同一个芯片和相同的体系结构上。它们在不同的位置闪烁,设置主堆栈指针并重置程序计数器,以便一个二进制“跳转”到另一个二进制。我想在这两个二进制文件之间共享代码 我将函数指针数组简单地复制到链接器脚本中定义的内存中。然后读取另一个二进制文件中的RAM并将其转换为数组,然后使用索引调用另一个二进制文件中的函数。这确实是一个概念证明,但我认为我要找的是一个更复杂的。因为我想用

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

我将函数指针数组简单地复制到链接器脚本中定义的内存中。然后读取另一个二进制文件中的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;
}
也从源二进制跳转的二进制:

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;
}
然后我可以使用_fp的
数组_从跳转二进制调用驻留在源二进制中的函数

所以我要找的是一些资源或是对那些已经实现了类似系统的人的投入。就像我不想有一个自定义的RAM部分,我要复制函数指针到其中

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

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


欢迎提供任何想法或资源链接。如果您还有任何问题,请随时对问题进行评论,我会尝试回答。

我很难想象您想要做什么,但是如果您有兴趣在您的引导加载程序/ROM上创建应用程序链接,请参阅,以获取有关您可以做什么的提示

构建“源”(?)图像,刮取其映射文件并生成一个符号文件,然后在链接“跳转”(?)图像时使用该文件

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

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

例如:

共享功能。h:

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

extern struct FunctionPointerTable sharedFunctions;
“源”图像中的源文件:

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

编译/链接“源”时,获取其映射文件并提取共享函数的位置,然后创建一个符号文件,该文件与“跳转”图像的源链接

注意:
printf
s(或共享函数直接调用的任何内容)将来自“源”图像(而不是“跳转”图像)

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

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


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

如注释中所述,我们可以想象应用程序和引导加载程序依赖于同一个动态库。所以应用程序和引导加载程序依赖于库,应用程序可以在不影响库或引导的情况下进行更改

我没有找到一种简单的方法来使用arm none eabi gcc实现共享库。然而 提供了一些共享库的替代方案。如果是你的情况,我建议使用跳转表解决方案

编写一个库,其中包含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
}
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);
}
应用程序和/或引导加载程序代码

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
}
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);
}

您可以研究如何使用链接器部分。如果在bootloader文件夹中有bootloader源代码,则可以使用

SECTIONS
{
    .bootloader:
    {
        build_output/bootloader/*.o(.text)
    } >flash_region1

    .binary1: 
    {
        build_output/binary1/*.o(.text)
    } >flash_region2

    .binary2:
    {
        build_output/binary2/*.o(.text)
    } >flash_region3 
}

我不太明白,也许你只是想把第一个程序编译成一个库,然后编译第二个程序,包括第一个库?也许可以解释为什么你想做这样的事情,这样我们就可以提出一个解决方案。我希望源二进制文件作为一个程序运行(可以作为库编译,但我不想编译成跳转二进制文件),因为一个要求是两者都可以单独编程,只是它们共享一些资源。因此,在某种程度上,你有一个带有网络堆栈(很大)的引导加载程序