是否有允许结构重新排序的 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 关键字?的主要内容,如果未能解决你的问题,请参考以下文章