alamat memori static int arr [10] selalu berakhir pada 060

17

Saya memiliki program ac yang terlihat seperti ini

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


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

dan menampilkan ini ketika saya menjalankan program yang dikompilasi beberapa kali

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

Mengapa selalu berakhir pada 060? Dan apakah array disimpan di heap?

Sunting: Saya di Linux dan ASLR aktif. Saya mengkompilasi program menggunakan gcc

linuxlmao
sumber
2
Sistem operasi apa? Kompiler apa?
Andrew Henle
2
Variabelnya tidak ada di heap, ada di bagian data atau bss dari ruang alamat program, lihat en.wikipedia.org/wiki/Static_variable . Dugaan saya adalah bahwa program akan selalu ditempatkan pada alamat memori pada batas tertentu, misalnya dapat dibagi dengan 0x1000, dan variabel ditempatkan oleh kompiler pada offset tetap di ruang alamat program.
Bodo

Jawaban:

15

Alamat berbeda karena ASLR (ramdomization tata letak ruang alamat). Dengan menggunakan ini, biner dapat dipetakan di lokasi yang berbeda di ruang alamat virtual.

Variabelnya heap- berbeda dengan namanya - tidak terletak di heap, tetapi di bss. Offset di ruang alamat karenanya konstan.

Halaman dipetakan pada granularity halaman, yaitu 4096 byte (hex: 0x1000) pada banyak platform. Inilah alasannya, mengapa tiga digit hex terakhir dari alamat itu sama.

Ketika Anda melakukan hal yang sama dengan variabel stack , alamat tersebut bahkan dapat bervariasi dalam digit terakhir pada beberapa platform (yaitu linux dengan kernel terbaru), karena stack tidak hanya dipetakan di tempat lain tetapi juga menerima offset acak saat startup.

Ctx
sumber
ASLR mengacak basis pemuatan seperti yang saya ingat. Alamat bagian didasarkan pada alamat itu.
Afshin
Saya menggunakan buku tentang pemrograman berorientasi objek ANSI-C oleh Axel-Thobias Schreiner. Buku ini ditulis kira-kira seperti tahun 1993. Apakah Anda tahu jika tata letak memorinya berbeda saat itu? Jika tidak, mengapa dia memberi nama variabel heapketika tidak ada dalam heap?
linuxlmao
Apakah 4096 menerjemahkan ke dalam 060 dalam beberapa cara atau apakah 0x1000 menerjemahkan ke dalam 060 kalau tidak, saya tidak mengerti apa yang Anda maksudkan dengan itu menjadi alasan untuk penutupnya? Saya pikir itu mungkin ada hubungannya dengan ukuran array menjadi sesuatu yang diterjemahkan ke dalam 060 dalam heksadesimal dari, misalnya desimal
linuxlmao
2
@linuxlmao Offset misalnya 14060, jadi ketika Anda menambahkan kelipatan ukuran halaman (0x1000), tiga digit terakhir tetap ada 060.
Ctx
4

Jika Anda menggunakan Windows, alasannya adalah struktur PE .

heapVariabel Anda disimpan di .databagian file dan alamatnya dihitung berdasarkan awal bagian ini. Setiap bagian dimuat dalam alamat secara independen, tetapi alamat awalnya adalah kelipatan dari ukuran halaman. Karena Anda tidak memiliki variabel lain, alamatnya mungkin mulai dari .databagian, jadi alamatnya akan lebih dari satu ukuran chunk.

Sebagai contoh, ini adalah tabel dari Windows versi dikompilasi dari kode Anda: bagian The .textseksi yang kode dikompilasi Anda dan .databerisi Anda heapvariabel. Ketika PE Anda dimuat ke dalam memori, bagian dimuat di alamat yang berbeda dan yang dikembalikan oleh VirtualAlloc()dan akan menjadi beberapa ukuran halaman. Tetapi alamat masing-masing variabel relatif terhadap awal bagian yang sekarang menjadi ukuran halaman. Jadi, Anda akan selalu melihat nomor tetap pada digit yang lebih rendah. Karena alamat relatif heapdari awal bagian didasarkan pada kompiler, opsi kompilasi, dll. Anda akan melihat nomor berbeda dari kode yang sama tetapi kompiler berbeda, tetapi setiap kali apa yang akan dicetak diperbaiki.

Ketika saya mengkompilasi kode, saya perhatikan heapditempatkan pada 0x8B0byte setelah memulai .databagian. Jadi setiap kali saya menjalankan kode ini, alamat saya berakhir 0x8B0.

Afshin
sumber
Saya menggunakan buku tentang pemrograman berorientasi objek ANSI-C oleh Axel-Thobias Schreiner. Buku ini ditulis kira-kira seperti tahun 1993. Apakah Anda tahu jika tata letak memorinya berbeda saat itu? Jika tidak, mengapa dia memberi nama variabel heapketika tidak ada dalam heap?
linuxlmao
2
@linuxlmao Mungkin berbeda. Pada tahun 1993, Windows adalah sistem operasi 16-bit, dengan segmentasi memori dan segala macam hal yang membingungkan. Itu bukan arsitektur 32-bit, memori datar seperti sekarang. Tetapi hal-hal semacam ini adalah mengapa bertanya / menjawab pertanyaan umum tentang tata letak program biner dalam memori tidak berguna. Pahami apa yang standar bahasa C menjamin untuk Anda secara umum , dan hanya itu yang perlu Anda ketahui. Hanya khawatir tentang tata letak yang sebenarnya jika Anda debugging masalah tertentu, kemudian menggunakan debugger
Cody Gray
tidak, variabel tidak boleh dibuat di heap bahkan pada sistem yang lebih lama karena tidak dialokasikan dengan malloc dan memiliki durasi penyimpanan statis
phuclv
@Afshin Saya menanggapi komentar OP di atas
phuclv
@ phuclv maaf, karena Anda tidak menyebut-nyebutnya, saya pikir Anda menyapa saya. :)
Afshin
4

Compiler kebetulan diletakkan heappada offset 0x60 byte di segmen data yang dimilikinya, mungkin karena kompiler memiliki beberapa hal lain dalam 0x60 byte pertama, seperti data yang digunakan oleh kode yang memulai mainrutinitas. Itu sebabnya Anda melihat "060"; itu hanya di mana itu terjadi, dan tidak ada signifikansi yang besar untuk itu.

Pengacakan tata letak ruang alamat mengubah alamat dasar yang digunakan untuk berbagai bagian memori program, tetapi selalu melakukannya dalam satuan 0x1000 byte (karena ini menghindari masalah dengan penyelarasan dan masalah lainnya). Jadi Anda melihat alamat berfluktuasi dengan kelipatan 0x1000, tetapi tiga digit terakhir tidak berubah.

Definisi tersebut static int heap[SOME_VAR];didefinisikan heapdengan durasi penyimpanan statis. Implementasi C yang khas menyimpannya di bagian data umum, bukan di heap. "Heap" adalah istilah yang salah untuk memori yang digunakan untuk alokasi dinamis. (Ini keliru karena mallocimplementasi dapat menggunakan berbagai struktur data dan algoritma, tidak terbatas pada tumpukan. Mereka bahkan dapat menggunakan beberapa metode dalam satu implementasi.)

Eric Postpischil
sumber