В програмуванні сегмент даних (часто позначається як .data) — це частина об’єктного файлу або відповідного адресного простору програми, яка містить ініціалізовані статичні змінні, тобто глобальні змінні та статичні локальні змінні. Розмір цього сегмента визначається розміром значень у вихідному коді програми й не змінюється під час виконання.
Сегмент даних доступний для читання/запису, оскільки значення змінних можуть змінюватися під час виконання. Це відрізняється від сегмента даних лише для читання (-сегмента або .rodata), який містить статичні константи, а не змінні; він також відрізняється від сегмента коду, також відомого як текстовий сегмент, який у багатьох архітектурах доступний лише для читання. Неініціалізовані дані — як змінні, так і константи — натомість розміщуються в сегменті .bss.
Історично, щоб мати можливість підтримувати адресні простори пам’яті, більші за той, який міг адресувати внутрішній адресний регістр нативного розміру, ранні ЦП реалізовували систему сегментації, за якої зберігався невеликий набір індексів, що використовувалися як зміщення до певних областей. Сімейство ЦП Intel 8086 надавало чотири сегменти: сегмент коду, сегмент даних, сегмент стека та додатковий сегмент. Кожен сегмент розміщувався програмним забезпеченням, що виконувалося, у певному місці пам’яті, а всі інструкції, які оперували даними всередині цих сегментів, виконувалися відносно початку відповідного сегмента. Це дозволяло 16-бітному адресному регістру, який зазвичай міг адресувати 64 КБ адресного простору пам’яті, отримувати доступ до 1 МБ адресного простору пам’яті.
Це розбиття адресного простору пам’яті на дискретні блоки з конкретними завданнями було перенесено в мови програмування того часу, і ця концепція досі широко використовується в сучасних мовах програмування.
Пам’ять програми
Пам’ять комп’ютерної програми можна значною мірою поділити на дві частини: доступну лише для читання та доступну для читання/запису. Цей поділ виник у ранніх системах, де основна програма зберігалася в пам’яті лише для читання, такій як Mask ROM, EPROM, PROM або EEPROM. У міру ускладнення систем і завантаження програм з інших носіїв у RAM замість виконання з ROM збереглася ідея про те, що деякі частини пам’яті програми не повинні змінюватися. Вони стали сегментами .text і .rodata програми, а решта, яку можна було змінювати, була розділена на низку інших сегментів для виконання конкретних завдань.
Код
Сегмент коду, також відомий як текстовий сегмент, містить виконуваний код і зазвичай доступний лише для читання та має фіксований розмір.
Дані
Сегмент даних містить ініціалізовані статичні змінні, тобто глобальні змінні та статичні локальні змінні, які мають визначене значення та можуть бути змінені. Приклади мовою C включають: int i = 3; char a[] = "Hello World"; static int b = 2023; // Initialized static global variable void foo (void) { static int c = 2023; // Initialized static local variable }
BSS
Сегмент BSS містить неініціалізовані статичні дані — як змінні, так і константи, тобто глобальні змінні та статичні локальні змінні, які ініціалізуються нулем або не мають явної ініціалізації у вихідному коді. Приклади мовою C включають: static int i; static char a;
Купа Сегмент купи містить динамічно виділену пам’ять; зазвичай він починається в кінці сегмента .bss і відтоді зростає в напрямку більших адрес. Ним керують malloc, calloc, realloc і free, які можуть використовувати системні виклики brk і sbrk для зміни його розміру (зауважимо, що використання brk/sbrk та єдиного сегмента купи не є обов’язковим для виконання контракту malloc/calloc/realloc/free; вони також можуть бути реалізовані за допомогою mmap/munmap для резервування/звільнення потенційно неперервних областей віртуальної пам’яті у віртуальний адресний простір процесу). Сегмент купи є спільним для всіх потоків, спільних бібліотек і динамічно завантажуваних модулів у процесі.
Стек
Сегмент стеку містить стек викликів, структуру LIFO, яка зазвичай розташована у верхніх частинах пам’яті. Регістр «вказівника стеку» відстежує вершину стеку; він коригується щоразу, коли значення «виштовхується» у стек. Набір значень, поміщених у стек для одного виклику функції, називається «кадром стеку». Кадр стеку щонайменше складається з адреси повернення. Автоматичні змінні також виділяються у стеку.
Традиційно сегмент стеку прилягав до сегмента купи, і вони зростали назустріч один одному; коли вказівник стеку зустрічався з вказівником купи, вільна пам’ять вичерпувалася. За великих адресних просторів і використання технологій віртуальної пам’яті вони, як правило, розміщуються вільніше, але все ще зазвичай зростають у зустрічних напрямках. У стандартній архітектурі x86 ПК стек зростає в напрямку адреси нуль, тобто новіші елементи, розташовані глибше в ланцюжку викликів, мають чисельно менші адреси й розташовані ближче до купи. На деяких інших архітектурах він зростає у протилежному напрямку.
Інтерпретовані мови
Деякі інтерпретовані мови надають подібний засіб для сегмента даних, зокрема Perlperldata: Special Literals та Ruby.Ruby: Embedded Data: У цих мовах включення рядка __DATA__ (Perl) або __END__ (Ruby, старі версії Perl) позначає кінець сегмента коду та початок сегмента даних. Виконується лише вміст до цього рядка, а вміст файлу вихідного коду після цього рядка доступний як файловий об’єкт: PACKAGE::DATA у Perl (наприклад, main::DATA) і DATA у Ruby. Це можна розглядати як форму документа Here.
Див. також Сегментація пам'яті Помилка сегментації Компонувальник Сегмент коду .bss Блок керування процесом
Примітки
Посилання