Как символы для статических переменных названы в GCC? - PullRequest
2 голосов
/ 07 июня 2019

Я экспериментирую со статическими глобальными переменными в 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

У меня есть два вопроса по этому поводу:

  • Откуда происходит имя локальной статической переменной? Это идентификатор процесса или случайное число?

  • Означает ли тот факт, что в global_static нет недопустимых символов, подразумевается, что я могу сделать extern static int global_static; в другом файле и прочитать global_static?

Когда я говорю недопустимые символы, я имею в виду символы, которые не могут быть частью имен переменных в C, т.е. ., $, %, # и т. Д.

Ответы [ 2 ]

3 голосов
/ 07 июня 2019

Откуда берется имя локальной статической переменной? Это идентификатор процесса или случайное число?

В gcc langhooks.c стандартная реализация ловушки set_decl_assembler_name (которая используется непосредственно для языка C) содержит :

  /* 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);
    }

И комментарий к макросу DECL_UID говорит:

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

Таким образом, число - это некоторый идентификатор, придуманный gcc, который гарантированно будет отличаться для каждого объявления, видимого в модуле перевода (включая объявления в #include -d файлах). Этого достаточно, чтобы убедиться, что если разные области используют локальные статические переменные с одинаковыми именами, они будут иметь разные искаженные имена символов в сборке и объектном коде.

Означает ли то, что в global_static нет недопустимых символов, подразумевается, что я мог бы сделать extern static int global_static; в другом файле и прочитать global_static?

Нет. С одной стороны, нельзя объединять extern и static, поскольку они дают конфликтующие связи с переменной. Обратите внимание, что static имеет два совершенно разных значения в C: внутри функции это означает, что переменная имеет статическую продолжительность хранения. Вне функции это означает, что переменная или функция имеет внутреннюю связь. (Переменная, которая не является локальной для функции, всегда имеет статическую продолжительность хранения.)

Таким образом, с точки зрения языка C, static on global_static означает, что переменная имеет внутреннюю связь, что означает, что она никогда не должна рассматриваться как та же самая переменная, что и любая другая единица перевода, поэтому существует нет способа получить к нему прямой доступ из другого * .c файла. При переводе в объекты ELF или другие распространенные форматы объектов это делается путем превращения символа для переменной в «локальный» символ вместо «глобального» символа. При связывании исполняемых файлов или загрузке динамических библиотек глобальный символ может удовлетворять неопределенному символу из другого объекта, но локальный символ никогда не удовлетворяет.

Обратите внимание, что инструмент nm печатает заглавные буквы типа символов для глобальных символов и строчные буквы типа символов для локальных символов, поэтому d рядом с переменными в выходных данных означает, что оба являются локальными символами и не могут использоваться напрямую другими объектами.

2 голосов
/ 07 июня 2019
  1. Это уникальный идентификатор в единице перевода (исходный / объектный файл), поэтому одноименные static с разными локальными областями не будут ссылаться на один и тот же объект.

  2. Нет.Символы, не помеченные как глобальные в сборке / объектном файле, не могут использоваться для разрешения ссылок из других файлов во время ссылки;они игнорируются.(Нижний регистр d из nm указывает, что это локальный символ, а не глобальный.) В одном и том же файле сборки / объекта правило уровня источника C, что нельзя иметь как внешние, так и статические объекты с одинаковым идентификатором вобласть действия файла исключает это.

...