В C они могут храниться там, где реализация сочтет нужным. Стандарт C не определяет, как реализация работает, а только как ведет себя.
Как правило, все статические переменные продолжительности хранения (статика внутри функции и все переменные вне функции) будут храниться в одной и той же области, независимо от того, находятся ли они на уровне файла или внутри функции.
Этот бит в скобках выше важен. Вне функции static
не определяет продолжительность хранения переменной, как в функции. Он решает, видна ли переменная за пределами текущей единицы перевода. Все переменные вне функций имеют статическую длительность хранения.
И, что касается таблицы символов, это конструкция, которая существует только во время процесса сборки. Как только исполняемый файл сгенерирован, символов нет (конечно, отладочная информация исключена, но это никак не связано с выполнением кода). Все ссылки на переменные в этой точке почти наверняка будут жестко закодированными адресами или смещениями.
Другими словами, именно компилятор определяет, на какую переменную вы ссылаетесь с именем.
Здесь вы можете увидеть пример того, как хранятся переменные. Рассмотрим следующую маленькую программу на C:
#include <stdio.h>
int var1;
static int var2;
int main (void) {
int var3;
static int var4;
var1 = 111;
var2 = 222;
var3 = 333;
var4 = 444;
return 0;
}
Создается следующая сборка:
.file "qq.c"
.comm var1,4,4
.local var2
.comm var2,4,4
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $111, var1
movl $222, var2
movl $333, -4(%ebp)
movl $444, var4.1705
movl $0, %eax
leave
ret
.size main, .-main
.local var4.1705
.comm var4.1705,4,4
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
И вы можете видеть, что var1
, var2
и var4
(статические единицы хранения) имеют строку .comm
, чтобы пометить их как общие записи, подлежащие консолидации компоновщиком.
Кроме того, var2
, var3
и var4
(те, которые невидимы вне текущей единицы трансдляции) имеют строку .local
, так что компоновщик не будет использовать их для удовлетворения неразрешенных внешних факторов. в другом объектном файле.
И, изучив вывод ld --verbose
при связывании файла, вы можете увидеть, что все общие записи попадают в область .bss
:
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
: : :
}