170 likes | 549 Views
KARABÜK ÜNİVERSİTESİ TEKNOLOJİ FAKÜLTESİ MEKATRONİK MÜHENDİSLİĞİ BÖLÜMÜ. MTM 305 MİKROİŞLEMCİLER. Arş. Gör. Emel SOYLU Arş. Gör. Kadriye ÖZ. C D ili İ çinde A ssembly K ullanımı. C/C++ kodu içinde assembly kod yazma.
E N D
KARABÜK ÜNİVERSİTESİ TEKNOLOJİ FAKÜLTESİ MEKATRONİK MÜHENDİSLİĞİ BÖLÜMÜ MTM 305 MİKROİŞLEMCİLER Arş. Gör. Emel SOYLU Arş. Gör. Kadriye ÖZ
C/C++ kodu içinde assembly kod yazma C dili içinde assembly dili programa hız kazandırmak için sıklıkla kullanılan bir yöntemdir. Asm kelimesini kullanarak C/C++ program satırları arasına assembly kodları yerleştirebiliriz ve C/C++ değişkenleri ile değerleri gösterebiliriz.
Avantajları • Assembly dilinde fonksiyonları yazma. • Hız kritik bölümlerin optimize edilmesi. • Aygıt sürücüleri için doğrudan donanım erişimi.
Microsoft Inline Assembly: C dili içerisinde Assembly dili birkaç farklı şekilde kullanılabilmektedir. C kaynak kodu içerisinde herhangi bir yerde asm ifadesi ile assembly kodları kullanılabilir. Kullanım şekli şöyledir. __asm <komut> <operand> <; veya yeni satır> __asm mov al, 01H __asm mov bl, 02H __asm add al, bl
Bu kullanım şeklinde assembly programını oluşturan tüm komut satırlarının başına asm ifadesini yazmak gereklidir. Ama daha kolay bir yolu vardır. Asm bloğu oluşturmak. __asm { mov al, 01H mov bl, 02H add al, bl } __asm bir deyim ayracı olduğunda, assembly kodları aynı satırda da kullanılabilir: __asm mov al, 2 __asm mov dx, 0xD007
__asm Blocklarında Değişken Kullanımı int joe=1234, fred;__asm {mov eax,joe ; eax = joe;add eax,2 ; eax += 2;mov fred,eax ; fred = eax};return fred;
__asm Blocklarında Operator Kullanımı int array[10]; __asm mov array[6], bx ; Store BX at array+6 (not scaled) array[6] = 0; /* Store 0 at array+24 (scaled) */ Diziye ilk referans ölçekli, ancak ikincisi değildir. Eğer bir sabite dayalı ölçeklemeye ulaşmak istiyorsak TYPE operatörünü kullanabiliriz. Örneğin, aşağıdaki ifadeler eşdeğerdir: __asm mov array[6 * TYPE int], 0 ; Store 0 at array + 24 array[6] = 0; /* Store 0 at array+24 (scaled) */
Assembler Fonksiyonu Yazma ; POWER.ASM ; Compute the power of an integer ; PUBLIC _power2 _TEXT SEGMENT WORD PUBLIC 'CODE' _power2 PROC push ebp ; Save EBP mov ebp, esp ; Move ESP into EBP so we can ; refer to arguments on the stack mov eax, [ebp+4] ; Get first argument mov ecx, [ebp+6] ; Get second argument shl eax, cl ; EAX = EAX * ( 2 ^ CL ) pop ebp ; Restore EBP ret ; Return with sum in EAX _power2 ENDP _TEXT ENDS END // Power2_inline_asm.c // compile with: /EHsc // processor: x86 #include <stdio.h> int power2( int num, int power ); int main( void ) { printf_s( "3 times 2 to the power of 5 is %d\n", \ power2( 3, 5) ); } int power2( int num, int power ) { __asm { mov eax, num ; Get first argument mov ecx, power ; Get second argument shl eax, cl ; EAX = EAX * ( 2 to the power of CL ) } // Return with result in EAX }
Kod İçi Assembly Yazım Kuralları • Değişken adlandırma: Değişkenler %,öneki ile başlar. Örneğin eax ve ecx kaydedicileri %eax, %ecx şeklinde kullanılır. • Operandların kullanımı: Intelden farklı olarak ilk operand kaynak ikinci operand hedeftir. Örneğin Intelde "mov eax, edx" c içinde kullanırken "mov %edx, %eax" şeklinde olacaktır. • Operand büyüklüğü: Operandın büyüklüğü opcodun sonuna yazılan harf ile anlaşılmaktadır. “b” (8-bit) byte için,”w” (16-bit) word için,”l” (32-bit) doubleword için. Örneğin "movl %edx, %eax“.
Kod İçi Assembly Yazım Kuralları • Acil Operand: Acil operandların önüne “$”öneki gelir. Örneğin "addl $5, %eax", acil doubleword sayı ile eax’i topla • Hafıza operandları: Eksik operand öneki, bir bellek adresi olduğunu gösterir. Örneğin “movl $bar, %ebx” %ebx içine değişkeninin adersini yerleştirirken, “movl bar, %ebx” %ebx ‘e değişkenin değerini yükler. • Indisleme: Indisleme parantezler kullanılarak yapılır. Örneğin, "movl 8(%ebp), %eax" (%ebp+8 adresi ile işaret edilen içeriği %eax’e taşır.). Tüm kodlar için, Intel x86 işlemciler üzerinde çalışıyor olacak.
Temel kod içi programlama C içinde iki farklı şekilde assembly kullanılabilir. asm("assembly code"); ya da __asm__ ("assembly code"); Örnek: • asm("movl %ebx, %eax"); /* eax =ebx */ • __asm__("movb %ch, (%ebx)"); /* ch’ın değerini (byte ) ebx’in gösterdiği belleğe taşır */
Birden fazla Assembly komut satırı kullanılacaksa ,her birinin sonunda noktalı virgül konulur. #include <stdio.h> int main() { /*10 ve 20 toplanır, sonuç %eax kaydedicisinde saklanır. */ __asm__ ( "movl $10, %eax;" "movl $20, %ebx;" "addl %ebx, %eax;" ); /* 20, 10dan çıkarılır ve sonuç %eax kaydedicisinde saklanır. */ __asm__ ( "movl $10, %eax;" "movl $20, %ebx;" "subl %ebx, %eax;" ); /* 10 ile 20 çarpılır ve sonuç %eax kaydedicisinde saklanır. */ __asm__ ( "movl $10, %eax;" "movl $20, %ebx;" "imull %ebx, %eax;" ); return 0 ; }
Genişletilmiş Assembly Genişletilmiş assembly, biz de operand belirtebiliriz. Bu bize giriş kaydedicilerini, çıkış kaydedicilerini ve değeri değişen kaydedicilerin bir listesini belirlemenizi sağlar. asm ( "assembly code" : cıkış operandları /* seçimlik*/ : giriş operandları /* seçimlik */ : overwrite edilen operandların listesi /* seçimlik */ ); Örnek asm ("movl %%eax, %0;" : "=r" ( val ));
Örnek: int no = 100, val ; asm ("movl %1, %%ebx;" "movl %%ebx, %0;" : "=r" ( val ) /* çıktı */ : "r" ( no ) /* girdi*/ : "%ebx" /* overwrite */ ); Yukarıdaki örnekte, çıkış işleneni "val“ % 0 ile anılır, giriş işlenen “no“ % 1 ile anılır. “r" operantlar için bir kısıtlamadır, böylece GCC herhangi bir kaydediciyi kullanabilir.