PDA

Orijinalini görmek için tıklayınız : Assebler


Sayfa : [1] 2 3 4

petricli
14-06-05, 12:00
Abdullah Gök tarafından derlenmiştir.

Assembler (1)

Giris

Assembler merkezi islemci olan bütün sistemlerde ve isletim sistemlerinde "kullanici - program - makine" iletisimi saglayan ve sembolik komutlar sayesinde programlamayi sayilar düzeyinden sembollere çikaran bir dildir. Normalde merkezi islemci (CPU) komutlari 1 ve 0 olarak anlar ve buna göre yapilmasi gereken islemleri yerine getirir.Kisacasi Assembler dili bir makine dilidir diyebiliriz…

ASCII mantigi

Herhangi bir EXE dosyaya bir editor ile baktigimiz zaman anlamsiz ve karmasik birçok semboller ve karakterler görürüz. Bunlar o an orada bulunan sayilara karsilik gelen ve ASCII olarak adlandirilan sembollerdir. Bu semboller hem sayilari,hem büyük/küçük harfleri,hemde birçok isareti içerir. ASCII tablosu 256 isaretten meydana gelir ve her sayi karsiligi bir semboldur. Ilk 32 karakter kontrol karakterleri adi verilen ve görülmeyen karakterlerdir.Bunlar yazici, string gibi islemlerde tek baslarina yada birden fazla görev alirlar. Örnegin 7 sayisi ASCII karakterlerinde \'BEEP\' anlamina gelir ve programinizda eger \'deneme yazisi\',7,0 seklinde kullanirsaniz yazi sonrasi bir \'beep\' sesi duyarsiniz. Yada 10 ve ardindan 13 kullanirsaniz yaziniz bir satir asagiya inip paragrafin en basina gelir. Örnegin: \'deneme yazisi\',10,13,0

48 - 58 arasi ise sayilardir. Buna göre:

48 = \'0\'
49 = \'1\'
50 = \'2\' ....

sayi sekillerine denk gelir ve bu standarttir.

Büyük harfler 65\' den baslar 90\' a kadar devam eder. Ayni sekilde küçük harflerde 97 ile 122 arasindadir. Bundan sonra 256 sayisina kadar karsilik gelen karakterler özel karakterlerdir. Bunlarla pek çok sekil olusturulabilir.

Sayi sistemleri

Yukarida verdigim örnekleri inceleyenler ve herhangi bir hex editör ile dosyalara bakanlar bir gariplik oldugunun farkina varmislardir. Hex editörde bütün sayilar iki basamakli ve içinde a,b,c,d,e,f gibi karakterler içeriyor. Ayrica 1 karakterine karsilik gelen sayi yukaridaki gibi 48 degil 30 oldugunu görürler. Iste programlar daha derli toplu oldugu için, ASCII gösterimine daha yatkin oldugu için ve diger sayi sistemlerine göre daha kullanisli oldugu için "Onaltilik sistem" diye adlandirilan hex (hexedecimal) sistemi kullanirlar. Burada sunu açiklamakta yarar var, hex sistemi sadece kullanicilar ve programcilar içindir. CPU sadece 1 ve 0 dan olusan ikili sistemi (binary) anlar.

Simdi konuyu toparlarsak üç degisik sayi sistemi oldugunu görürüz:

1 - Onluk sayma sayilari (dec) 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16... seklinde devam eden bildigimiz sayi sistemi...

2 - Onaltilik sayilar (hex) 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,10,11... seklinde devam eden ve "a...f" arasi ekstra olarak 6 sayi daha fazlaligi olan sayi sistemi...

3 - Ikili sistem (binary) 0,1 Bu sistemde ya sifir yada bir olacaktir. 0 kapali 1 ise açik mantigindadir. Bu sistem makina dilinin temelini olusturur ve programlamasi ve yazmasi çok oldugu için assembler diline gerek duyulmustur...

Normal sayilar hepmizin ilkokuldan beri ögrendigi sayi sistemidir. Sayi dizilimi 0 ile 9 arasidir ve her 9 sonrasi bir alt basamak bir yükselir.

Onaltilik sistemde toplam basamak yükseltme sayisi 16\' dir. Biz normal sayma sisteminde 9 sayisindan sonra 10 geldigini biliyoruz. Onaltilik sistemde ise 9 sayisindan sonra 0A,0B,0C,0D,0E,0F ve bundan sonra 10 gelir. Dolayisiyla 0A onaltilik sayisi normal sayi sisteminde 10 sayina esit gelir. Ayni sekilde 10hex sayisi normal sayi sisteminde 16 sayisina esit gelir. Kisaca onaltilik sayi sistemi 16\' nin katlari seklinde büyür.

Assembler programlarinda kullanilan sayilar su sekillerde simgelenerek birbirinden ayrilirlar:

