使用函数指针消除 gcc 死代码

Posted

技术标签:

【中文标题】使用函数指针消除 gcc 死代码【英文标题】:gcc dead-code elimination with function pointers 【发布时间】:2014-10-28 20:32:31 【问题描述】:

我对链接器如何消除未使用的函数和数据段的死代码有一个初步的了解。如果您使用正确的编译器和链接器标志,它将每个函数和数据成员放入它自己的部分,然后当链接器去链接它们时,它会看到,如果没有直接引用,没有任何东西链接到该部分,然后它不会链接那个部分进入最后的精灵。

我正在尝试协调它与函数指针的工作方式。例如,您可以有一个函数指针,其值基于用户输入。可能不是一件安全的事情,但是编译器和链接器将如何处理呢?

【问题讨论】:

那不是垃圾回收,一般叫dead code eliminationen.wikipedia.org/wiki/Dead_code_elimination。 另请阅读 garbage collection 上的维基页面。实际上,GCC 有一个名为ggcinternal GC(相当糟糕的IMNSHO;MELT 有一个更好的,并且在gcc 内部运行),用于在编译时处理内部数据。与您的问题没有直接关系。 啊,对术语混淆感到抱歉。您传递给 gcc 的链接器标志是“--gc-sections”,所以这有点误导。我更新了问题。我的问题中提出的情况仍然存在。 【参考方案1】:

没有明确引用函数的情况下,没有可移植的方法来分配函数指针(例如,您不能对函数指针使用指针运算)。

因此,您的程序可访问的每个函数也必须在代码中命名和引用,链接器会知道它。甚至将函数指针存储在数组中,例如:

typedef void (*Callback)();
Callback callbacks[] =  foo, bar, baz ;

足以确保列出的函数将包含在链接的可执行文件中(数组内容将在加载时或链接时固定,具体取决于平台)。

【讨论】:

有趣,不知道。你能否将我链接到一些资源,解释为什么你不能用数学或任何其他方式分配函数指针,而不是显式引用函数?另外,数据段呢?我知道你可以使用指针算术来制作数据指针... 在大多数 POSIX 操作系统(例如 Linux)上,您可以在运行时使用 dlopen 加载插件并使用 dlsym 获取其中的一些函数符号;此类函数不是程序初始文本的一部分。 @NickHalden 问问自己如何使用算术定义函数指针。数据指针的指针算法依赖于编译器知道数据类型的大小。无法知道编译函数的大小或它们在内存中的顺序。它只是变成了后勤上的不可能。 这个答案不正确。事实上,可以为函数指针分配任意值或将整数转换为函数指针,但调用生成的函数指针可能是未定义的行为。 @FUZxxl:在问题的上下文中是正确的。当然,还有其他方法可以获得有效的函数指针,如 dlopen/dlsym 上的注释解释的,但是在链接时删除代码对于函数指针来说不是问题,因为没有可移植的方法来获取指向没有的函数的指针在源代码中明确引用。另请注意,即使仅设置具有无效值的指针(无需调用该函数),您也可以获得 UB;有一些硬件,只要在指针中设置一个错误的值就可能触发硬件陷阱。

以上是关于使用函数指针消除 gcc 死代码的主要内容,如果未能解决你的问题,请参考以下文章

C-函数,数组指针,指针之间的运算

在 gcc 上将成员函数指针传递给模板成员函数时出现问题

gcc 可以通过函数指针的常量数组内联间接函数调用吗?

gcc 编译错误,对象初始化解释为函数指针?

GCC C++14/17 成员函数指针模板参数的区别

MSVC 抱怨函数指针不是编译时常量