Я знаю, что глобальные и статические переменные хранятся в .data
сегменте, а неинициализированные данные находятся в .bss
сегменте. Я не понимаю, почему у нас есть специальный сегмент для неинициализированных переменных? Если неинициализированной переменной присвоено значение во время выполнения, существует ли эта переменная .bss
только в сегменте?
В следующей программе a
находится в .data
сегменте и b
находится в .bss
сегменте; это правильно? Пожалуйста, поправьте меня, если я неправильно понимаю.
#include <stdio.h>
#include <stdlib.h>
int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */
int main ()
{
;
}
Также рассмотрите следующую программу,
#include <stdio.h>
#include <stdlib.h>
int var[10]; /* Uninitialized so in .bss */
int main ()
{
var[0] = 20 /* **Initialized, where this 'var' will be ?** */
}
c
linux
compiler-construction
Кто я
источник
источник
Ответы:
Причина в том, чтобы уменьшить размер программы. Представьте, что ваша программа на C работает во встроенной системе, где код и все константы сохранены в истинном ПЗУ (флэш-памяти). В таких системах перед вызовом main () должно выполняться начальное «копирование вниз» для установки всех статических объектов продолжительности хранения. Обычно это выглядит так:
Где .data и .bss хранятся в RAM, а init_value хранится в ROM. Если бы это был один сегмент, то ПЗУ нужно было бы заполнить множеством нулей, что значительно увеличило размер ПЗУ.
Исполняемые файлы на основе RAM работают аналогично, хотя, конечно, у них нет настоящего ПЗУ.
Кроме того, memset, вероятно, является очень эффективным встроенным ассемблером, а это означает, что стартовое копирование может выполняться быстрее.
источник
.bss
Сегмент является оптимизация. Весь.bss
сегмент описывается одним числом, вероятно, 4 или 8 байтами, которое дает его размер в запущенном процессе, в то время.data
как размер раздела равен сумме размеров инициализированных переменных. Таким образом,.bss
исполняемые файлы становятся меньше и быстрее загружаются. В противном случае переменные могут находиться в.data
сегменте с явной инициализацией нулями; программе будет сложно заметить разницу. (В частности, адрес объектов.bss
, вероятно, отличался бы от адреса, если бы он был в.data
сегменте.)В первой программе
a
будет в.data
сегменте иb
будет в.bss
сегменте исполняемого файла. После загрузки программы различие становится несущественным. Во время выполненияb
занимает20 * sizeof(int)
байты.Во второй программе
var
выделяется пространство, и назначениеmain()
изменяет это пространство. Так получилось, что пространство дляvar
было описано в.bss
сегменте, а не в.data
сегменте, но это не влияет на поведение программы при запуске.источник
edata
). На практике после создания образа процесса .bss не существует в памяти; обнуленные данные являются простой частью раздела .data. Но детали различаются в зависимости от экипажа и т. Д.Из Assembly Language Step-by-Step: Programming with Linux by Jeff Duntemann, относительно раздела .data :
и раздел .bss :
источник
Ну, во-первых, эти переменные в вашем примере не неинициализированы; C указывает, что статические переменные, не инициализированные иным образом, инициализируются значением 0.
Таким образом, причина использования .bss заключается в том, чтобы иметь меньшие исполняемые файлы, экономить место и обеспечивать более быструю загрузку программы, поскольку загрузчик может просто выделить кучу нулей вместо того, чтобы копировать данные с диска.
При запуске программы загрузчик программы загрузит в память .data и .bss. Записывает в объекты, расположенные в .data или .bss, таким образом, идет только в память, они не сбрасываются в двоичный файл на диске в любой момент.
источник
System V ABI 4,1 (1997) (AKA ELF спецификация) также содержит ответ:
говорит, что имя раздела
.bss
зарезервировано и имеет специальные эффекты, в частности, он не занимает файлового пространства , поэтому преимущество выше.data
.Обратной стороной является, конечно, то, что все байты должны быть установлены,
0
когда ОС помещает их в память, что является более строгим, но распространенным вариантом использования и отлично работает для неинициализированных переменных.Документация по
SHT_NOBITS
типу раздела повторяет это утверждение:Стандарт C ничего не говорит о разделах, но мы можем легко проверить, где хранится переменная в Linux с помощью
objdump
иreadelf
, и сделать вывод, что неинициализированные глобальные переменные на самом деле хранятся в.bss
. См., Например, этот ответ: Что происходит с объявленной неинициализированной переменной в C?источник
Статья в Википедии .bss дает хорошее историческое объяснение, учитывая, что этот термин относится к середине 1950-х годов (ура, мой день рождения ;-).
Раньше каждый бит был драгоценен, поэтому любой метод сигнализации зарезервированного пустого пространства был полезен. Это ( .bss ) тот, который застрял.
Разделы .data предназначены для пространства, которое не является пустым, скорее, в него будут введены (ваши) определенные значения.
источник