- \'d\' harfi yada harfsiz bu bildigimiz onluk sistemde demektir. Eger bir kaynak kodunda sayinin yaninda (önceden bütün sayilarin hex olacagini belirten .radix16 gibi bir komut kullanilmamissa) hiçbir simge yoksa o sayi göründügü degerinde bildigimiz onluk tabanda bir sayidir. Eger onaltilik kurallariyla yazilmis (a,b,c,d,e,f içerikli) ve yaninda hiçbir isaret yoksa derleyici burada \'illegal number\' seklinde bir hata mesaji verir.

-\'h\' harfi ise her zaman onaltilik sistemde bir sayi oldugunu belirtir. Bu durumda normal onluk sistemde bir sayi yazip yanina \'h\' koyarsaniz bu sayi onaltilik olarak kabul edilecek ve yazdiginiz deger degilde onaltilik sistemin degerini alacaktir. Eger onaltilik bir sayi ve yanina \'h\' isaretini koyarsaniz o sayi onaltilik olarak ve verdiginiz degerde kabul edilecektir.

-\'b\' harfi ise ikilik sistemi belirtir ve adi üzerinde sadece 1 ve 0 kullanabilirsiniz. Aksi halde hata mesaji verir. Asagida hesaplamasini göreceksiniz ama önbilgi olarak vermek gerekirse yazmadiginiz basamaklar daima 0 olarak kabul edilecektir.

Örnekler:

323 ----> onluk sayi sisteminde ve degeri 323
323d----> onluk sayi sisteminde ve degeri 323
323h----> onaltilik sayi sisteminde ve degeri 803

02a-----> Hatali sayi. Içinde onaltilik sayi sistemine ait \'a\' kullanilmis ama sayinin ne oldugu belirtilmemis
02ah----> Onaltilik sayi onluk karsilik degeri 42

1110b--> Ikilik sistemde bir sayi ve normalde 00001110b olarak kabul edilir ondalik 14, onaltilik 0e sayisina denk gelir
1310b--> Hatali sayi yaninda \'b\' ile ikilik oldugu belirtilmesine ragmen içinde 3 sayisi mevcut. 1 veya 0 olmak zorunda.

Çevrimler ve hesaplamalar:

Buraya kadar herkes bir fikir sahibi olmustur. Burada da bunlarin nasil ve neden böyle oldugunu görecegiz. Öncelikle sunu belirtmem gerekiyor: onluk zaten biliyoruz ama onaltilik ve ikilik sistem mutlaka bilinmesi gerekiyor. Programlarinizda, denemelerinizde hep bu sistemler kullanilacak. Komutlar hep bu sistemlere göre çalisacak ve bazilari sadece bu sistemlerdeki degerlere göre hareket edecek. Bunun için bir assembler programcisinin mutlaka bu sistemleri bilmesi ve kullanmasi gerekiyor.

Normal bildigimiz sayma sayilarinin 0 dan baslayip 1,2,3,4,5,6,7,8,9,10,11... gibi gittigini biliyoruz. Ona onluk sistem adini veren kural ise her 10 sayi sonrasi bir basamak altini basamak atlatmasidir. Onaltilik sistem ise yine 0 dan baslayip 1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,10,11.. seklinde devam eder. Burada görüldügü gibi onaltilik sistem her 16 sayi sonrasi basamak atlatiyor. Ayrica a,b,c,d,e,f olmak üzere 6 tane daha fazladan sayiya sahip. O zaman onaltilik bir sistemde deger 10 ise onluk sistemede o sayi 16 demektir. Yani 16 nin katlari olarak artmaktadir.

10h = 16
20h = 32
a4h = 164 gibi...

Onaltilik bir sayiyi onluk sayiya nasil çeviririz?

Önce en kolay sekliyle baslayalim. Yukaridaki örnekte a4h onaltilik sayisinin 164 oldugunu görüyoruz. a4h sayisina bakinca iki basamaktan oldugunu biliyoruz ve yine biliyoruz ki onaltilik sayi sistemi 16\' nin katlari ile büyür ve \'a\' harfinin onluk sistemdeki degeri 10 , o zaman elimizde 0a +0 seklinde bir sayi var:

0a* 16 + 4 olacak. 0a = 10 olduguna göre: 10 *16+4 = 164

Birinci basamak her zaman kendi degerindedir. Sayi 0ah,0bh,0ch.. olsa bile onluk sisteme çevirilince birlik basamak olarak digerlerine eklenir. Diger basamaklarda ayni bildigimiz matematik kurallarinda oldugu gibi basamak çarpani esas alinarak çarpilir. Nasilki 164 sayisinin 16*10+4 oldugunu biliyorsak onaltilik sistemde de 164 sayisinin 0ah*10+4 oldugunu biliriz.

Daha büyük sayilarda onaltilik sistemden onluk sisteme çevrim söyle yapilir:

