与-GC链接链接时,海湾室高电平与函数的内线版本保持联系

发布于 2025-02-11 21:05:41 字数 1220 浏览 1 评论 0原文

编译器选项和-GC -S部分的组合来检测代码中未使用的功能

我想通过使用- ffumctions-sipes 。这是一个简单的复制器:

mylib.c:

int plusone(int a)
{
    return a + 1;
}

int myadd(int a, int b)
{
    int c = plusone(a);
    return c -1 +b;
}

main.c

#include <stdio.h>
#include "mylib.h"

int main(int argc, char*argv[])
{
    int a = 1;
    int b=3;
    printf("%d\n", myadd(a,b));
    return 0;
}

编译和链接脚本:

#!/bin/sh
gcc -c -o main.o -O2 -ffunction-sections -fdata-sections main.c
gcc -c -o mylib.o -O2 -ffunction-sections -fdata-sections mylib.c
gcc -o test  -Wl,--gc-sections,--print-gc-sections  main.o mylib.o

这是输出:

/usr/bin/ld: removing unused section '.rodata.cst4' in file '/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld: removing unused section '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld: removing unused section '.text.plusone' in file 'mylib.o'

从mylib.c的代码中,我们可以看到plusone函数尚未未使用,但是-print-gc - 节消息说明了相反。

它如何工作? GCC在Mylib.c内使用时是否会插入功能,如果在Mylib.c之外称为非衬里的副本,请保留非衬里的副本?

如何使该技术对于检测未使用的代码的目标更有用?

I would like to detect unused functions in my code by using the combination of -ffunctions-sections compiler options, and the --gc-sections,--print-gc-sections

However, it shows false positive. Here is a simple reproducer :

mylib.c :

int plusone(int a)
{
    return a + 1;
}

int myadd(int a, int b)
{
    int c = plusone(a);
    return c -1 +b;
}

main.c

#include <stdio.h>
#include "mylib.h"

int main(int argc, char*argv[])
{
    int a = 1;
    int b=3;
    printf("%d\n", myadd(a,b));
    return 0;
}

Compiling and linking script :

#!/bin/sh
gcc -c -o main.o -O2 -ffunction-sections -fdata-sections main.c
gcc -c -o mylib.o -O2 -ffunction-sections -fdata-sections mylib.c
gcc -o test  -Wl,--gc-sections,--print-gc-sections  main.o mylib.o

And here is the output :

/usr/bin/ld: removing unused section '.rodata.cst4' in file '/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld: removing unused section '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o'
/usr/bin/ld: removing unused section '.text.plusone' in file 'mylib.o'

From the code of mylib.c, we can see that the plusone function is NOT unused, yet the --print-gc-sections message tells the opposite.

How does it work ?
Is GCC inlining the function when used inside mylib.c, AND keeping a non inlined copy if it is called outside of mylib.c ?

How to make this technique more useful for the goal of detecting unused code ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

呆橘 2025-02-18 21:05:41

GCC在mylib.c内使用时是否会嵌入功能,如果在mylib.c?

的外部称为非衬里的副本

是的。如果您查看 mylib.o的拆卸 不调用plusOne(它们两个只是一个lea计算结果,然后是ret)。进行该功能调用的成本大于其中完成的工作(添加1实际上是大多数架构上的一种指令);设置呼叫堆栈并调用该功能比该功能要贵(x86-64,call指令单独lea 它将忽略处理参数设置等),因此,无论调用函数多少次,它都比集中实现更有效。但是它实际上无法删除实现,因为可以在以后的汇编阶段从另一个翻译单元调用它,因此它可以保持原本未使用的定义,以防万一。

如何使该技术对于检测未使用的代码的目标更有用?

这并不是编译器的工作。您可以将plusone声明为static,这意味着当它普遍嵌入时,它不会发出作为单独的函数(我已经在GCC 11.2上验证了这项工作,没有<<代码>静态我使用static获得您的演示输出单位需要它。 从某种意义上说,编译器 IS 检测未使用的代码;您声明了在翻译单元之外使用的函数,并且从未在翻译单元之外使用它,因此它是“未使用”的,并且可以具有其范围有限(使用statation),以避免广告宣传,但悬挂了悬挂的代码。

如果您对未使用的代码真的很偏执,那么无论如何,良好的静态纪律是一个好主意。尽管在这种情况下,无论如何,对于更复杂的功能,编译器可能更犹豫地嵌入非static函数,并且该功能也可以在翻译单元之外多次使用(因此,插入可能会在不节省任何空间的情况下膨胀代码,这可能会通过不共享相同的热代码来破坏处理器缓存)。如果是静态,则编译器不需要担心,并且可以更可靠地确定内衬是否有意义。

Is GCC inlining the function when used inside mylib.c, AND keeping a non inlined copy if it is called outside of mylib.c?

Yep. If you look at the disassembly of mylib.o, myadd does not call plusone (both of them are just a single lea computing the result, followed by a ret). The cost of making that function call is greater than the work done inside it (adding 1 is literally one instruction on most architectures); setting up a call stack and calling the function is more expensive than that (on x86-64, the call instruction alone is two bytes longer than the lea it would factor out, ignoring handling argument setup and the like), so no matter how many times the function is called, it would be more efficient to inline it than centralize implementation. But it can't actually remove the implementation since it might be called from another translation unit in a later compilation phase, so it keeps the otherwise unused definition, just in case.

How to make this technique more useful for the goal of detecting unused code?

That's not really the job of the compiler. You could declare plusone as static, which means it doesn't get emitted as a separate function when it's universally inlined (I've verified this works on gcc 11.2; without static I get your demonstrated output, with static it doesn't claim to be trimming .text.plusone), but this assumes nothing outside that translation unit needs it. In a sense, the compiler is detecting unused code; you declared a function for use outside the translation unit and never used it outside the translation unit, so it's "unused" and could have its scope limited (with static) to avoid advertised-but-unused code.

If you're really paranoid about unused code, good static discipline is a good idea anyway; while in this case inlining made sense no matter what, for more complex functions the compiler might be more hesitant to inline non-static functions and the function might also be used many times outside the translation unit (so inlining might bloat the code in the translation unit without saving any space, possibly ruining processor caches by not sharing the same hot code). If it's static, the compiler doesn't need to worry, and can more reliably determine if inlining makes sense or not.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文