首页 > 解决方案 > 静态链接中的静态函数与非静态?

问题描述

我使用 C 编写了以下 2 个程序:

第一的:

int foo(int x)
{
    return 1;
}

int main()
{
    return foo(4);
}

第二:

static int foo(int x)
{
    return 1;
}

int main()
{
    return foo(4);
}

然后我跑了:

gcc -c my_file.c

对于我看到的第一个文件(不是完整的输出):

000000000000000e <main>:
   e:   55                      push   %rbp
   f:   48 89 e5                mov    %rsp,%rbp
  12:   bf 04 00 00 00          mov    $0x4,%edi
  17:   e8 00 00 00 00          callq  1c <main+0xe>
  1c:   5d                      pop    %rbp
  1d:   c3                      retq   

对于第二个:

000000000000000e <main>:
   e:   55                      push   %rbp
   f:   48 89 e5                mov    %rsp,%rbp
  12:   bf 04 00 00 00          mov    $0x4,%edi
  17:   e8 e4 ff ff ff          callq  0 <foo>
  1c:   5d                      pop    %rbp
  1d:   c3                      retq   

我的问题是,为什么在第一个文件中当函数在当前文件中定义(而不仅仅是声明)时我们需要重定位?这对我来说听起来太奇怪了。

标签: cstaticlinkerelfstatic-linking

解决方案


您查看未解析的代码。

第一个版本是foo()全局的,因此在适当的表、符号和重定位中有条目,列表中没有显示。<编辑>很可能是因为编译器是这样工作的,当它发出对全局函数的调用时,它会在地址字段中放置零(或其他任何东西)。这个全局函数在同一个翻译单元中并不重要。使用其他选项或其他版本的编译器或其他编译器调用可能会产生不同的结果。< /Edit >

在第二个版本中,编译器知道这foo()是本地的并立即解析调用,而无需生成重定位条目。

如果链接程序,调用将被解析为相等的值。

<编辑>有趣:我尝试在 Windows 上使用 GCC 8.1.0 (MinGW-W64) 重现此问题,并且两个调用都由编译器解析。但是,对于当前 Manjaro Linux 的 GCC 11.1.0,它会显示所描述的行为。< /Edit >


推荐阅读