如何在GCC中命名静态变量的符号?

时间:2019-06-07 17:37:13

标签: c gcc static

我正在C语言中尝试静态全局变量。我尝试了此代码,并在其中运行nm

#include <stdio.h>

static int global_static = 12345;

int main(void)
{
    static int local_static = 12345;
    printf("%d\n", global_static);
    printf("%d\n", local_static);
    return 0;
}

以下是nm输出的摘要:

00004020 d global_static
00004024 d local_static.1905
000011a9 T main

对此我有两个问题:

  • 局部静态变量的名称从何而来?是进程ID还是随机数?

  • global_static中没有无效字符的事实是否意味着我可以在另一个文件中执行extern static int global_static;并读取global_static

当我说无效字符时,是指不能成为C中变量名称一部分的字符,即.$%,{{1} }等

2 个答案:

答案 0 :(得分:3)

  

局部静态变量的名称从何而来?是进程ID还是随机数?

在gcc的langhooks.c中,默认的set_decl_assembler_name钩子实现(直接用于C语言)contains

  /* By default, assume the name to use in assembly code is the same
     as that used in the source language.  (That's correct for C, and
     GCC used to set DECL_ASSEMBLER_NAME to the same value as
     DECL_NAME in build_decl, so this choice provides backwards
     compatibility with existing front-ends.  This assumption is wrapped
     in a target hook, to allow for target-specific modification of the
     identifier.
     Can't use just the variable's own name for a variable whose scope
     is less than the whole compilation.  Concatenate a distinguishing
     number - we use the DECL_UID.  */
  if (TREE_PUBLIC (decl) || DECL_FILE_SCOPE_P (decl))
    id = targetm.mangle_decl_assembler_name (decl, DECL_NAME (decl));
  else
    {
      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
      char *label;
      ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
      id = get_identifier (label);
    }

comment on the macro DECL_UID说:

/* Every ..._DECL node gets a unique number.  */

因此,数字是gcc发明的一些标识符,对于在翻译单元中看到的每个声明(包括#include-d文件中的声明),该标识符均应保证是不同的。这足以确保不同的作用域是否使用具有相同名称的局部静态变量,它们在汇编代码和目标代码中将具有不同的符号名称。

  

global_static中没有无效字符的事实是否意味着我可以在另一个文件中进行extern static int global_static;并读取global_static

不。一方面,结合使用externstatic是非法的,因为它们给变量带来了相互矛盾的联系。请注意,static在C中有两个完全不同的含义:在函数内部,这意味着变量具有静态存储持续时间。在函数外部,这意味着变量或函数具有内部链接。 (不是函数本地变量的变量始终具有静态存储持续时间。)

因此,从C语言的角度来看,static上的global_static意味着该变量具有内部链接,这意味着它永远不会被视为与任何其他翻译单元中的任何变量相同的变量,因此无法从另一个* .c文件直接访问它。在转换为ELF对象或其他常见对象格式时,可以通过将变量的符号设置为“局部”符号而不是“全局”符号来实现。链接可执行文件或加载动态库时,全局符号可以满足另一个对象中未定义的符号,而本地符号则永远不能满足。

请注意,nm工具会为全局符号打印大写的符号类型字母,为局部符号打印小写的符号类型字母,因此输出中变量旁边的d表示它们都是本地符号,不能可能被其他对象直接使用。

答案 1 :(得分:2)

  1. 这是翻译单元(源/目标文件)中的唯一标识符,因此具有不同本地范围的同名static将不会引用同一对象。

  2. 否。在程序集/目标文件中未标记为全局的符号不能在链接时用于解析其他文件中的引用。他们被忽略了。 (d中的小写nm表示它是局部符号,而不是全局符号。)在同一程序集/对象文件中,不能同时拥有外部和静态对象的C源代码级规则在文件作用域具有相同标识符的情况将其排除。