Elimizde 03f4ah gibi bir sayi oldugunu farzedelim. Bu sayi "3 - f - 4 - a" olarak 4 basamakli ve onaltilik sistemde. Her zaman sondan basliyoruz ve 2\'1, 2\'2, 2\'3 gibi gidiyoruz. Burada çarpan sayilari daima sabittir.

Basamak Çarpan Üs 2\'
------------- ------------ -------------------
1 1 1 * 1
10 64 16 * 16
100 256 16 * 64
1000 4096 16 * 256
10000 65535 16 * 4096
100000 1048576 16 * 65535
1000000 16777216 16 * 1048576
10000000 268435456 16 * 16777216

gibi öyleyse bizim sayimizi bulmanin zamani geldi

0ah * 1 = 10
04h * 16 = 16 * 4 = 64
0fh * 256 = 15 * 256 = 3840
03h * 4096 = 03 * 4096 = 12288

Toplam : 10+64+3840+12288 = 16202

Biraz zor gibi gözüksede alistirma yaptikça daha çok anlasilir. Zaten çogu kez bende büyük sayilarin çevriminde Windows\' un hesap makinasini kullaniyorum. Bunun assembler rutin yazip çevirmek yada _wsprintf gibi bir fonksiyonunu kullanmak aslinda daha kolay. Ama mantiginin bilinmesi gerekir.

Ondalik sayilarin ikili sisteme çevrilisi

Ondalik bir sayiyi ikilik bir sayi sistemine çevirmek çok kolaydir. Öncelikle ikilik bir sayinin 1 ve 0 sayilarindan olustugunu hatirlayalim. Bu düzen nasil olusur? Bir sayi ikiye ya tam bölünür yada kalanli bölünür. Eger tam bölünüyorsa 0, kalanli bölünüyorsa 1 olur. Kalanli bölünme drurumunda 1 olur ve sayidan bir eksiltilerek isleme devam edilir. Örnegin:

22 /2 0
11/2 1
5/2 1
2/2 0
1/1 1

olur ve daima tersden yazilarak ikili sisteme çevrilmis olur. O zaman 22 ondalik sayisi 10110 ikili sistemine esit olur. Bu islem esasen bundan sonraki konuda görecegimiz bitlere ayirma islemidir.

Bit, Byte, Kilobyte, Megabyte, Gigabyte...

Her zaman duyariz su program diskte su kadar kilobyte yer kapliyor diye. Yada yeni bir disk aldim 80gb gibi. Bunlar aslinda datanin uzunlugudur. Yani verinin kapladigi alandir. Bu büyüklükler temeldir ve disk,hafiza, program içinde aynidir. Sadece bit büyüklük olarak farklilik gösterir ancak digerleri hep 1024\' ün katlari olarak artar ve birimlenir.

1 bit en fazla 1 birim olabilir,
1 byte 0 ile 256 arasinda deger alir.
1 kilobyte 0 ile 65535 arasinda deger alir.
1 megabyte 0 ile 4294967295 arasinda deger alir.

petricli
14-06-05, 12:00
Birimler sirasiyla su sekilde küçükten büyüge dogru siralanir: bit, byte, kilobyte, megabyte, gigabyte, terabyte... Burada en küçük birim olan \'bit\' tek basina kendiden sonraki birimin 8/1 ni olusuturur. Kisaca açarsak 1 byte = 8 bittir. Ayni sekilde 2 byte 16 bittir. Bunu söyle göstererek daha iyi anlasilir hale getirebiliriz:

Elimizdeki sayi: 256 ve bu sayinin onaltilik sekli 0FFh, bunu ikili sisteme çevirirsek :

256/2 0
128/2 0
64/2 0
32/2 0
16/2 0
8/2 0
4/2 0
2/2 0
1/1 1

sonucunu elde ederiz. bu durumda 256 sayisi 1 byte ve 8 bitten olusur. Bu 8 tane bitin illaki 1 ve 0 olmasi gerekmez. Sonuçta 8 tane 1 veya 0, 1 byte\'i olusturur. Byte ile beraber bütün üst birimler 1024 \' ün katlari olarak artar.

1024 byte = 1 kb (kilobyte)
1024 kb = 1 mb (megabyte)
1024 mb = 1 gb (gigabyte)
1024 gb = 1 tb (terabyte)

Seklinde açiklanabilir. Makine dili islemleri CPU\' a ikili sistemde gönderildigini söylemistik. Yukaridaki birimlere bakinca sadece ikili sistemde programlamanin ne kadar zor oludugu görülmektedir. Assembler dili bunun için gelistirilmistir. Kullandigimiz programlar dili veya arabirim ne olursa olsun sonuçta assembler kodlarina döner. Kullandigimiz *.exe ve *.com gibi dosyalar aslinda assembler dilinden olusan makine dilini içerir ve program hafizada çalismaya baslayinca CPU\' a (merkez islem birimi) 1 ve 0 olarak çevrilerek gönderilir. Delphi, C++, VB gibi dillerde kullandigimiz hemen hemen bütün komutlar semboliktir. Bu komutlara karsilik gelen makine komutlari setleri vardirki bunlar sayesinde tekrar tekrar ayni kodlari yazmak yerine daha düzenli ve daha optimize bir sekilde makine dili programlari olusturulabilir. Makine dili assemblerdir. Tüm assembler komutlarina birden "opkod" olarak isim verilir.

