【问题标题】:What's the usecase of gcc's used attribute?gcc used 属性的用例是什么?
【发布时间】:2015-07-26 13:41:28
【问题描述】:
#include <stdio.h>

// xyz will be emitted with -flto (or if it is static) even when
// the function is unused

__attribute__((__used__))
void xyz() {
  printf("Hello World!\n");
}

int main() {
  return 0;
}

我需要这个做什么?

除了直接调用函数之外,我还能以某种方式访问​​xyz,就像魔术一样的dlsym()

【问题讨论】:

  • dlsym 不是您要找的答案吗?在问题中提及这样的答案令人困惑。
  • 我想你可以调用 xyz 隐藏在编译器不知道的内联汇编中。
  • @Potatoswatter:不,不是。 dlsym() 不适用于可执行文件,这就是我写“like some”的原因。
  • @Thomas 我很确定可执行文件本身可以dlopen
  • @melpomene:我试过了,但找不到符号。

标签: c++ c gcc clang icc


【解决方案1】:

属性used 在你想强制编译器发出符号的情况下很有帮助,通常它可以被省略。正如GCC's documentation 所说(强调我的):

这个属性,附加到一个函数,意味着代码必须是 为函数发出,即使看起来该函数不是 参考。这很有用,例如,当函数 仅在内联汇编中引用

例如,如果您有如下代码:

#include <iostream>

static int foo(int a, int b)
{
    return a + b;
}

int main()
{
   int result = 0;

   // some inline assembly that calls foo and updates result

   std::cout << result << std::endl;
}

您可能会注意到,-O 标志不存在符号 foo(优化级别 -O1):

g++ -O -pedantic -Wall check.cpp -c
check.cpp:3: warning: ‘int foo(int, int)’ defined but not used
nm check.o | c++filt | grep foo

因此,您无法在此(虚构的)内联程序集中引用 foo

通过添加:

__attribute__((__used__))

变成:

g++ -O -pedantic -Wall check.cpp -c
nm check.o | c++filt | grep foo
00000000 t foo(int, int)

因此现在可以在其中引用foo

您可能还发现 gcc 的警告现在消失了,因为您告诉编译器您确定 foo 实际上是在“幕后”使用的。

【讨论】:

  • 另一个用例,尤其是在 C++ 中,用于调试助手。例如,您可能有一个漂亮地打印内部对象的void dump() 方法。您不会在程序中的任何地方调用它,但您希望能够在调试器中暂停时调用它。 __attribute__((used)) 将确保它不会作为死代码被淘汰。
【解决方案2】:

一个特定的用例是静态库中的中断服务例程。 比如一个定时器溢出中断:

void __attribute__((interrupt(TIMERA_VECTOR),used)) timera_isr(void)

这个 timera_isr 永远不会被用户代码中的任何函数调用,但它可能构成库的重要组成部分。 为了确保它被链接并且没有指向空白部分的中断向量,关键字确保链接器不会对其进行优化。

【讨论】:

  • 我认为这不是真的。当您将 ISR 函数的地址放入中断向量表时,就会引用 ISR 函数。这可能会间接发生(例如,使用编译器特定的语法,例如 __attribute__((interrupt(X)))),但无需添加 __attribute__((__used__))
【解决方案3】:

如果你声明了一个未使用的全局变量或函数,gcc 会优化它(带有警告),但如果你用'__attribute__((used))' 声明了全局变量或函数,gcc 会将它包含在目标文件中(并链接可执行文件)。

https://gcc.gnu.org/legacy-ml/gcc-help/2013-09/msg00108.html

【讨论】:

    【解决方案4】:

    另一个用例是为头文件生成适当的覆盖信息。头文件中声明的函数通常在未引用时被编译器删除。因此,即使您忘记调用位于头文件中的某些函数,您的覆盖率报告也将获得 100% 的覆盖率。为防止这种情况发生,您可以在覆盖构建中使用 __attribute__((used)) 标记您的函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 2014-09-02
      相关资源
      最近更新 更多