.bss vs COMMON: что происходит?
Из моей книги:
.bss:
Неинициализированные глобальные переменные C
ОБЩИЙ:
Uninitalized объекты данных, которые еще не выделены
Я должен сказать, я не совсем понимаю четкое различие. Я даже не совсем понимаю, что неинициализированный, не выделенный объект данных... кажется ничем. Я использовал инструмент GNU readelf
, чтобы попытаться взглянуть на простой C-код, но не могу найти ни одного символа COMMON. Я читал такие вещи, как FORTRAN COMMON, это пример символа COMMON, но я не знаю FORTRAN
Может ли кто-то отличить меня от меня? Если это вообще возможно, надеюсь с примером? Очень ценится.
изменить: из this post, переменная c здесь:
int c;
int main() {} ...
должен быть ОБЩИМ. Но использование objdump -t
показывает для меня, что c находится в .bss...
спутать
Ответы
Ответ 1
// file a.c
// file-scope
int a = 0; // goes into BSS
после компиляции a.c
в файл объекта a.o
, символ a
переходит в раздел BSS.
// file b.c
// file-scope
int b; // goes into COMMON section
после компиляции b.c
в файл объекта b.o
, символ b
переходит в раздел COMMON.
После связывания a.o
и b.o
символы a
и b
переходят в раздел BSS. Общие символы существуют только в объектных файлах, а не в исполняемых файлах. Идея ОБЩИХ символов в Unix заключается в разрешении нескольких внешних определений одной и той же переменной (в разных единицах компиляции) под одним общим символом при определенных условиях.
Ответ 2
Commons появляется только на этапе компоновки. Commons - это то, что позже входит в bss или данные, но это зависит от компоновщика, чтобы решить, куда он идет. Это позволяет вам иметь одну и ту же переменную, определенную в разных единицах компиляции. Насколько я знаю, это в основном для того, чтобы некоторые древние файлы заголовков имели int foo;
в них вместо extern int foo;
.
Вот как это работает:
$ cat > a.c
int foo;
$ cat > b.c
int foo;
$ cat > main.c
extern int foo;
int main(int argc, char **argv) { return foo; }
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ objdump -t a.o | grep foo
0000000000000004 O *COM* 0000000000000004 foo
$ objdump -t b.o | grep foo
0000000000000004 O *COM* 0000000000000004 foo
$ objdump -t x | grep foo
0000000000600828 g O .bss 0000000000000004 foo
$
Обратите внимание, что это работает только тогда, когда инициализируется не более одной из переменных в разных единицах компиляции.
$ echo "int foo = 0;" > a.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
$ echo "int foo = 0;" > b.c
$ cc -c a.c && cc -c b.c && cc -c main.c && cc -o x a.o b.o main.o
b.o:(.bss+0x0): multiple definition of `foo'
a.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
$
Это страшный материал, совместимость с древними системами, и вы никогда не должны полагаться на него. Делайте все правильно - только одно определение глобальных переменных во всех единицах компиляции, объявляйте, что оно выходит из него повсюду через заголовок.
Ответ 3
Если вы разрешаете common
при связывании разных единиц, можете объявить одну и ту же переменную, и компоновщик найдет их в одном месте. Типы не обязательно должны быть одинаковыми, поэтому это своего рода соединение времени соединения. Это функция common
от Fortran. Если вы не разрешаете common
при связывании C, тогда такая ситуация приведет к ошибке времени ссылки. Такое связывание common
возможно только для неинициализированных глобалов, потому что в противном случае неясно, какая инициализация должна быть выполнена.
Глобалы, идущие к bss
, представляют собой просто неинициализированные глобальные переменные, которые C определяет как инициализированные на 0. Большинство форматов объектов поддерживают разделы, где задан только размер, и загрузчик заполняет всю секцию нулями.
P.S: Если вы используете gcc
, вы можете использовать опцию -fno-common
, чтобы принудительно использовать символы common
в разделе bss
, что, как утверждает Art, является хорошей и целесообразной практикой.
Ответ 4
статические переменные попадают в секцию .bss. Исключенные глобальные переменные (не статические) входят в .common section.
static a; //bss
int c; //.common
main(){
}