petricli
14-06-05, 12:02
Abdullah Gök tarafından derlenmiştir.

Assembler (2)

Registerler

Registeler en basit sekilde söyle anlatilabilir: a=1 Burada "a" isimli bir degiskenimiz var ve ona bir degerini atiyoruz. Bundan sonra yeni bir deger atamadigimiz sürece a her zaman 1 olacaktir. Aynen bunun gibi CPU\' nun her türlü islemlerini yerine getirmesi için isimleri sabit registerleri vardir. Bunlari yukaridaki gibi degiskenlere benzetebilirsiniz. Bunlar;

AX ,BX , CX, DX = Bunlar matematiksel ve mantiksal islemlerde kullanilir. Bu registerler çalisan özel opkodlar vardir.
SI, DI = Yazi, veri arama veya aktarimi gibi islemler
BP, SP = Yigin islemleri ile ilgili
IP = Komut noktasi o andaki nokta
ES, DS, CS, SS = Segment islemleri ile ilgili
F = Bayrak registeri, Bu registerin bitlerine göre islemler yapilir yada yapilmaz

Bunlardan baska korumali modu sistem ile ilgili DR(0)-DR(7) ve matematik islemcisi St(0) - St(7) registerleri bulunmaktadir. Ayrica MMX ile birlikte yeni registerler gelmistir.

Registerler kullanim sekline göre yada yapilarina göre deger alabilirler. Örnegin; AX register diger BX,CX,DX registerler gibi 8 bit 8 bit seklinde deger alabilir yada tamamen 16 bit seklinde deger alabilir. Açilimi söyledir:

AX = AL ve AH
BX = BL ve BH
CX = CL ve CH
DX = DL ve DH

Burada \'L\' low demektir ve ilk 8 biti (1byte) temsil eder. \'H\' ise high demektir ve son 8 biti (1 byte) temsil eder.

SI, DI registerler genel amaçli kullanildiklari gibi islemcinin tahsis ettigi bazi özel komutlarla beraber veri aktarma, doldurma, silme yada karsilastirma islemlerini yerine getirir.

SI, DI, BP, SP, IP,ES,CS,DS,SS, FS, GS,F registerler daima 16 bittir (2byte) ve yukaridaki registerler gibi düsük-alçak bit seklinde ayrilmazlar. Ancak komutlarla bu bitlere müdahale ve degistirmek mümkündür.

AX,BX,CX,DX registerler matematiksel islemler, lojik islemler, sayma islemleri, ve bazi komutlarla string islemlerinde kullanilir.

AX register "akümulatör" olarak adlandirilir. Bu register ile çalisan ve sonuçlari bu registere aktaran pek çok opkod vardir.

BX register "base = taban" register olarak adlandirilir. Örnegin XLAT gibi komutlar bu register ile çalisir ve genelde AX registere yakin ve yardimci olarak kullanilan bir registerdir.

CX register "counter = sayaç" olarak nitelendirilir. Bu register sayaç ve döngü konularina tahsis edilmistir. Yine pek çok opkod bu registere göre sayma ve sonuçlandirma islemleri yapar.

DX register yine diger registerler gibi birçok islemde kullanildigi gibi bölüm sonu kalan sayisi için AX registerle beraber kullanilir.

Bu registerler DOS ortaminda 16 bit yada 8 bit olarak çesitli interrupt (kesme) fonksiyonlarinida olustururlar.

CS,DS,ES,GS,FS registerler programin bulundugu hafiza bölgesi ile ilgili tanimlamalari yaparlar. Örnegin bir yere veri aktarilacaksa ve bu bölge programin bulundugu bölgenin disinda ise bu registerler ile exstra olarak gösterilerek aktarma yapilabilir.

Bütün registerler deger alirken basina \'MOV\' komunu alirlar. Bu komut yükle anlamindadir ve "mov ax,1020" dersek bunun anlami "ax registere 1020 yükle" olur. Buradan sonra ax register degistirilmedigi sürece 1020 degerini almis olur. IP ve F register hariç bütün registeler MOV komutu ile deger alir veya deger yazar.

SI, DI registerler CPU\' nun onlara tahsis ettigi komutlar ile hizli ve en yüksek seviyede data aktarma, arama, isleme yetenegi kazanir. Ayni zamanda diger registerler ile matematiksel ve lojik islemlerde de kullanilabilirler.

