2011-12-12 20 views
9

GCC'nin satır içi birleştiricisini kullanarak kendimi x86 montajı ile tanıştırmaya çalışıyorum. İki sayıyı (a ve b) eklemeye çalışıyorum ve sonucu c içinde saklıyorum. Dört tane farklı denemeye sahibim; son beklenen sonucu üretmiyor.İki sayı ekleme

İlk iki örnek bir ara kayıt kullanır ve bunlar her ikisi de iyi çalışır. Üçüncü ve dördüncü örnekler, iki değeri doğrudan ara kayıt olmaksızın eklemeyi dener, ancak sonuçlar, optimizasyon seviyesine ve girdi değerlerini eklediğim sıraya bağlı olarak değişir. Neyi yanlış anlayacağım?

Ortamı:

int a = 4; 
int b = 7; 
int c; 

Örnek 1:

asm(" movl %1,%%eax;" 
    " addl %2,%%eax;" 
    " movl %%eax,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    : "%eax" 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output: a=4, b=7, c=11 

Örnek 2:

aşağıdaki gibi

i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3) 

İlk olarak, değişkenler bildirilen

asm(" movl %2,%%eax;" 
    " addl %1,%%eax;" 
    " movl %%eax,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    : "%eax" 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output: a=4, b=7, c=11 

Örnek 3:

asm(" movl %2,%0;" 
    " addl %1,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output with -O0: a=4, b=7, c=11 
// output with -O3: a=4, b=7, c=14 

Örnek 4:

// this one appears to calculate a+a instead of a+b 
asm(" movl %1,%0;" 
    " addl %2,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    ); 
printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output with -O0: a=4, b=7, c=8 
// output with -O3: a=4, b=7, c=11 

ÇÖZÜLECEK.Matthew Slattery's answer doğrudur. Önce, b ve c ikisi için eax yeniden çalışıyordu: yerinde Matthew düzeltme önerisi ile

movl -4(%rbp), %edx 
movl -8(%rbp), %eax 
movl %edx, %eax 
addl %eax, %eax 

, şimdi ayrı ayrı c tutmak için ecx kullanır.

movl -4(%rbp), %edx 
movl -8(%rbp), %eax 
movl %edx, %ecx 
addl %eax, %ecx 
+2

Optimizasyon etkin veya etkin olmadan benim için iyi çalışıyor. Derleme dili listesi almak için -S ile derlemeyi deneyin. Sonra hangi kayıtların kullanıldığını görebilirsiniz. – TonyK

+0

Fark ettim ki, optimizasyon seviyesine bağlı olarak farklı sonuçlar elde ediyorum. Kod örnekleri yeni çıktıyla güncellendi. –

+0

Peki montaj listesi size ne anlatıyor? – TonyK

cevap

7

Varsayılan olarak, gcc, satır içi asm bloğunun, çıkış işlenenlerini güncellemeden önce giriş işlenenlerini kullanarak biteceğini varsayacaktır. Bu, hem bir girişin hem de bir çıkışın aynı sicile atanabileceği anlamına gelir.

Ama, bu mutlaka mesela senin örneklerde 3 vaka ve 4.

değil Örneğin 3'te:

asm(" movl %2,%0;" 
    " addl %1,%0;" 
    : "=r" (c) 
    : "r" (a), "r" (b) 
    ); 

... Eğer a (%1) okumadan önce c (%0) güncelledik. gcc hem %0 ve %1 aynı kayıt atamak olursa, o zaman c = b; c += c hesaplar ve dolayısıyla gözlemlemek tam şekilde başarısız olur: gcc anlatarak

printf("a=%d, b=%d, c=%d\n", a, b, c); 
// output with -O0: a=4, b=7, c=11 
// output with -O3: a=4, b=7, c=14 

Sen tamir edebiliriz çıktı terimi may olduğunu

asm(" movl %2,%0;" 
    " addl %1,%0;" 
    : "=&r" (c) 
    : "r" (a), "r" (b) 
    ); 

(gcc dokümanlar "Constraint Modifier Characters" bakın.)

: girdilerin yok edilmeden önce, bu gibi işlenene " &" değiştirici ekleyerek kullanılabilir
+0

Tam olarak bu, teşekkürler. Sorunun, düzeltmeden önce ve sonra derleme listesiyle güncelleştirildi. –

+0

Bunun için teşekkürler! Anlamak zorunda olduğum bir şey ama belgeleme oldukça yasak. Bunun gibi ipuçları çok değerli. – TonyK

0

Hoi, burada bir sorun görmüyorum ve burada derleme yapıyor ve iyi çalışıyor. Ancak, küçük bir ipucu: Adsız değişkenler/kayıtlar ile çok yakında karıştım, bu yüzden adlandırılmış olanları kullanmaya karar verdim. Eklenti size mesela böyle uygulamak thingy:

static inline void atomicAdd32(volInt32 *dest, int32_t source) { 
// IMPLEMENTS: add m32, r32 
__asm__ __volatile__(
     "lock; addl %[in], %[out]" 
     : [out] "+m"(*dest) 
     : [in] "ir"(source)//, "[out]" "m"(*dest) 
     ); 
return; 
    } 

(sadece şimdilik atomik/kilit şeyler göz ardı edebilirsiniz), yapar net ne olur:

1) okunabilir, yazılabilir ne kayıtlar ya da her ikisi de, performans ve saat döngüleri söz konusu olduğunda önemli olan, kayıt işlemleri bellek erişenlerinkinden daha hızlı olduğu için kullanılan (bellek, yazmaç)).

Alkış, G.

P.S. .: Eğer derleyici kodu yeniden düzenler olmadığını kontrol ettiniz mi?