статична адреса пам'яті int arr [10] завжди закінчується 060


17

У мене є програма змінного струму, яка виглядає приблизно так

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


int main(void) {
    printf("%p", heap);
    return 0;
}

і виводить це, коли я кілька разів запускаю компільовану програму

0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060

Чому це завжди закінчується 060? А чи зберігається масив у купі?

Редагувати: Я в Linux і в мене ASLR. Я склав програму за допомогою gcc


2
Яка операційна система? Який компілятор?
Ендрю Генле

2
Змінна не в купі, вона знаходиться в розділі даних або bss адресного простору програми, див. En.wikipedia.org/wiki/Static_variable . Я гадаю, що програма завжди буде розміщена за адресою пам'яті на певній межі, наприклад, поділяється на 0x1000, а змінна розміщується компілятором при фіксованому зміщенні в адресному просторі програми.
Бодо

Відповіді:


15

Адреси відрізняються через ASLR (рамбовування розміщення адресного простору). Використовуючи це, двійковий файл може бути відображений у різних місцях у віртуальному адресному просторі.

Змінна heap- на відміну від її імені - розташована не на купі, а на bss. Тому зміщення в адресному просторі є постійним.

Сторінки відображаються за деталізацією сторінки, яка становить 4096 байтів (hex: 0x1000) на багатьох платформах. Це причина, чому три останні шістнадцяткові цифри адреси однакові.

Коли ви зробили те ж саме зі змінною стека , адреса може навіть змінюватися в останніх цифрах на деяких платформах (а саме в Linux з останніми ядрами), тому що стек не тільки відображається десь в іншому місці, але і отримує випадкове зміщення при запуску.


Як я пам’ятаю, ASLR рандомізує базу завантаження. Адреса розділу заснована на цій адресі.
Афшин

Я використовую книгу про об’єктно-орієнтоване програмування ANSI-C Акселя-Тобіаса Шрайнера. Книга написана приблизно як 1993. Чи знаєте ви, чи тоді структура пам’яті відрізнялася? Якщо це не так, чому він міг би назвати змінну, heapколи її немає в купі?
linuxlmao

Чи 4096 перекладає на 060 якимось чином, чи 0x1000 перекладає на 060, інакше я не розумію, що ви маєте на увазі під тим, що це є причиною закінчення? Я думав, що це може мати відношення до того, що розмір масиву є чимось, що переводиться в 060 шістнадцятковим з, наприклад, десятковим
linuxlmao

2
@linuxlmao Зсув, наприклад, 14060, тому коли ви додаєте кратний розмір сторінки (0x1000), три останні цифри залишаються 060.
Ctx

4

Якщо ви використовуєте Windows, причиною є структура PE .

Ваша heapзмінна зберігається у .dataрозділі файлу, а її адреса обчислюється на основі початку цього розділу. Кожен розділ завантажується в адресу незалежно, але його початкова адреса кратна розміру сторінки. Оскільки у вас немає інших змінних, його адреса, ймовірно, починається з .dataрозділу, тому його адреса буде кратною за розміром.

Наприклад, це таблиця компільованою версії Windows , ваш код: розділ були ваш скомпільований код і містить ваш змінний. Коли ваше ПЕ завантажується в пам'ять, розділи завантажуються за різною адресою, яка повертається і буде кратною розміру сторінки. Але адреса кожної змінної є відносно початку розділу, який зараз є розміром сторінки. Так ви завжди будете бачити фіксовану цифру на нижчих цифрах. Оскільки відносна адреса від початку розділу базується на компіляторі, параметрах компіляції тощо, ви побачите різну кількість від одного і того ж коду, але різні компілятори, але щоразу, що буде надруковано, фіксується.розділи.text.dataheapVirtualAlloc()heap

Коли я компілюю код, я помітив, що heapвін розміщується на 0x8B0байтах після початку .dataрозділу. Тому щоразу, коли я запускаю цей код, моя адреса закінчується 0x8B0.


Я використовую книгу про об’єктно-орієнтоване програмування ANSI-C Акселя-Тобіаса Шрайнера. Книга написана приблизно як 1993. Чи знаєте ви, чи тоді структура пам’яті відрізнялася? Якщо це не так, чому він міг би назвати змінну, heapколи її немає в купі?
linuxlmao

2
@linuxlmao Це, можливо, було інакше. У 1993 році Windows була 16-бітною операційною системою з сегментацією пам'яті та всілякими заплутаними речами. Це була не 32-розрядна архітектура з плоскою пам'яттю, як зараз. Але такі речі пояснюють, чому задавати / відповідати на загальні запитання щодо компонування програмного двійкового файлу в пам'яті не корисно. Зрозумійте, що загалом гарантує вам мова мови С , і це все, що вам потрібно знати. Потурбуйтеся про власний макет, якщо ви налагодите конкретну проблему, тоді використовуйте налагоджувач
Коді Грей

ні, змінна не повинна створюватися в купі навіть у старих системах, оскільки вона не була виділена з malloc та має статичну тривалість зберігання
phuclv

@Afshin Я звертаюся до коментаря ОП вище
phuclv

@phuclv вибачте, тому що ви його не згадали, я думав, що ви звертаєтесь до мене. :)
Афшин

4

Компілятор ставив heapна зміщення 0x60 байт у сегменті даних, який він має, можливо, тому, що компілятор має деякі інші речі в перших байтах 0x60, наприклад, дані, що використовуються кодом, який запускає mainпроцедуру. Ось чому ви бачите "060"; це саме там, де це трапилося, і великого значення для цього немає.

Рандомізація розміщення адресного простору змінює базові адреси, які використовуються для різних частин пам'яті програми, але це завжди робиться в одиницях розміром 0x1000 байт (тому що це дозволяє уникнути проблем з вирівнюванням та інших проблем). Отже, ви бачите, що адреси коливаються кратними 0x1000, але останні три цифри не змінюються.

Визначення static int heap[SOME_VAR];визначається heapзі статичною тривалістю зберігання. Типові реалізації C зберігають його в загальному розділі даних, а не в купі. "Купа" - це неправильне значення для пам'яті, яке використовується для динамічного розподілу. (Це неправильне значення, оскільки mallocреалізація може використовувати різноманітні структури даних та алгоритми, не обмежуючись купами. Вони можуть використовувати навіть кілька методів в одній реалізації.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.