BP, SP, SS registerler yigin için kullanilir. Yigin kelimesini açiklamak gerekirse programin çalismasi için saklanan degerlerdir. Yani programda ayni registeri kullanarak farkli islemler yapmamiz gerekiyorsa önceki register degerini saklamamiz gerekiyor. Aksi halde bu degeri kaybederiz ve yeniden kazanmak mümkün olmayabilir. Bunu iki yolla yapariz. Ya bir yere bu degeri yazariz yada sistemin bize verdigi saklama komutlari ile hafizada saklariz. BP ve SP registerler iste bu hafizada yigilan saklanan degerlerin yeni gösterir.

IP register özel bir registerdir ve direk olarak kullanilamaz. Programin o andaki çalisma adresini belirtir ve degistirmek için CPU\' nun verdigi özel debug registerler kullanilir.

ES, DS, CS, FS, GS, SS registerler hafizayi daha iyi ve güçlü kullanmayi saglamak, dogru veri kontrolu ve aktarimi saglamak ve programin çalistigi yeri saptamak için kullanilir. Bazilarinin bilinçsizce degistirilmesi programda büyük sorunlara yol açar ancak hiç bir deneme yada sorun sisteme kalici bir zarar vermez, reset islemi ile hersey eskiye döner.

F register Türkçe adiyla bayrak register sistemin karsilastirmalar, olay - sonuç - durum gibi hayati hallerine yön verme gibi etkilere sahiptir. Bütün atlamalar bu registerin bitlerine bagli olarak olusur. Bir karsilastirmanin sonucunda bu registerin sabit ve belli bitleri set (1) veya reset (0) olarak durum bildirimi yaparlar. Sartsiz atlama komutu hariç bütün atlama komutlari bu registerin bitlerine bakarak atlama yaparlar.

Modlar

8088 islemciler hem 16 bit bir CPU idi hem su anda kullandigimiz islemcilere göre daha yavas ve daha az özellikliydi. Sanal86 modu yoktu. Zamanina göre yeterli görülsede sonradan bunun asla yetmeyecegi anlasildi ve 80286 ile beraber yeni bir16 bitlik islemci ve mod stratejisi gelistirildi. Buna göre hem eskiye uyumlu olarak 8088 gibi çalisacak hemde yeni nesil programlari destekleyecekti... Ancak asil düzenlemenin 80386 sonrasi islemcilerde yapildigi kabul edilir. Uzun süreli DOS isletim sisteminin hakimiyeti ve korumali modun DOS altinda zahmetli programlanmasi bizim bu yeniliklerden ve birçok avantajdan istemeyerekte olsa mahrum kalmamiza neden oldu. Windows ile beraber 80386\' dan beri gelen degisim ve avantajlar kullanima geçti. En basta birden çok program çalistirma, büyük adresleme yapabilme ve zaten var olan 32 bitlik komutlari tam anlamiyla kullanma bunlardan sadece bazilari.

Su an kullandigimiz 386+ islemcili sistemlerde üç mod var. Bunlar: Gerçek mod, Korumali mod ve Sanal mod. Bunlarin arasinda çalisma, adresleme, hafiza kullanilimi gibi pek çok farkliliklar var. Bilgisayar ilk çalistirildiginda gerçek modda çalisir. Daha sonra isletim sistemi onu istedigi moda geçirir.

DOS isletim sistemi gerçek modda çalisir. Bu mod tek (single) moddur ve yardimci emulasyonlar olmadigi sürece ayni anda tek program çalistirilir. Ayrica adresleme sekli segment ve offset düzenine bagli. Bir programda bir yerin adresi Seg:Off olarak gösterilir ve segmentler 16\' nin katlari seklinde artar. Bir verinin yada programin fiziksel adresi segment 16 ile çarpilir. Bu onaltilik sistemde 10h ile çarpmaktir ve kisaca yanina bir 0 eklemek yeterli. Bundan sonrada offset çikan sayi ile toplanir ve bize fiziksel hafizadaki adresi verir.

Korumali mod çoklu islemi (multi) destekleyen saglam, ve güçlü bir hafiza stratejisi olan bir moddur. Gerçek mod ile korumali mod arasindaki en önemli farklardan birisi hassasiyet derecelendirmesidir. Buna "ring" de denir ve korumali modda toplam 4 hassasiyet seviyesi vardir. En düsük seviye 0 aslinda en büyük, gerçek zamanli seviyedir. Gerçek modda bir program hafizadaki baska bir programa rahatça ulasabilir ve degistirebilir. Bunun sakincasi ve bilgi kaybi açisindan riski vardir. Korumali modda ise bu ancak iki programda 0 (ring 0) olmasi durumunda mümkündür.

Sanal mod gerçek mod ile korumali mod arasindaki emulasyonu saglar. Böylece korumali modda gerçek mod programlarinida kullanabilmek mümkün olur.

CS, DS, ES registerler bir bakima gerçek moda ait segment registerleridir. Çünkü korumali modda segment kavrami yoktur. Ayrica korumali mod bazi gerçek mod komutlarinin direkt olarak çalismasina izin vermez. Örnegin dos isletim sisteminin vazgeçilmez komutlarindan int nn ( interrupt) komutu ancak bir VXD içerisinde çalisir. VXD dosyalari daima en yüksek modda çalisan programlardir.

