【问题标题】:Static Function vs Non-Static in Static Linking?静态链接中的静态函数与非静态?
【发布时间】:2021-10-20 06:00:17
【问题描述】:

我使用 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   

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

【问题讨论】:

  • “重新分配”为特定用途保留或分配新内存。您正在寻找的术语是“搬迁”;在各种链接和加载步骤中,代码和数据会重新定位到内存中。
  • @n.1.8e9-where's-my-sharem。我在ubuntu上试过了
  • 告诉我们GCC的版本很重要。
  • 我在一个重复的问题中得到了很好的答复:stackoverflow.com/a/69043406/7084

标签: c static linker elf static-linking


【解决方案1】:

您查看未解析的代码。

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

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

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

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

【讨论】:

  • 这不能回答我的问题...在第一种情况下,为什么符号没有被解析它是全局正确的,但它在当前文件中。
  • 在符号是全局的情况下,稍后在动态链接期间它可能会被覆盖。因此,即使编译器知道 this 翻译单元中 foo 的地址,它也无法知道最终是否应该调用该版本的 foo,并且必须为链接器保留重定位。
猜你喜欢
  • 1970-01-01
  • 2021-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多