0

auto链接器是否链接了内部标识符(例如局部变量标签)?

(根据我目前的知识,他们不是。我想问“我对吗?”)

还有一件事:
- 说“所有具有非文件范围的东西都不会被链接器链接”是否正确?

4

3 回答 3

4

通常自动/局部变量位于寄存器或堆栈中,因此不需要任何链接。然而,可以想象,在某些堆栈有限的体系结构上,非递归(直接或间接)函数的自动/局部变量会从函数中取出并放置在全局内存中。当然,该功能也不会再进入。在这种情况下,将为此本地生成一个符号,该符号将由链接器解析。同样考虑以下示例:

int f(void)
{
        static int v = 0;
        return v++;
}

尽管范围v仅限于函数f,但它仍然会导致全局符号(很可能)由链接器解析。我说“最有可能”,因为编译器也有可能将static全局变量组合在一起,并通过指向组基数的指针加上偏移量来引用它们。从而节省了过于频繁地加载符号的地址。

您的陈述大致成立,但也有例外,它可能取决于编译器和体系结构。

标签通常由链接器处理,即使它们没有导出链接。

编辑:考虑到乔纳森的观察,您可能指的是标识符的实际名称,那么通常只有具有外部链接的符号才会被逐字传递给链接器。例如,用于标签和静态全局变量的所有内部标识符都将重命名为一些编号符号。尽管如此,链接器仍可用于解析此类编号符号。请注意,即使它们没有外部链接,通常静态函数仍将保留其名称。

于 2013-08-17T16:24:30.810 回答
1

取决于您所说的“组装”是什么意思。链接器/加载器基本上做了三件事:

  • 在需要但无法在编译时提供的地方修补地址
  • 重新定位代码片段(主要是通过修补地址......)
  • 收集程序“段”:数据和代码(通过附加来自单个目标文件的片段)

如果您查看本地符号会发生什么(让我们暂时使用具有文件范围的“静态”符号,而不是自动),编译提供的信息如下

  • 我在数据段中需要 4 个字节的内存,我正在调用地址 foobar。

但是它可以在它生成的代码中使用任何实际数字来引用该地址吗?否:数据段要么是从段寄存器的偏移量(现在很少见,分段地址空间大部分已经消失),要么是从某个基地址的偏移量。

但是编译器无法知道存储将位于数据段中的哪个位置。所以它必须等待链接器提供这些信息。

链接器能提供什么?它通过附加对象文件收集所有数据段定义),因此它知道完整的静态数据段以及指向数据段的符号的偏移量。但是它可以修补一个绝对地址吗?嗯 - 这取决于您的操作系统:如果有固定数据段基地址的约定,则链接器将在此事务阶段已经知道地址。

但如果提供该地址是操作系统配置和进程加载的一部分,则链接器只能修补数据段的偏移量(即“我需要 4 个字节名为 foobar”的符号引用变为“foobar 是 NNN字节形成数据段的开头”)。然后是操作系统程序加载器在创建进程的内存映像时将补丁放在绝对地址中。

使用“局部”变量,事情就更简单了:这些只是堆栈中的偏移量,可以在编译时确定,链接器与它们无关。

(我将“静态”局部变量留给读者作为练习:-)

希望有帮助。

于 2013-08-17T16:33:23.753 回答
0

C 语言有链接的概念。链接是名称的一种属性,它描述了名称在不同翻译单元中的含义。详细信息例如在 C11 6.2.2 中。

简而言之,链接可以是外部的,也可以是内部的,也可以没有。只有作为对象或函数标识符的名称才能具有链接。例如,函数具有外部链接,除非它们被声明为static,在这种情况下它们具有内部链接。根据 6.2.2/6,未声明的局部变量extern没有链接:

以下标识符没有链接: 声明为对象或函数以外的任何标识符;声明为函数参数的标识符;没有存储类说明符声明的对象的块范围标识符extern

在实现方面,没有链接的名称不需要在生成的机器代码中使用符号占位符,因为它们可以直接引用。具有内部链接的名称可能需要也可能不需要符号,但如果需要,它必须是唯一的,并且仅取决于声明名称的翻译单元。具有外部链接的事物是经过适当链接的事物,并且需要由链接器跨翻译单元找到。

于 2014-03-02T02:05:16.907 回答