32 bit registerler

Önceki konularda 16 bir registerleri anlatmistim. Buna göre 16 bit registerler 8 olarak ikiye ayrilabilirler. 32 bit registerlerde registerin 16 bitlik kismi ayni sekilde kullanilabilir ancak eklenen 16 bitlik kisim böyle 8\' er bit yada tek basina 16 bit halinde kullanilamazlar. Ancak lojik komutlar ile bit kaydirmasi yaparak erisilir. 16 bitlik bir register en fazla 65535 degerini alirken 32 bitlik bir register 4294967295 degerine kadar alir.

Yukarida anlattigim bütün registerler baslarina bir \'E\' (extended) harfi alarak 32 bit olurlar.

AX --> EAX
BX--> EBX
F ---> EF
SP --> ESP .... gibi

petricli
14-06-05, 12:02
Registelerin normal olarak \'mov\' komutu ile adresleme ve yükleme yaptigini daha önce belirtmistim. Buna göre AX registere örnegin 1234h sayini yüklemek istedigimizde :

mov ax,1234h

yazmamiz yeterli Ayrica 32 bit bir register olarak kullanmak istedigimizde :

mov eax,12345678

seklinde kullaniriz. Bu örnekte görüldügü gibi bütün registerler MOV regname, deger seklinde yüklenirler.

Adresleme ise bir yerden deger yükleme yada bir yere deger aktarma demektir. Bir adresten deger alip registerleri yüklemek için [] köseli parantezi kullaniriz. Ayrica editör ile bir asm dosyasi olusturduksa ve sembolik olarak bir yeri veri adreslemesi için kullaniyorsak LEA komutunu yada adresin yanina offset komutu kullanabiliriz.

mov ax word ptr,[1234]
mov cx,word ptr,[sayac1]
mov dl, byte ptr [sayi]
mov ax,[bx]
mov si,[ax+bx]

seklinde kullanilir. Ayrica sembolik adreslemeler için:

lea ax, string1
lea si, aktarma_start
mov si, offset aktarma_start

olarak kullanilabilir.

Simdi register degerlerinin degistirilmesi ile ilgili örnekleri inceleyelim:

Örnek1: Burada AX registerin düsük 8 biti degistiriliyor
mov ax, 1234h -------> ax=1234
mov al,0aah -------> ax = 12aah

Örnek2:

mov ax,4423 ----> ax=4423
mov bx,1167 ----> bx = 1123
mov al,bl -----> al= bl yani al= 23 iken 67 oluyor
mov word ptr [sonuc],ax -----> sonuc adresine ax register yaziliyor. AX = 4467

Adreslemeler

Adresleme konusu assembler dilinde önemli bir konudur. Adresleme hafizanin bir bölgesini kullanma yada bir bölgesini gösterme olarak tanimlanabilir. Herhangi bir degeri saklama, bir hafiza bölgesi üzerinde çalisma yada kisaca BUFFER olarak kullanma olanagi saglar. Örnegin klavyeden girilen bir yaziyi inceleyebilmek ve üzerinde arastirma yapabilmek için bir bölgeye yazilmasi gereklidir. Bunun için kullanilan fonksiyona göre registerlerle önceden ayrilmis bir adrese aktarma yapilir. Daha sona burada kullanicinin istedigi sekilde bu yazi üzerinde degisiklik, hesaplama veya mantiksal islemler yapabilir.

Baslica adreslemeler sunlardir:

- Register adreslemesi : Registere bir degeri yüklemek için registerin biti kadar bir adresten yükleme yapilmasi.

Örnegin: mov eax, [sayi1] veya mov eax,sayi1
Burada eax register sayi1 ile belirtilen hazifa adresinden o andaki degeri alip eax registere yüklüyor.

- Deger saklamak için adresleme (Dolayli adresleme) : Burada ileride görecegimiz PUSH ve POP komutuna benzer olarak istenilen bir hafiza adresine saklama islemi yapilir. Bu bir register olabilecegi gibi bagimsiz bir degerde olabilir.

Örnegin : mov dword ptr [deneme],ebx yada mov word ptr [04010000],1234h gibi...

- Hafiza bölgesi adreslemesi : Bu adresleme ile register hafizanin herhangi bir bölgesi isaretlenir. Bunun için MOV komutu yerine LEA komutunu kullanabiliriz. MOV komutu registere verilen degeri yükler yada adresler. LEA komutuda ayni isi yapar. Ancak MOV komutundan önemli farki vardir. Verdiginiz yerdeki degeri degil adresi yükleme yapar. Örnegin:

debug \'Yazi1\',0

lea eax, debug seklinde verilince eax registere \'Yazi\' degeri degil bulundugu yerin adresi yüklenir. Böylece biz bu verinin basindan itibaren istedigimiz gibi çalisma yapabiliriz.

