Subject : Inline ASM Author : pOiSOn Email : poisone@usa.net Irc : irc.ada.net.tr / #scene.tr #manowar #atheist ICQ : 6795916 LastUpdate : biraz once ne yedin deseniz hatirlamam... Note : DOS hicbir zaman olmez! (linuxda fena degil...) assembler. hmm.. assembler çok uzun bir konu .. :) assembler'a giris için her zaman turbo pascal'i tavsiye ederim.. kullanim acisindan en rahat ortam pascal... pekala neden asm'de yazmak ihtiyacimiz var ??... cok basit.. hiz.. bundan baska bir sebep icin asm kullanmak bence pek gerekli degil.. (tabi bazi durumlar haric :) ) tavsiye olunan alet edavatlar.. en temelde bir turbo pascal veya watcom c (mumkunse en son version) veya da borland c veya tasm.. ve tabiki bir yerlerden opcode (komut) larin hangi ise yaradigini yazan bir kitap veya dokuman bulun... (www.x86.org) pascal altinda asm... pascal altinda asm kullanmak cok basit asm diyip asm ile devam ediyorsunuz .. :) (bi not: uzun zamandir pascal ile yazmadim syntax hatalari olabilir..) procedure OpenGraph(); begin writeln('Opening graphic screen'); asm mov ax,0013h int 10h end; { ebelek gobekek.. falan filan...} end; veya procedur tamamen asm olacaksa procedure OpenGraph(); assembler; asm mov ax,0013h int 10h end; diyebilirsiniz... eveett geldik pascal'dan vazgecmeme sebep olan noktaya .. biraz onceki opengraph procedure'unu asmde yazmamiza ragmen sevgili TP compiler'i procedure'e girmeden once tum registerlari saklamakta (exe icinde gorulebilir)... bunun icin asm bloklarinizi boyle ayri procedure yapmaktansa ana blok icinde yazarsaniz compiler buna gore kontrol yapiyor...(her zaman degil, nedenini sormayin..) gelelim c dilinee.. burdada farkli compilerlarda yazim degisebilir fakat duzen olarak ayni.. void opengraph() { _asm { mov ax,0013h int 10h } } veya blok belirtmeden...inline olarak.. _asm mov ax,0013h _asm int 10h not: bazi compilerlar asm yazabilmek icin programin basina < #pragma inline > yazmanizi gerektirebilir...(watcom c mesela..) mesela mi ? mesela asagidaki func. string seklindeki bir sayiyi iki ile carpmak icin yazildi.. void Mul2(char * Str,int StringSize) { register int s1; // register !! int elde; elde = 0; for(s1=StringSize;s1 > 0; s1--) { register int byt; // register !! byt = Str[s1] + elde; byt = byt * 2; if (byt > 255) { elde = 1; byt &= 0xFF ; } else { elde = 0; } Str[s1] = byt; } if (elde != 0) Str[s1] = elde; } carpma kisminin dongu icindeki kisimlari asm ile yazmak gerektinde.... void TBank::Mul2() { register int s1; char elde; elde = 0; for(s1=StringSize-1; s1 > 0; s1--) { char byt; byt = Str[s1]; // byte'i 1 kez sola kaydir tasma varsa tasma = 1 yap. _asm { mov al,byt shl al,1 jc tasmavar or al,elde mov elde,0 jmp cik tasmavar: or al,elde mov elde,1 cik: mov byt,al } Str[s1] = byt; } if (elde == 1) { Str[s1] = elde; } } pekala sizce hangisi hizlidir ?....(bu islem biraz daha kisaltilabilir fakat anlasilmasi acisindan boyle daha iyi) sanirim konu anlasildi... asm konusu pascal'da c'de oldugunun aynisi tanimladiginiz degiskenleri asm bloklari icinde kullanabilirsiniz... dikkat edilecek ikinci nokta degistirdiginiz registerlari saklama konusu.. ornekde ben eax registerini saklamadim.. cunku genel olarak kullanilan bir registeri saklamak ana program icerisinde herhangi bir degisiklik yapmaz.. ama bu mesela segment registerlarini, stack registerlarini, si,di,cx gibi kullanilabilmesi tahmin edilen registerlari saklamak daha guvenli bir yoldur. bir not daha procedurler icinde tanimladiginiz variablelari mumkun oldugunca kullanmayin cunku bunlar stackdan cagrilir ve bunun icin compiler'iniz ek kodlar ekler.. cok kullandiginiz degiskenleri global tanimlamanin hic bir zarari yokdur.. (sadece exenin boyu bir kac byte artar..) pekala simdi size son bir ornek daha... iste size pure c olarak yazilmis bir putpixel.. hizli gorunuyor degilmi ? void putpixel(register int X,register int Y,register color) { register unsigned char * offset; offset = (unsigned char *) ( Y * 320 + X + VGA) *offset = color; } ve bunu debug yapalim bakalim...(watcom c'de derlendi.) 005C putpixel_: 005C 56 push esi 005D 57 push edi 005E 55 push ebp 005F 89 E5 mov ebp,esp 0061 81 EC 18 00 00 00 sub esp,0x00000018 0067 89 45 E8 mov -0x18[ebp],eax 006A 89 55 EC mov -0x14[ebp],edx 006D 89 5D F0 mov -0x10[ebp],ebx 0070 89 4D F4 mov -0xc[ebp],ecx 0073 69 55 EC 40 01 00 00 imul edx,-0x14[ebp],0x00000140 007A 03 55 F4 add edx,-0xc[ebp] 007D 8B 45 E8 mov eax,-0x18[ebp] 0080 01 D0 add eax,edx 0082 89 45 FC mov -0x4[ebp],eax 0085 8A 45 F0 mov al,-0x10[ebp] 0088 8B 55 FC mov edx,-0x4[ebp] 008B 88 02 mov [edx],al 008D 89 EC mov esp,ebp 008F 5D pop ebp 0090 5F pop edi 0091 5E pop esi 0092 C3 ret hizli gibi fakat bir putpixel icin biraz yavas... bunu birde asm altinda yazalim.. void putpixel(int x,int y,int color,unsigned char * segment); #pragma aux putpixel=\ "shl edi,6"\ "lea ebx,[ebx+esi]"\ "lea edi,[edi*4+edi]"\ "mov [edi+ebx],al"\ parm [ebx] [edi] [eax] [esi]\ modify [edi ebx]; parm fonksiyona gecilen parametrelerin hangi registerlara yuklenecegini, modify ilede fonksiyon icinde degisen registerlari belirtiyorsunuz.. daha parm ve modify icin watcom c'nin manuallarina bakmanizi tavsiye ederim..(burda anlatirdim ama manuallari her zaman okumak daha iyidir) hmm.. 4 komut..peki birde lookup table kullanirsak... int YTable[200]; // her n. eleman icin n*320 degerini tutar.. ... ... void putpixel(int x,int y,int color,unsigned char * segment); #pragma aux putpixel=\ "lea edi,YTable[edi*4]"\ "mov [edi+ebx+0xa0000],al"\ parm [ebx] [edi] [eax] [esi]\ modify [edi ebx]; nihayetinde 2 komuta dusurduk... sanirim asm'nin nerede gerektigi konusu anlasilmistir..