C dili içinde assembly kullanımı

Download Report

Transcript C dili içinde assembly kullanımı

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 Dili İçinde
Assembly Kullanımı
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
}
GCC Inline Assembly:
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.
Beni dinlediğiniz için teşekkür ederim.