- Dolaysiz adresleme : Bu adresleme registerler arasindaki degerlerin hafiza adresi olarak kullanilmasi ile olusan adreslemedir. Buna göre elimizde hiçbir deger yok sadece registeler vardir. Yaygin bir kullanima sahiptir. Örnegin:

mov dword ptr [esi] ,eax
mov byte ptr [eax],bl
mov dword ptr [esi],ebx
mov word ptr [edi+esi],ax

gibi sadece registerler arasi adreslemedir.

petricli
14-06-05, 12:03
Abdullah Gök tarafından derlenmiştir.

Assembler (3)

Yigin (Stack) konusu

Komutunu vermeden önce yigin konusunun ne oldugundan bahsetmekte yarar var. Yigin kisaca saklamak istedigimiz degerleri hafizanin ESP (veya 16 bit olarak SP) registerler gösterilen bölgeye yigilmasi ve dolayisiyla saklanmasidir. Kullandigimiz degerleri burada örnek olarak 32 bitlik degerler olarak kabul edersek daha anlasilir bir seklide 4 * 8 bit anlamina gelirki bunu 4 tane sayi veya simge olarak düsünebiliriz. Örnegin programimizda eax registerde 12345678 degerinin oldugunu düsünelim. Ancak yine eax register ile bir islem yapacagiz ve bu deger degisecek. Bunu saklamamiz gerekiyor. Yukarida örnek verdigim sekilde adresleme yaparak hafizanin bir yerine yazar ve saklariz ama ya bu register bir sayaç yada çok sayida degisme gösteriyorsa. Iste bunun için CPU iki tane register ile bu sorunu en çözümlü ve basit olacak sekle indirmistir. Normalde gerçek mod segment yapisina sahip oldugu için yigin isleminde sadece hafiza adresini göstermesi yetmez. Bunun için yigin bölgesinin tam adresinin bulunmasi amaciyla SS (Stack Segment) adiyla bir yardimci register daha vardir. Gerçek modda yani DOS\' da yigin bölgesini SS:SP seklinde algilariz ve islemler buna göre yapilir. Korumali modda böyle bir segmentleme ihitiyaci yoktur. Dosya hafizaya yüklendigi anda Windows otomatik olarak o program için bir bir yigin noktasi belirler ve ESP registere bu noktayi yükler. Hiçbir CPU 8 bitlik bir degeri saklamaz. En düsük register veya deger saklamasi 16 bittir. Program içinde ve her modda degerleri bu yigin bölgesine atmak ve almak için PUSH ve POP komutlari vardir. Bu komutlardan PUSH komutu saklanilan registeri yada degeri degistirmez, ayni degerin kopyasini alir. POP komutu ise verilen registerin degerini siler ve yükledigi degeri uygular. Burada 32 bit registerler kullandigimizi varsayabilir. PUSH komutu degeri yigin bölgesine yazdiktan sonra ESP registerin degerini 32 bit (4byte) eksiltir. Eger kullandigimiz register 16 bit ise 16 bit (2byte) eksilme yapar. Burada önemli konu ise CPU\' nun deger olarak çalisilan moduda dikkate almasidir. Örnegin 32bit korumali modda 16bitlik bir degeri yigina atmak istersek bunu daima 32 bit olarak kabul edecek, deger vermedigimiz kismi ise 0 olarak kabul edecektir. Bu yeni degerleri saklamak için uygun adreslemeyi yapmasidir. Ayni sekilde POP komutu degeri yigin bölgesinden alir ve ESP register +4 artar. Bu konu biraz karisik gibi görünebilir. Ancak kullandikça öyle olmadigini göreceksiniz. Önemli bir hususda girilen degerlerin çikis seklidir. Örnegin sirasiya 10 20 30 degerleri PUSH komutu ile yiginda saklanmissa geri dönüs daima 30 20 10 seklinde olacaktir. Yani son giren ilk çikar kurali geçerlidir. Eger bu siralama bozulursa yigina atilan degerler hep yanlis çikacaktir. Normalde API çagrilari hariç kullandiginiz her PUSH komutu için POP komutuda kullanarak kullandiginiz her degeri yigindan almaniz gerekir. Yine önceden girilmis bir deger ESP register vasitasiyla eksiltmeden yada POP yapmadan alinabilir. Bunun için örnegin mov eax, [esp-8] gibi bir komut yeterli.

Simdi daha iyi anlasilabilmesi için

ESP = 643038 oldugu farzedelim

mov eax,12345678h
push eax ; -----> eax registerin 12345678 degeri yigina atiliyor. ESP = 643038 - 4 = 643034 oldu
mov eax,0aa5599aah
push eax ; -----> eax registerin yeni degeri olan 0aa5599aah degeri yigina atildi. ESP=643034-4= 643030 oldu.
pop eax ; -----> son giren ilk çikar. eax = 0aa5599aah oldu ve yigin 643030+4 = 643034 oldu
pop eax ; ----> önceki deger çikti. eax = 12345678h ve ESP = 643034+4 = 643038 oldu.

