У меня есть программа переменного тока, которая выглядит так
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
Ответы:
Адреса различаются из-за ASLR (рамдомизация адресного пространства). Используя это, двоичный файл может отображаться в разных местах в виртуальном адресном пространстве.
Переменная,
heap
в отличие от ее имени, находится не в куче, а вbss
. Поэтому смещение в адресном пространстве является постоянным.Страницы отображаются с гранулярностью страниц, которая составляет 4096 байт (hex: 0x1000) на многих платформах. По этой причине последние три шестнадцатеричные цифры адреса совпадают.
Когда вы делали то же самое с переменной стека , адрес мог даже меняться в последних цифрах на некоторых платформах (а именно в linux с последними ядрами), потому что стек не только отображается в другом месте, но также получает случайное смещение при запуске.
источник
heap
когда она не в куче?060
.Если вы используете Windows, причина в структуре PE .
Ваша
heap
переменная хранится в.data
разделе файла, и ее адрес рассчитывается на основании начала этого раздела. Каждый раздел загружается по адресу независимо, но его начальный адрес кратен размеру страницы. Поскольку у вас нет других переменных, его адрес, вероятно, является началом.data
раздела, поэтому его адрес будет кратен размеру куска.Например, это таблица скомпилированной версии Windows , ваш код: раздел были ваш скомпилированный код и содержит ваш переменный. Когда ваш PE загружен в память, разделы загружаются по другому адресу, который возвращается и будет кратным размеру страницы. Но адрес каждой переменной относительно начала раздела, который теперь является размером страницы. Таким образом, вы всегда будете видеть фиксированное число в младших разрядах. Поскольку относительный адрес в начале раздела основан на компиляторе, опциях компиляции и т. Д., Вы увидите разные числа в одном и том же коде, но разные компиляторы, но каждый раз, когда будет напечатано, исправлено.
.text
.data
heap
VirtualAlloc()
heap
Когда я компилировал код, я заметил, что
heap
он помещается в0x8B0
байты после начала.data
раздела. Поэтому каждый раз, когда я запускаю этот код, мой адрес заканчивается0x8B0
.источник
heap
когда она не в куче?Случилось так, что компилятор установил
heap
смещение 0x60 байтов в сегменте данных, который у него есть, возможно, потому, что у компилятора есть некоторые другие вещи в первых байтах 0x60, такие как данные, используемые кодом, который запускаетmain
подпрограмму. Вот почему вы видите «060»; это именно то, где это произошло, и для этого нет большого значения.Рандомизация размещения адресного пространства изменяет базовый адрес (а), используемый для различных частей памяти программ, но это всегда происходит в единицах 0x1000 байт (потому что это позволяет избежать проблем с выравниванием и других проблем). Таким образом, вы видите, что адреса колеблются с кратностью 0x1000, но последние три цифры не меняются.
Определение
static int heap[SOME_VAR];
определяетheap
со статической продолжительностью хранения. Типичные реализации C хранят его в общем разделе данных, а не в куче. «Куча» является неправильным обозначением памяти, которая используется для динамического выделения. (Это неправильно, потому чтоmalloc
реализации могут использовать различные структуры данных и алгоритмы, не ограничиваясь кучами. Они могут даже использовать несколько методов в одной реализации.)источник