Mam program ac, który wygląda tak
main.c
#include <stdio.h>
#define SOME_VAR 10
static int heap[SOME_VAR];
int main(void) {
printf("%p", heap);
return 0;
}
i wypisuje to, gdy uruchamiam skompilowany program kilka razy
0x58aa7c49060
0x56555644060
0x2f8d1f8e060
0x92f58280060
0x59551c53060
0xd474ed6e060
0x767c4561060
0xf515aeda060
0xbe62367e060
Dlaczego zawsze kończy się na 060? A czy tablica jest przechowywana w stercie?
Edycja: Jestem na Linuksie i mam włączony ASLR. Skompilowałem program za pomocą gcc
Odpowiedzi:
Adresy różnią się z powodu ASLR (ramdomizacja układu przestrzeni adresowej). Dzięki temu plik binarny można zmapować w różnych lokalizacjach w wirtualnej przestrzeni adresowej.
Zmienna
heap
- w przeciwieństwie do nazwy - nie znajduje się na stercie, ale nabss
. Przesunięcie w przestrzeni adresowej jest zatem stałe.Strony są odwzorowane na ziarnistość strony, która wynosi 4096 bajtów (hex: 0x1000) na wielu platformach. Z tego powodu ostatnie trzy cyfry szesnastkowe adresu są takie same.
Kiedy zrobiłeś to samo ze zmienną stosu , adres może nawet różnić się ostatnimi cyframi na niektórych platformach (mianowicie linux z najnowszymi jądrami), ponieważ stos jest nie tylko mapowany gdzie indziej, ale również otrzymuje losowe przesunięcie przy uruchomieniu.
źródło
heap
gdy nie ma jej w stosie?060
.Jeśli używasz systemu Windows, przyczyną jest struktura PE .
Twoja
heap
zmienna jest przechowywana w.data
sekcji pliku, a jej adres jest obliczany na podstawie początku tej sekcji. Każda sekcja jest ładowana niezależnie pod adresem, ale jej adres początkowy jest wielokrotnością rozmiaru strony. Ponieważ nie masz żadnych innych zmiennych, jego adres jest prawdopodobnie początkiem.data
sekcji, więc jego adres będzie wielokrotnością wielkości porcji.Na przykład jest to tabela skompilowanej wersji kodu systemu Windows:
.text
sekcja były Twój kod jest kompilowany i.data
zawiera swojąheap
zmienną. Kiedy twój PE jest ładowany do pamięci, sekcje są ładowane pod innym adresem i który jest zwracany przezVirtualAlloc()
i będzie wielokrotnością rozmiaru strony. Ale adres każdej zmiennej odnosi się do początku sekcji, która jest teraz rozmiarem strony. Tak więc zawsze zobaczysz stały numer na niższych cyfrach. Ponieważ względny adresheap
od początku sekcji jest oparty na kompilatorze, opcjach kompilacji itp., Zobaczysz inną liczbę z tego samego kodu, ale różne kompilatory, ale za każdym razem naprawiane jest to, co zostanie wydrukowane.Kiedy kompiluję kod, zauważyłem, że
heap
umieszczany jest w0x8B0
bajtach po rozpoczęciu.data
sekcji. Za każdym razem, gdy uruchamiam ten kod, mój adres kończy się na0x8B0
.źródło
heap
gdy nie ma jej w stosie?Kompilator się położył
heap
z przesunięciem 0x60 bajtów w segmencie danych, który ma, być może dlatego, że kompilator ma jakieś inne rzeczy w pierwszych bajtach 0x60, takie jak dane używane przez kod uruchamiającymain
procedurę. Dlatego widzisz „060”; jest dokładnie tam, gdzie to się stało, i nie ma to wielkiego znaczenia.Randomizacja układu przestrzeni adresowej zmienia adresy podstawowe używane dla różnych części pamięci programu, ale zawsze dzieje się tak w jednostkach 0x1000 bajtów (ponieważ pozwala to uniknąć problemów z wyrównaniem i innych problemów). Widzisz więc, że adresy zmieniają się o wielokrotności 0x1000, ale ostatnie trzy cyfry się nie zmieniają.
Definicja
static int heap[SOME_VAR];
określaheap
statyczny czas przechowywania. Typowe implementacje języka C przechowują je w ogólnej sekcji danych, a nie w stercie. „Sterta” jest mylącą nazwą pamięci używanej do dynamicznego przydzielania. (Jest to mylące, ponieważmalloc
implementacje mogą korzystać z różnych struktur danych i algorytmów, nie ograniczając się do stosów. Mogą nawet korzystać z wielu metod w jednej implementacji.)źródło