derleyici yığında statik ayırma yerine, otomatik ayırma oluşturur oldukça büyüktür. Statik diziler, COMMON adlı sözde bir tahsisat oluşturan .comm
derleme yönergesiyle oluşturulur. Bu bölümdeki semboller toplanır, aynı adlandırılmış semboller birleştirilir (istenen en büyük boyuta eşit büyüklükte bir sembol isteğine indirgenir) ve daha sonra dinlenme, çoğu çalıştırılabilir formattaki BSS (başlatılmamış veri) bölümüne eşlenir. ELF çalıştırılabilirleri ile .bss
bölümü, veri segmentinde, yığının veri parçası kısmından hemen önce yer alır (veri bölümünde yer almayan anonim bellek eşlemeleri tarafından yönetilen başka bir yığın parçası vardır).
small
bellek modeliyle 32 bit adresleme yönergeleri, x86_64 üzerindeki simgeler adreslemek için kullanılır. Bu, kodu daha küçük ve daha hızlı hale getirir. small
bellek modeli kullanan bazı montaj çıkışı:
movl $bar.1535, %ebx <---- Instruction length saving
...
movl %eax, baz_+4(%rip) <---- Problem!!
...
.local bar.1535
.comm bar.1535,2575411200,32
...
.comm baz_,12,16
Bu içine bar.1535
sembolün değerini (bu değer sembol konumu adresine eşittir) koymak için (5 bayt uzunluğunda) 32 bit hareket talimatı kullanır RBX
kaydının alt 32 biti (üst 32 biti sıfırlanır). bar.1535
sembolünün kendisi .comm
direktifi kullanılarak tahsis edilmiştir. baz
COMMON bloğu için bellek daha sonra ayrılır. bar.1535
çok büyük olduğu için, baz_
, .bss
bölümünün başlangıcından itibaren 2 GiB'den fazla biter. Bu, RIP
olmayan 32bit (imzalı) ofset EAX
değerinin EAX
değerinin taşınması gereken b
değişkenini adreslemek için kullanıldığından ikinci movl
yönergesinde bir sorun teşkil etmektedir. Bu sadece bağlantı sırasında tespit edilir. Montajcının kendisinin uygun ofseti bilmediğinden, yönerge göstergesinin (RIP
) değerinin ne olacağını bilmediğinden (kodun yüklendiği mutlak sanal adrese bağlıdır ve bu, linker tarafından belirlenir) Sadece 0
bir ofset koyar ve daha sonra R_X86_64_PC32
türünde bir relokasyon isteği oluşturur. Bağlayıcıya, gerçek ofset değeriyle 0
değerini yamaları talimatını verir. Ancak, bu, offset değeri, işaretli 32 bitlik bir tam sayı içine sığmayacağı ve bu nedenle kurtarıldığı için bunu yapamaz.yer şeylerde medium
bellek modeli ile
şuna benzer:
movabsq $bar.1535, %r10
...
movl %eax, baz_+4(%rip)
...
.local bar.1535
.largecomm bar.1535,2575411200,32
...
.comm baz_,12,16
64 bit acil hareket talimatı (10 bayt uzunluğunda) adresini temsil 64 bit değeri koymak için kullanılır İlk bar.1535
kayıt R10
içine. bar.1535
sembolünün hafızası .largecomm
direktifi kullanılarak tahsis edilir ve dolayısıyla ELF'nin .lbss
bölümünde sonlanır. .lbss
, ilk 2 GiB'ye sığmayan sembolleri saklamak için kullanılır (ve bu nedenle 32-bit yönergeler veya RIP'ye göre adresleme kullanılarak adreslenmemelidir), daha küçük şeyler .bss
'a gider (baz_
hala .comm
ve .largecomm
değil). .lbss
bölümü, ELF linker komut dosyasında .bss
bölümünden sonra yerleştirildiğinden, baz_
, 32 bit RIP ile ilgili adresleme kullanılarak erişilemez duruma gelmez.
Tüm adresleme modları System V ABI: AMD64 Architecture Processor Supplement'da açıklanmaktadır. Ağır bir teknik okumadır ancak 64 bit kodun çoğu x86_64 Unix üzerinde nasıl çalıştığını anlamak isteyen herkes için okumalıdır.
movl $2575411200, %edi
...
call malloc
movq %rax, %rdi
Bu temelde RDI = malloc(2575411200)
olup: bir ALLOCATABLE
dizi yerine kullanılır
, gfortran
(büyük olasılıkla tahsisi büyük boyutlu verilen anonim bellek haritası olarak uygulanır) yığın bellek ayırır. Daha sonra bar
unsurları itibaren RDI
depolanan değerin pozitif teknikleri kullanarak erişilir: bar
başlangıcından itibaren en fazla 2 GiB olan yerler için
movl 51190040(%rdi), %eax
movl %eax, baz_+4(%rip)
, daha ayrıntılı bir yöntemi kullanılır. Örneğin. hiçbir şey dinamik ayırma yapılmış olacağını adresi hakkında varsayılır beri
; Some computations that leave the offset in RAX
movl (%rdi,%rax), %eax
movl %eax, baz_+4(%rip)
Bu kod
bellek modeli etkilenmez:
b = bar(12,144*144*450)
gfortran
yaydığı uygulamaktır. Ayrıca, dizi etrafından geçmediğinden, hiçbir tanımlayıcı oluşturulmuyor. Bir varsayılan şekilli diziyi alan ve buna
bar
geçiren başka bir işlev eklerseniz,
bar
için bir tanımlayıcı otomatik bir değişken olarak oluşturulur (yani
foo
yığınında).
boo
beyan bir arayüze sahip benim örnek durumda
call boo(bar)
içinde (
movl $bar.1580, %edi
...
; RAX still holds the address of the allocated memory as returned by malloc
; Computations, computations
movl -232(%rax,%rdx,4), %eax
movl %eax, baz_+4(%rip)
ilk hareket, bir işlev çağrısı argüman hazırlar: dizi SAVE
özelliği olan statik yapılırsa, açıklayıcısı .bss
bölümünde yerleştirilir varsayılan şekilli bir dizi alarak). bar
dizi tanımlayıcısının adresini EDI
içine taşır. Bu 32-bitlik bir hamledir, bu yüzden tanımlayıcının ilk 2 GiB'de olması beklenir. Nitekim, böyle hem small
ve medium
bellek modellerinde .bss
ayrılır:
.local bar.1580
.comm bar.1580,72,32
Bu çok güzel bir açıklama. Teşekkürler. Bu bana, bu şeylerin bir demetine (aradığım şey) daha çok bakmaya başlamak için iyi bir başlangıç sağlar. – mgilson
@mgilson, sadece cevabın şeyiyle ben de bar' başka bir alt tanımlayıcı tarafından geçirildiğinde 'olanlara açıklamalar ekledik. –