我正在寻找有关如何在针对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处理器上创建多二进制应用程序时节省空间。
欢迎任何想法或资源链接。如果您还有其他问题,请随时对此问题发表评论,我会尽力回答。
答案 0 :(得分:0)
我很难想象您想做什么,但是如果您有兴趣在Bootloader / ROM上建立应用程序链接,请参阅Loading symbol file while linking,以获取关于您可以做什么的提示。
构建“源”(?)图像,刮取其映射文件并制作符号文件,然后在链接“跳转”(?)图像时使用该图像。
这确实意味着您需要将“跳转”图像链接到“源”图像的特定版本。
如果您需要它们与半版本无关(即,您定义了一组导出的函数,但是可以在任一侧进行重建),则需要在“源”图像中的已知位置导出函数指针并链接到“跳转”图像中的那些函数指针。通过使函数指针的结构可以从任一侧访问函数,可以简化簿记。
例如:
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);
编译/链接“源”时,获取其映射文件并提取sharedFunctions的位置,并创建一个与源链接的“跳转”图像的符号文件。
注意:printf
(或共享函数直接调用的任何内容)将来自“源”图像(而不是“跳转”图像)。
如果您需要它们来自“跳转”图像(或可重写),则需要通过相同的函数指针表访问它们,并且“跳转”图像需要使用其指针修复函数指针表相关功能的版本。我更新了function1()来显示此内容。直接调用function2始终是“源”版本。它的共享函数调用版本将通过跳转表并调用“源”版本,除非“跳转”图像更新了函数表以指向其实现。
您可以脱离结构,但随后需要一个一个地导出功能指针(这不是一个大问题),但是您想要将它们保持在固定的位置并有序放置,这意味着将它们明确地放在其中链接器描述符文件等。我展示了将其提炼为最简单示例的结构方法。
如您所见,事情变得很繁琐,并且要付出一定的代价(通过函数指针进行调用会比较慢,因为您需要加载地址才能跳转到)
答案 1 :(得分:0)
正如评论中所解释的,我们可以想象一个应用程序和一个引导程序依赖于相同的动态库。因此,应用程序和引导程序依赖于库,可以在不影响库或启动的情况下更改应用程序。
我没有找到一种简单的方法来使用arm-none-eabi-gcc创建共享库。然而 this document为共享库提供了一些替代方案。对于您的情况,我建议使用跳转表解决方案。
编写一个库,其中包含需要在引导加载程序和应用程序中使用的功能。
“库”代码
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);
}
答案 2 :(得分:0)
您可以考虑使用链接器部分。如果您的引导加载程序源代码在文件夹引导加载程序中,则可以使用
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
}