如何在多核项目中手动(以编程方式)放置对象?

时间:2011-12-07 20:35:42

标签: c gcc linker embedded multicore

我正在使用gnu工具链为embedded architecture开发一个mutlicore项目。在此架构中,所有独立内核共享相同的全局平面内存空间。每个内核都有自己的内部存储器,可通过其全局32位地址从任何其他内核寻址。

没有实现操作系统,我们进行低级编程,但在C而不是汇编。每个核心都有自己的可执行文件,使用单独的编译生成。我们用于核间通信的当前方法是通过计算目标核心数据空间中对象的绝对地址。如果我们为所有核心构建相同的代码,则链接器将对象放在同一位置,因此访问远程核心中的对象只是改变当前核心中对象地址的高位,进行交易。类似的概念允许我们共享位于外部DRAM中的对象。

事情开始变得复杂:

  1. 两个核心的代码不一样,因此对象可能不会在类似的地址中分配,

  2. 我们有时使用“主机”,这是另一个运行某些控制代码的处理器,需要访问核心中的对象,以及外部存储器中的共享对象。

  3. 为了克服这个问题,我正在寻找一种在构建时放置变量的优雅方法。我想避免尽可能更改链接描述文件。但是,似乎在C级别,我只能控制放置使用section属性(太粗糙)和align属性(不保证确切)的组合位)。

    可能的hack是使用内联汇编来定义对象并显式放置它们(使用.org.global关键字),但它看起来有点难看(我们还没有真正测试过这个想法...)

    所以,这是问题:

    1. 是否存在半标准方式或手动将对象放入C程序的优雅解决方案?

    2. 我可以在代码中声明一个“uber”-extarnel对象,并使链接器使用另一个项目的可执行文件解析其地址吗?

    3. This question描述了类似的情况,但用户引用了预先分配的资源(如外围设备),其地址在构建时间之前已知。

4 个答案:

答案 0 :(得分:3)

也许你应该尝试使用新运营商的'placement'标签。更确切地说,如果您已经分配/共享内存,则可以在其上创建新对象。请参阅:create objects in pre-allocated memory

答案 1 :(得分:2)

您没有确切地说明您要分享哪种数据,但假设它主要是固定大小的静态分配变量,我会将所有数据放在一个结构中并仅共享。

这里的关键点是这个结构必须是共享代码,即使其他程序不是。可以附加额外的字段(可能带有版本字段,以便读者可以正确解释它),但不能删除或修改现有字段。结构已经被用作各地库之间的接口,因此可以依赖它们的布局(尽管在异构环境中需要更多的关注,只要类型大小和对齐方式相同,你应该没问题。)< / p>

然后您可以通过以下任一方式共享结构:  a)将它们放在一个特殊的部分,并使用链接描述文件将它放在一个已知的位置;  b)在静态数据中分配结构,并将指针放在已知位置,例如在程序集启动文件中;要么  c)as(b),但在堆上分配struct,并在运行时将指针复制到已知的指针位置。它的优点是可以为外部消费者预先调整指针,从而避免一定程度的混乱。

希望有所帮助

答案 2 :(得分:1)

  1. 你在这里走得很远 - 不要指望任何一个'标准':)
  2. This answer建议将原始地址列表传递给链接器的方法。链接外部可执行文件时,生成链接器映射文件,然后处理它以生成此原始符号表。
  3. 您还可以尝试将整个程序(所有核心程序)链接到一个可执行文件中。使用节定义和链接描述文件将每个内核程序放入其内部存储器地址空间;您可以单独构建每个核心程序,逐步将其链接到单个.o文件,然后使用objcopy重命名其部分以包含链接描述文件的核心ID,如果要复制相同的代码,则使用rename (hide) private symbols多核。最后,手动将每个内核的起始地址提供给引导代码,而不是使用正常的起始符号。

答案 3 :(得分:1)

对问题1的回答:不,没有。

至于其余部分,它很大程度上取决于您使用的操作系统。在我嵌入时的系统中,我们只有一个处理器的内存可以处理(基于80186和68030),但是具有多任务但是来自相同的二进制文件。我们的工具链得到了扩展,以某种方式处理内存。 工具链看起来像那样(在80186上):

  • Microsoft C 16bit或Borland-C
  • 链接到我们特定的crt.o的链接器,它定义了一些特殊的符号和段。
  • Microsoft链接器,生成具有MS-DOS地址架构的exe和映射文件
  • 调整可执行文件中的地址并生成平面二进制文件的定位器
  • 地址修补程序。
  • EPROM刻录机(后来是Flash加载程序)。

在我们的程序集中,我们定义了一个始终位于数据段开头的符号,并使用来自定位映射文件的硬编码值修补二进制文件。这允许库将所有剩余的内存用作堆。

事实上,如果你没有对定位器(linux上的elf加载器或windows中的exe / dll加载器)的控制,你就搞砸了。