是否有允许结构重新排序的 GCC 关键字?

Posted

技术标签:

【中文标题】是否有允许结构重新排序的 GCC 关键字?【英文标题】:Is there a GCC keyword to allow structure-reordering? 【发布时间】:2013-01-18 05:43:18 【问题描述】:

我知道为什么 GCC 默认不重新排序结构的成员,但我很少编写依赖于结构顺序的代码,那么有什么方法可以标记我的结构以自动重新排序?

【问题讨论】:

@H2CO3 因为我在一个内存紧张的系统上,我总是必须手动计算以确保使用最少的填充量。 @Joshua 您的架构是否允许未对齐的内存访问? @duDE:联合和结构是完全不同的东西。 @cnicutar 我相信是这样,但是将它们转换为打包结构并不是答案,因为它只会删除填充,但不会重新排序以获得最佳内存对齐。我想要我手动执行的操作:内存与最少的填充对齐。 @Joshua 哦,我明白了。你想吃蛋糕并吃掉它。也许您可以预处理(flex ?)您的文件并重新排列成员。 【参考方案1】:

以前的 GCC 版本具有 -fipa-struct-reorg option 以允许在 -fwhole-program + -combine 模式下重新排序结构。

-fipa-struct-reorg

进行结构重组优化,改变类C结构布局,以更好地利用空间局部性。这种转换对包含结构数组的程序有效。有两种编译模式可用:基于配置文件(使用-fprofile-generate 启用)或静态(使用内置启发式)。要求-fipa-type-escape 提供此转换的安全性。它仅在整个程序模式下有效,因此需要启用-fwhole-program-combine。被此转换视为'cold' 的结构不受影响(请参阅--param struct-reorg-cold-struct-ratio=value)。

由于release note 中的以下原因,它从 GCC 4.8.x 开始被删除

结构重组和矩阵重组优化(命令行选项-fipa-struct-reorg-fipa-matrix-reorg)已被删除。它们并不总是能正常工作,也不能与链接时优化 (LTO) 一起工作,因此仅适用于由单个翻译单元组成的程序。

但是,您仍然可以在GCC SVN 上尝试struct-reorg-branch 或github mirror,风险自负,因为它仍在积极开发中。

您还可以使用clang-tools-extra 中的clang-reorder-fields 工具对字段重新排序

另见

Automated field re-ordering in C structs to avoid padding

【讨论】:

【参考方案2】:

附带说明一下,Linux 内核实现了一个 gcc plugin 来引入一个名为 randomize_layout 的属性。目标是在结构的定义中使用它,以使编译器随机化字段的顺序。 Linux 内核将其用于the sake of security 以应对需要了解结构布局的攻击。例如cred结构在include/linux/cred.h中定义如下:

struct cred 
    atomic_t    usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
    atomic_t    subscribers;    /* number of processes subscribed */
    void        *put_addr;
[...]
    struct user_struct *user;   /* real user ID subscription */
    struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
    struct group_info *group_info;  /* supplementary groups for euid/fsgid */
    /* RCU deletion */
    union 
        int non_rcu;            /* Can we skip RCU deletion? */
        struct rcu_head rcu;        /* RCU deletion hook */
    ;
 __randomize_layout;

__randomize_layout 标签在 Linux 源代码树的 include/linux/compiler-gcc.h 中定义为:

#define __randomize_layout __attribute__((randomize_layout))

【讨论】:

【参考方案3】:

GCC 中没有这样的选项。而且,我敢肯定,它不能以任何明智的方式介绍。关于padding优化请看this discussion。

我知道的唯一例外是热/冷结构字段拆分,这在某些情况下可以完成(我仍然不确定,即使在配置文件引导模式下,GCC 也可以做到这一点,我知道 ICC 可以)。此功能不受用户控制,而是在调用图上执行,这种转换对数据流的保守性是可证明的。

【讨论】:

为什么不能引入?如果我指定 __packed 属性,我会告诉 GCC 以不同的方式威胁结构,那么 __reorder 属性会有什么问题?但似乎我的问题与您链接的问题重复。 @Joshua 从内存中,C 标准指定struct 成员在内存中的顺序必须与定义中的顺序相同。使用packed 属性可以保留顺序。重新排序属性不会。我意识到这不是关于标准合规性的讨论。 我认为无法引入它的原因更深层次,然后只是标准合规性。至少我们不太关心打包结构、嵌套函数等。但是打包取决于用户。重新排序由编译器决定如何重新排序以及是否重新排序。因此,在引入时,需要对字段进行可能的重新排序、准确的指向分析以重新排序所有引用以及对引用的引用等等。这可能会使编译时间增加数倍。 @KonstantinVladimirov 这不仅仅是标准合规性。 C 和 C++ 程序通常由许多不同的源文件和库构建。编译库后,您无法更改顺序或包装。而且您不希望在不同模块的同一结构中具有不同顺序的成员。 “热/冷结构字段拆分”技术真的很有趣:)【参考方案4】:

我认为在编译整个程序时可以重新组织/拆分 struct 的元素(lto 模式,使用 -flto 标志)。在这种情况下,您对程序有完整的了解,对于不会转义的符号,应该可以重新排序它们以获得更好的缓存行为等。

在 gcc 主干中,这正在积极开发中。这是在 GNU cauldron 2015 中提出的。您可能想尝试 gcc trunk 或 struct-reorg-branch。

https://gcc.gnu.org/wiki/cauldron2015?action=AttachFile&do=view&target=Olga+Golovanevsky_+Memory+Layout+Optimizations+of+Structures+and+Objects.pdf

【讨论】:

以上是关于是否有允许结构重新排序的 GCC 关键字?的主要内容,如果未能解决你的问题,请参考以下文章

数据结构-排序(Golang)

数据结构 第八章学习小结

数据结构第八章小结

数据结构_内排序总结

[数据结构]八大排序算法(C语言)

数据结构(11)_排序