2012-01-25 49 views
10

Ben DumpBin kullanarak (büyük olasılıkla Visual C++ derleyicisi kullanılarak oluşturulan) bir nesne dosyası sökülüp aşağıdaki kod parçasını gördü:Derleyici neden bu kodu oluşturuyor?

...   ... 
mov   dword ptr [ebp-4],eax  // Why save EAX? 
push  dword ptr [ebp+14h] 
push  dword ptr [ebp+10h] 
push  dword ptr [ebp+0Ch] 
push  dword ptr [ebp+8] 
mov   eax,dword ptr [ebp-4]  // Why restore EAX? Did it change at all? 
call  <function> 
...   ... 

EAX kayıt kaydedilir ve bu 4 genelinde restore ediliyor neden birinin açıklayabilir misiniz push talimatları?

+2

Derleyicileri, bundan daha fazla bir şey yaptıklarını gördüm ... – Mysticial

+0

@Mysticial: Oh lol ... ilk defa böyle bir şey fark ettim. :) İyi bilmek. – Mehrdad

+7

Belki de ilk basamağa bir dal var. –

cevap

9

Ayrıca, belki de serbest bırakma modunda derlenmiştir, ancak bu değişken olarak işaretlenmiştir, bu da derleyiciye böyle bir değişkenin bilmeden değişebileceğini söyler, böylece sürekli olarak yazma/yığma üzerine yazmak/geri yüklemek zorunda kalır o function, Windows CS_SYSCALL çağırma kuralını kullanarak yani __syscall ilanı halinde

+0

Ahhhh bu oldukça mümkündür! +1 teşekkürler. – Mehrdad

+0

Buradaki “uçucu” nun bir fark yaratacağından emin değilim. “volatile” bir bellek konumuna aittir, ancak EAX bir kayıttır; Bir kaydı uçucu olarak işaretleyemezsiniz. Bu yüzden, 'uçucu', [ebp-4] 'ün her operasyondan hemen önce * yeniden yüklendiğini (eap-4) açıklayacağını, ancak kurtarılmasının değil. – Crashworks

+0

Belli aritmetikler için derleyici _has_, bir yazmaç içine uçucu olarak işaretlenmiş bir bellek konumu yüklemek içindir, çünkü işlem okuma-değiştirme-yazma komutu olarak mümkün değildir. Bu kod segmentinden sonra bir mağaza takip edilebilir ve bundan önce bir yük önceden yüklenebilir, bu nedenle eldeki bilgilerden mutlakeleyebilir. Ancak, sadece VC tarafından yapılan cevapsız bir optimizasyon değil. – hirschhornsalz

6

Bu, hata ayıklama modunda oluşturuldu mu? Öyleyse, derleyici her yerel değişkeni yığında saklar, böylece hata ayıklayıcı bunları tutarlı bir şekilde bulabilir.

Bu tür gereksiz depoların ve yeniden yüklemelerin seçilmesi, "serbest bırakma" modunu oluşturan en iyileştirmelerden biridir.

+0

Sürüm * kodunun * olduğu varsayılan * olduğuna inanıyorum (herhangi bir yerde görebildiğim bir şeyin 'hata ayıklama' sürümü yok ...), ama emin değilim ... Kaynak kodum yok ya. Ama +1 makul bir tahmin, teşekkürler. – Mehrdad

2

volatile ya da olmasın, EAXWindows üzerinde bir işlev çağrısı yapmadan önce doğrudan başlatılması için olurdu neden sadece teknik nedeni idi. Kavramsal olarak, bu, %al'un %xmm kayıt defterinde geçirilen kayan nokta türü arşivi içerdiği UN * X x86_64 sözleşmesine biraz benzer.

Windows'ta sistem çağrısı çağrı kuralı __cdecl ile aynıdır, yani yığın üzerinde ters sırada işlevler, ancak ek olarak AL argüman sayısını içerir; Bu, genellikle bunun son ucunda bulunan çekirdek kodunun, arjları geri almak için kullanıcı yığınından çekirdek yığınına ne kadar veri okunacağını bilmesi için yapılır.

EAX, 32bit Windows'daki tüm çağrı kuralları için bir not defteridür, değeri hiçbir zaman arama yapmadan önce işlev çağrıları üzerinden korunmaz, bir çağrı yapmadan önce doğrudan başlatılır. Sahip olduğu değişken volatile olsa bile - basit bir yeniden yükleme bellek bariyeri değildir ve önceki bir depoyu "taahhüt etmez". Ayrıca, [EBP - 4] konumu yığınının içinde yer aldığından, değişken yerel (ve volatile niteleyicinin çok az anlam ifade etmemektedir). Bir cevapsız optimizasyon değilse

o zaman

__syscall printf_syscall_conv(char *fmt, ...); 

void possibly_print_three_vals(char *fmt, int val1, int val2, int val3) 
{ 
    if (*strchr('%', fmt) == '\0') // if no "%" in fmt, pass no args 
     printf_syscall_conv(fmt); 
    else 
     printf_syscall_conv(fmt, val1, val2, val3); 
} 

Bu programlar sayesinde sizin gibi montaj çıktı yaratabilecek, varsayımsal argümanlar gibi farklı sayıdaki ile __syscall function(...) bir çağırma olabilir.

İlgili konular