Burada görüldügü gibi eax registerin ilk degeri 12345678h saklandi daha sonra 0aa5599aah ile islem yapildi ve tekrar yigindan alinarak bastaki degerine dönüldü. Burada bir tüyo vermek gerekirse illaki girilen registerler çikilacak diye bir kural yok. Yani biz yukarida eax register ile yigina attik. Ancak dönüste ebx, ecx,edx,... gibi bütün registeleri kullanabiliriz. Örnegin:

mov eax,12345678h ; eax = 12345678h

push eax ; eax yigina atilarak saklaniyor

mov eax,0 ; eax registere 0 degerini verdik

pop ebx ; yigindaki son deger aliniyor ilk basta girdigimiz 12345678 degeri artik ebx registerde yüklü.



Yigin konusu döngüler içinde döngü sayisini tutmak içinde kullanilir. Bu anlamda yigin çok önemlidir. Ayrica Bayrak registerde (F - EF) yigin içinde saklanilabilir. 386+ sonrasi komutlar arasinda tek komutla bütün registerleri yigina atan ve yine tek komutla hepsini yigindan alan PUSHA ve POPA komutu eklenmistir.

Kesmeler (Interrupts)

Kesmeler özellikle gerçek modda çok önemli olan bir konudur. Ancak korumali modda da en düsük seviyede kesmeler kullanilmaktadir. Kesmeler programcilar açisindan kisaca sistemin bize sagladigi fonksiyonlardir. Sistem açisindan ise, kullanilan isletim sistemi ile bilgisayar arasindaki kontrollü çalismayi saglama ve gerektigi kadar paylasimi olusturmadir. Buradaki paylasim sistemin ve isletim sisteminin kaynaklarinin paylastirilmasi. Örnegin bir tusa basilip basilmadigini ve hangi tusa basildigini ögrenmek için sistem bize sadece klavye konusunda bir kesme vermistir. Bunu kullanarak program içerisinden hangi tusa basildigini ögrenebiliriz. Yada hangi ekran modunda oldugumuzu yine kesmeler vasitasiyla ögrenebiliriz. Kesmelerin olmadigi bir program düsünürsek o zaman zor ve çok yüksek bir bilgi birikimi gerektiren "donanim programlamasi" yapilmasi gerekir.

Kesmelerin gerçek modda "kesme tablosu" olarak adlandirilan 0:0 adresinden baslayan bir tablosu vardir. Bu tabloda kesmeler 4 byte aralikla birbirlerini takip ederler. Bunun nedeni gerçek modda 64kb \' lik segment - offset sistemidir. 16 bitlik segment adresi önce, 16 bitlik offset adreside sonra takip eder. Bu kesme vektörleri degistirilerek "geridönüm" (callback) yapmak sartiyla yönlendirilebilirler (Hook). Bundan yararlanarak ortaya TSR (terminate and stay resident -sonlan ve kal-) ortaya çikmistir. Sistemin istenilen bir fonksiyonu alinarak filtre edilebilir ve o fonksiyon kullanildiginda istenilen program parçacigi çalistirilabilir. Ayrica sistemin debug için kesme 1 ve kesme 3 olarak ayirdigi iki kesmede mevcuttur. EFLAG bayrak registerininin TR biti (trap biti = kapan veya debug biti) set edilince CPU her komuttan sonra kesme 1 \' i çagirir. Böylece debug etme islemi yapilmis olur.

Bayraklar (Flaglar)

Bayrak komutlari ve olaylari deyince aklimiza hep sayilari olusturan bit\'ler gelmeli. Basit olarak iki sayinin karsilastirilmasinda ortaya o sayinin ayni oldugu, ayni olmadigi, büyük veya küçük olmasi yada sifir olmasi gibi durumlar çikar. Bu durumlari ögrenmenin tek yolu o duruma göre sekil alan bayrak register (f) bitlerinin durumunu ögrenmemizdir. Bir test veya bir matematiksel islem oldugu durumlarda sonuçlar daima bayrak registerin ilgili bitlerine yansir.

Bayrak register gerçek modda 16 bit, korumali modda ise 32 bitliktir. Yani gerçek modda toplam 16 bit tane sebep-sonuç biti ayrilmis ayni sekilde korumali modda 32 tane sebep-sonuç biti ayrilmistir.32 bitlik bayrak registere EFlag adi verilir ve ayni 16 bitlik sekli gibi sadece ilk 16 biti kullanilir.(Bazi bitler dökümante edilmemistir). EFlag registerin sonraki 16 biti ileride yapilacak CPU güncellemeleri için ayrilmistir.En baslica olanlari ZF (zero flag), CF (carry flag) ,SF, AF gibidir. Örnegin bir islem sonucu 0 ise ZF set olur yani 1 olur.