【问题标题】:__attribute__((section("name"))) usage?__attribute__((section("name"))) 用法?
【发布时间】:2013-08-23 05:12:10
【问题描述】:

我已经浏览过使用 _ attribute _((section("name")) 的代码。我知道对于 gcc 编译器,这允许您告诉链接器将创建的对象放在特定节“名称”(在链接器文件中声明了“名称”绝对地址)。

这样做而不是仅仅使用 .data 部分有什么意义?

【问题讨论】:

  • 这是因为那是我正在处理的代码的平台。我知道这个____attribute____ 仅在某些平台上可用,因此为了清楚起见,我想将其包含在内。我试图了解编码器将某些对象划分为测试对象、跟踪对象等时的意图。
  • 我删除了 ARM 部分,因此更清楚的是我并不特别关心 ARM,只关心用法。

标签: c gcc linker


【解决方案1】:

有许多可能的用途。 [编辑添加注释:这只是我自己看到或考虑过的使用示例,不是完整列表。]

例如,Linux 内核将一些代码和数据部分标记为仅在内核引导期间使用。这些可以在内核运行后丢弃,回收空间用于其他用途。

您可以使用它来标记需要在特定处理器变体上修补的代码或数据值,例如,有或没有协处理器。

您可以使用它来使事物存在于“特殊”地址空间中,这些地址空间将被烧录到 PROM 或保存在 EEPROM 中,而不是在普通内存中。

您可以使用它来收集代码或数据区域以用于初始化和清理等目的,例如在程序启动之前和结束时运行的 C++ 构造函数和析构函数,或者用于使用较短的寻址模式(我不知道多少适用于 ARM,因为我自己没有编写任何 ARM 代码)。

实际使用取决于链接描述文件。

【讨论】:

  • 其他用途是 hotcold 用于 cache locality。您还可以划分功能,如中断处理、调度等。即使例程/功能可能在一个“C”文件中,典型的执行路径也可以通过分组调用堆栈受益。一些代码可能从 flashinternal ram 执行。这些资源可能是有限的,等等。
  • @torek 关于为初始化/清理收集代码/数据区域的最后一点,这实质上意味着我可以选择在程序启动之前包含代码,但在运行时而不是编译时?有点像#ifdef 的更好版本?
  • 我不确定你在这里问的是什么。如果您编写的链接描述文件包含了一些部分而丢弃了其他部分,您可以在 link 时包含或排除部分。在 run 时做事需要协调你的链接器脚本和你的运行时代码,而且要困难得多。
  • 这对我来说是个糟糕的问题。当你说这是在 link 时间内完成时,我现在明白了。谢谢。
【解决方案2】:

从用例的角度来看,.data 有很多不同类型,例如:

  • 特定 CPU 和/或 NUMA 节点的本地数据
  • 上下文之间共享的数据(如用户/内核空间,.vdsovsyscall 页面。或者,另一个示例,引导加载程序和内核)
  • 只读数据或具有特定访问模式/类型限制的其他数据(例如,可缓存性或缓存驻留 - 后者可以在某些 ARM SoC 上指定)
  • 持续“状态转换”的数据(例如休眠图像加载,或崩溃内核/快速重启重新初始化)
  • 具有特定生命周期/生命周期的数据(仅在启动或操作期间的特定阶段使用,一次写入数据)
  • 特定内核子系统或特定内核模块的特定数据
  • “代码并置”数据(x64 中的寻址偏移量为正/负 2GB,因此如果您想要RIP-相对寻址,数据必须在当前执行代码的范围内)
  • 数据映射到某些特定的硬件寄存器空间 VA 范围

所以最后通常是关于 attributes(这里使用的这个词比__attribute__(...) 更通用,允许您从 gcc 源代码中声明。是否需要另一个部分和/或有用的是......在旁观者的眼中 - 系统设计师,即。

因此,section 属性的可用性允许灵活性,也就是说,恕我直言,这是一件好事。

【讨论】:

    【解决方案3】:

    多年后,我将添加一个具体的细节,因为它值得写下来。

    如果您创建自己的部分,则可以自行管理。特别是,您可以使用预处理器宏将某些数据项插入您的特殊部分。如果唯一使用该特殊部分的是您的预处理器宏,那么您就有能力以分布式方式创建数据结构。

    这是什么意思?这意味着您可以编写一个像ADD_VAR_TO_SPECIAL_SECTION(...) 这样的预处理器宏,并在您的部分中将一堆不同的值以随机顺序连接成一个数组(或者只是一个大的旧堆,如果它们不是相同的类型)。

    这使您能够在编译时创建一个(随机排序的)数据数组没有初始化,没有注册,没有开销。您只需编译并链接您的代码,所有不同源文件中的所有宏都将它们的所有值添加到一个大数组中。

    你怎么能用这个?创建一堆“模块”。在 ad-hoc 数组中注册初始化函数和销毁函数。在启动时处理阵列。 (如果需要,您可以添加某种拓扑排序。)您不需要在任何地方都有模块的主列表,它会自动构建。 或者, 创建一个宏来将单元测试功能注册到测试套件中。同样,它会创建一个不需要“注册”的临时列表。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 2016-03-31
      • 2021-01-19
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多