statik int arr [10] bellek adresi her zaman 060 ile biter


17

Buna benzeyen bir ac programım var

main.c

#include <stdio.h>
#define SOME_VAR 10

static int heap[SOME_VAR];


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

ve derlenen programı birkaç kez çalıştırdığımda bu çıktı

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

Neden hep 060 ile bitiyor? Ve dizi yığın halinde saklanıyor mu?

Düzenleme: Ben Linux ve ASLR var. Programı gcc kullanarak derledim


2
Hangi işletim sistemi? Ne derleyicisi?
Andrew Henle

2
Değişken yığınta değil, programın adres alanının veri veya bss bölümünde bulunuyor, bkz. En.wikipedia.org/wiki/Static_variable . Benim tahminim, programın her zaman belirli bir sınırda bir bellek adresine, örneğin 0x1000 ile bölünebilir olması ve değişkenin derleyici tarafından programın adres alanındaki sabit bir ofsete yerleştirilmesidir.
Bodo

Yanıtlar:


15

Adresler ASLR (Adres alanı düzeni ramdomizasyonu) nedeniyle farklılık gösterir. Bunu kullanarak, ikili dosya sanal adres alanındaki farklı konumlarda eşlenebilir.

Değişken heap- adının aksine - öbek üzerinde değil bss,. Bu nedenle adres alanındaki ofset sabittir.

Sayfalar, birçok platformda 4096 bayt (onaltılık: 0x1000) olan sayfa ayrıntı düzeyinde eşlenir. Adresin son üç onaltılık basamağının aynı olmasının nedeni budur.

Bir yığın değişkeni ile aynı işlemi yaptığınızda, adres bazı platformlardaki son rakamlarda bile değişebilir (yani son çekirdekli linux), çünkü yığın yalnızca başka bir yere eşlenmediği gibi başlangıçta rastgele bir denge de alır.


ASLR hatırladığım gibi yükleme tabanını rastgele seçiyor. Bölüm adresi bu adrese dayanmaktadır.
Afshin

Axel-Thobias Schreiner'ın nesneye yönelik ANSI-C programlaması üzerine bir kitap kullanıyorum. Kitap 1993 gibi bir şeyle yazılmış. O zamanlar bellek düzeninin farklı olup olmadığını biliyor musunuz? Değilse, neden yığında olmadığında değişkeni adlandırmış olabilir heap?
linuxlmao

4096 bir şekilde 060'a mı çeviriyor, yoksa 0x1000 060'a mı çevriliyor? Aksi takdirde, sonun sebebi olarak ne demek istediğini anlamıyorum? Ben dizinin büyüklüğü onaltılık, örneğin ondalık
düşündüm

2
@linuxlmao Ofset örneğin 14060'tır, bu nedenle sayfa boyutunun (0x1000) katını eklediğinizde son üç basamak kalır 060.
Ctx

4

Windows kullanıyorsanız, bunun nedeni PE yapısıdır.

Sizin heapdeğişken saklanır .datadosyasının bölümüne ve adresi bu bölümün başlangıcında dayalı olarak hesaplanır. Her bölüm bağımsız olarak bir adrese yüklenir, ancak başlangıç ​​adresi sayfa boyutunun katlarıdır. Başka değişkeniniz olmadığından, adresi büyük olasılıkla .databölüm başlangıcıdır , bu nedenle adresi yığın boyutunun katı olacaktır.

Örneğin, bu senin kodun derlenmiş, Windows sürümünün tablosudur: bölümde derlenmiş koddur ve were sizin içeren değişken. PE'niz belleğe yüklendiğinde, bölümler farklı bir adrese yüklenir ve bu bölüm tarafından döndürülür ve sayfa boyutunun katı olur. Ancak her değişkenin adresi, şu anda bir sayfa boyutu olan bölümün başlangıcına göredir. Böylece her zaman düşük rakamlarda sabit bir sayı göreceksiniz. Bölümün başlangıcındaki göreli adres derleyici, derleme seçenekleri vb. Temelli olduğundan, aynı koddan ancak farklı derleyicilerden farklı sayılar görürsünüz, ancak her yazdırılacak zaman sabittir.bölümler.text.dataheapVirtualAlloc()heap

Kodu derlediğimde , bölüm başladıktan sonra baytlara heapyerleştirildiğini fark ettim . Bu kodu her çalıştırdığımda adresim bitiyor .0x8B0.data0x8B0


Axel-Thobias Schreiner'ın nesneye yönelik ANSI-C programlaması üzerine bir kitap kullanıyorum. Kitap 1993 gibi bir şeyle yazılmış. O zamanlar bellek düzeninin farklı olup olmadığını biliyor musunuz? Değilse, neden yığında olmadığında değişkeni adlandırmış olabilir heap?
linuxlmao

2
@linuxlmao Farklı olabilirdi. 1993 yılında, Windows 16-bit bir işletim sistemiydi, bellek bölümlendirmesi ve her türlü kafa karıştırıcı şeyler vardı. Bu olarak değil , şimdi olduğu gibi, bir 32-bit, düz bellek mimarisi. Ancak bu tür şeyler, hafızadaki bir program ikili düzeninin düzeni hakkında genel sorular sormanın / cevaplamanın neden yararlı olmadığıdır. C dili standardının size genel olarak neyi garanti ettiğini anlayın ve bilmeniz gereken her şey bu. Sadece belirli bir problemde hata ayıklama yapıyorsanız, gerçek düzen hakkında endişelenin, sonra bir hata ayıklayıcı kullanın
Cody Gray

Hayır, malloc ile ayrılmadığı ve statik depolama süresine sahip olduğu için değişken eski sistemlerde bile yığın üzerinde oluşturulmamalıdır
phuclv

@Afshin OP'nin yukarıdaki
yorumuna değindim

@phuclv özür dilerim, çünkü ondan bahsetmediniz, bana hitap ettiğinizi sanıyordum. :)
Afshin

4

Derleyici heap, muhtemelen derleyicinin ilk 0x60 baytında, mainrutini başlatan kod tarafından kullanılan veriler gibi başka şeyler olması nedeniyle sahip olduğu bir veri segmentine ofset 0x60 bayt koydu . Bu yüzden “060” ı görüyorsunuz; tam orada olduğu yer ve bunun büyük bir önemi yok.

Adres alanı düzeni rastgele seçimi, program belleğinin çeşitli bölümleri için kullanılan temel adresleri değiştirir, ancak bunu her zaman 0x1000 bayt biriminde yapar (çünkü bu, hizalama ve diğer sorunlarla ilgili sorunlara neden olmaz). Yani adreslerin 0x1000'in katları ile dalgalandığını görüyorsunuz, ancak son üç basamak değişmiyor.

Tanım static int heap[SOME_VAR];, heapstatik depolama süresi ile tanımlanır . Tipik C uygulamaları, yığını değil genel veri bölümünde saklar. "Öbek", dinamik ayırma için kullanılan bellek için bir yanlış adlandırma aracıdır. (Yanlış adlandırmadır, çünkü mallocuygulamalar yığınlarla sınırlı olmayan çeşitli veri yapıları ve algoritmalar kullanabilir. Hatta bir uygulamada birden fazla yöntem bile kullanabilirler.)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.