.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(){
}