我知道为什么GCC默认情况下不会重新排列结构体的成员,但我很少编写依赖于结构体顺序的代码,因此有没有一种方式可以标记我的结构体以便自动重排?
我知道为什么GCC默认情况下不会重新排列结构体的成员,但我很少编写依赖于结构体顺序的代码,因此有没有一种方式可以标记我的结构体以便自动重排?
之前的GCC版本有-fipa-struct-reorg
选项,可以在-fwhole-program
+ -combine
模式下允许结构重排。
-fipa-struct-reorg
执行结构重新组织优化,改变类C结构的布局以更好地利用空间局部性。此转换对包含结构数组的程序有效。有两种编译模式可用:基于配置文件的(使用
-fprofile-generate
启用)或静态的(使用内置启发式算法)。需要-fipa-type-escape
来提供此转换的安全性。它仅在整个程序模式下工作,因此需要启用-fwhole-program
和-combine
。被此转换视为“冷”的结构不受影响(请参见--param struct-reorg-cold-struct-ratio=value
)。
由于以下原因,在GCC 4.8.x中已将其删除,详见发布说明:
结构体重组和矩阵重组优化(命令行选项
-fipa-struct-reorg
和-fipa-matrix-reorg
)已被移除。它们并不总是能够正常工作,也不能与链接时优化(LTO)一起使用,因此只适用于由单个翻译单元组成的程序。
然而,您仍可以在GCC SVN上尝试使用struct-reorg-branch
或github镜像进行自己的风险评估,因为它仍在积极开发中。
您还可以使用clang-tools-extra中的clang-reorder-fields工具重新排序字段。
另请参见
randomize_layout
的属性,通过使用gcc插件来引入它。其目的是在结构的定义中使用它,使编译器随机排列字段的顺序。Linux内核在安全性方面使用它,以抵御需要知道结构布局的攻击。例如,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))
在GCC中没有这样的选项。而且,我确定它不能以任何明智的方式引入。关于填充优化,请参考此讨论。
我知道的唯一例外是热/冷结构字段拆分,在某些情况下可以实现(即使在基于配置文件指导的模式下,我也不确定GCC能否做到这一点,我知道ICC可以)。此功能不受用户控制,并在调用图上执行,其中对数据流的保守性可证明。
我认为在编译整个程序时(使用lto模式,使用-flto标志),重新组织/拆分结构的元素是可能的。在这种情况下,您可以获得程序的完整图片,并且对于未逃逸的符号,应该可以重新排序它们以获得更好的缓存行为等。
在gcc主干中,这正在积极开发中。这在GNU cauldron 2015中展示过。您可能想尝试gcc主干或struct-reorg-branch。