Tekil Mesaj gösterimi
Alt 06-09-2008, 15:17   #15
Constantin
ยŦยк
 
Constantin - ait Kullanıcı Resmi (Avatar)
 

Kısa ve Uzun Dallanmalar

Kısa dallanma komutları, genelde bir altprogramın içinde kullanılır. Bu komutlarda dallanacak alan, dallanma komutunu takip eden 127 byte ilerisi ile 128 byte gerisi, arasında sınırlıdır. Dallanma adresi, bir sonraki komuta göre göreceli (relative) ofset olarak tanımlı olduğu için, program kodu başka bir adrese tekrar taşınabilir durumdadır (relocatabla code). Bir program veya bir blok kod, program hafızada yerleştirildiği yerden bağımsız olarak doğru çalışıyorsa, tekrar yerleştirilebilir (relocatable) diye adlandırılır. Kodun tekrar yerleştirilebilir olmaözelliği, dallanma komutları kullanıldığında önemli olur. Eğer bir dallanma komutu, program akışını Program Hafızada belli bir adrese yönlendirirse dallanma adresinde geçerli bir kodun olması programcının sorumluluğundadır. Kısa dallanma komutları kullanılan bir kod bloğunun, hafızada bir başka adrese taşınması durumunda, program, yerleştirildiği yerden bağımsız olarak düzgün çalışacaktır. Çünkü, bir dallanma adresi sonraki komuta göre, göreceli ofset olarak hesaplanır. Aşağıda verilen program parçasını düşünelim:

ORG 8000h
MOV C, P0.0
MOV Pl.0, C
LJMP 8000h ; tekrar

Bu program 8000h adresinden itibaren yerleştirilmelidir. Çünkü , son komut 8000h adresine bir dallanma yapar. Eğer program başka bir adrese yerleştirildiyse, doğru çalışmayacaktır. Şimdide aşağıdaki değişiklikle programa bakalım:


ORG 8000h

START:

MOV C,P0.0
MOV P1.0, C
SJMP START ;TEKRAR


Bu durumda başlangıç (ORG-origin) adresi değiştirilse de program doğru olarak çalışacaktır. Yukarıda verilen üç komutun her biri 2 byte uzunluğundadır. Program başlarken PC 8000h değerindedir ve sırasıyla 8002h ve son komut yürütülmeden 8004h değerini alır. Son komut ta 2 byte uzunluğunda olduğu için , PC artırılarak 8006h olur. Bununla beraber ,son komut bir dallanma komutu olduğu için , PC değerinin göreceli 6 byte gerisindeki adres olan 8000h değeri PC’nin değeri olur. Böylece, işlemci sonsuz bir çevirim içinde çalışmasına devam eder. Eğer program başlangıç adresi değiştirilse , örneğin , 9000h yapılsa; program yine doğru çalışacaktır. Komutlar 9000h , 9002h ve 9004h adreslerinden başlar ve son komut yürütüldüğünde, PC 9000h adresinden başlayarak çevirim tekrar eder.programın kısa dallanmalı ikinci şekli, Program Hafızada tekrar yerleştirilebilir olup birinci verilen örnek , hafıza –özeldir.

Yukarıdaki örnekleri genelleştirecek olursak,uzun dallanmalar kullanan programlar hafıza-özeldir.Buna karşın, kısa dallanmalar kullananlar ise, tekrar yerleştirilebilir programlardır.Uzun dallanmalara,bilhassa,kod boyunun kısa dallanmaların alanı dışına taşması durumlarında ihtiyaç vardır.Program geliştirmede genel bir yaklaşım, kod üretimindeki derleme(assembly) ve kod bağlama(link) işlemlerinin ayrılmasıdır. Derlemede, uzun dallanmaları takip eden adresler gibi , bazı özel adresler haricindeki assembly kodu büyük bir kısmı makine diline çevrilir. Derlenen kod segmentleri ve alt programlar , daha sonra bir linker programı ile bağlanarak en son yürütülecek program elde edilir. Bu bağlama aşama ,dallanma adreslerine harici referansların değerleri ve değişkenlerin değerleri belirlenir.

Mutlak (absolute) Dallanma

8051’in mutlak (absolute) dallanma komutu (AJMP) , derleme ve bağlama işlemlerini ayırmaya bir alternatif sunarak , kod için bir çeşit tekrar yerleştirilebilirlik sunmaktadır. Mutlak dallanmalar, dallanma adresinin en düşük değerli 11-bit’ini tanımlar.
Iste internette bircok sitede, formda gördügüm bu cümle. HAYIR Assembler ölmedi ve ölemezde! Assembler bugünde tipki yillar öncesindeki gibi önemli bir dil. Makine yakini hizli, kücük programlar üretmek icin en iyi dil. >> Neden Assembler? C/C++ da makine yakini, kücük ve gercekten hizli programlar üretebiliyor. << diyorsaniz ve eger yeni bir isletim sistemi veya sürücü yazmak istemiyorsaniz, hakli oldugunuzu itiraf etmeliyim. Ama bugun bile bazi yerlerde derleyicilerden daha iyi programlari optime etmek mümkün. Bunun disinda Assembler ile programlamak size bilgisayarla tam bir iletisim kurma imkani veriyor. Yani yazdiginiz her komut, bilgisayarin CPU(FPU komutlari haric) tarafindan direkt olarak calistiriliyor. Ilk bölümde daha önce Bilgisayar donanimi hakkinda yada CPU ve FPU hakkinda fazla bilgi sayibi olmayan insan lara bu donanim parcalari hakinda bilgi verecegim.

Her bilgisayar bir CPU ya sahiptir. CPU lar farkli bicimlerde olabilirler. Su an kullanilan CPU lar genelde iki bicimdelerdir. RISC ve CISC CPU lar. CISC 8086 tabanli islemcilerin kullandiklari komut modelidir. RISC komut destekli CPU lar ise genelde Server ve Workstation larda kullanilirlar. RISC az bir komut kapestesine ve az sapida adresleme modellerine sahiptir. Genelde her komut bir Takt da yapilir. Hatta bazi durumlarda bir Takt icinde bir kac islem yapmakta mümkündür. CISC CPU lar ise bir CPU ne kadar komut taniyorsa o kadar iyidir, felsefesi üzerine yapilirlar. Bazi komutlar 10 Takt bile gerektrebilirler. Ama yeni CISC CPU lari ile CISC ile RISC arasinda fazla bir fark kalmamistir. Cogu CISC CPU usu günümüzde CISC komutlarini kücük RISC komutlari haline getirip calistirabilme özelliginin yani sira 1 Takt da bir kac islem yapma özzelliginede sahiplerdir. Bunun disinda yeni bir islemci modeli olan EPIC (CISC ile RISC in karisimi) de intel tarafindan IA64 ile su anda pazara yerlestirilmeye calisiliyor. Ama genel bir CPU her sekilde registerlere, ve bir adresleme bicimine sahiptir.
CPU:
Datenbus

----------------------------------
^....-REGISTERS-.-.............
|...............|..........-.................
|...............|.........-..................
|...............|........-...................
|...............|.......-....................
|...............|......-.....................
|...............|...- . . OP-Code.
---------ALU-------BR .. BZ
Flags...... |...........................
----------------------------------
Adressbus

ALU bir islemcinin kalbidir denebilir. Islemler ALU icinde gerceklesir. Adressbus bize herhangibi bir alani adresleme olanagi verir. Datenbus üzerinden veri degis tokusu olur. Registerler bir islemcinin en önemli parcalaridirlar.Islemlerin yapilabilmesi icin ihtiyac duyulurlar, ve her hangibibir veri den cok daha hizli erisilebilirler. FPU ya gelince. FPU da CPU gibi kendi register lerini icerir ve kendi komut satiri vardir. Yüksek, komali vs. sayilarin hesaplanmasinda CPU dan cok daha hizlidir. 8486 dan beri FPU CPU un bir parcasi olarak bulunuyor. FPU ile programlamayi bu dökümanda ögrenmeyeceksiniz. Ama talep gelirse bu konu hakkindada bir döküman hazirlayabilirim.
Merhaba Dünya!

--------------------------------------------------------------------------------
Bircok kitaptaki gibi bizde önce bir “Merhaba Dünya!” programiyla Assembler diline girelim. Derliyici olarak aksi söylenmedigi sürece TASM kullanilacaktir.(Zaten MASM ile TASM arasinda bir fark oldugu söylenemez)

.model small

.data
merhaba db ‘Merhaba Dunya!$’
.code

start:
mov ax, @data
mov ds, ax

mov ah, 0x09
lea dx, merhaba
int 0x021

mov ah, 0x04c
int 0x021

end start
ends


Aslinda ilk bakista fazla cana yakin bir dile benzemiyor Assembler, ama anlayinca gercektende kolay oldugunu anlayacaksiniz. Anlatmaya basliyorum;
Öncelikle “.model small” komutu ile programin programin bir CS(Code Segment) ve bir DS(Data Segment) e sahip olacagini söylüyoruz.SS(Stack Segment) ile DS ne yazikki ayni yeri paylasiyorlar. Daha sonra “.data” ile degiskenlerin saklanacaklari yeri belirliyoruz. DB(Define Byte) ile satirimizin Byte lar halinde saklanan bir degisken olmasini istedigimizi belirtiyoruz. “.code” ile CS e girdigimizi söylüyoruz. “mov ax, @data” ve “mov ds, ax” ile önce AX e DS nin baslangic adresini yükleyip sonrada DS in baslangic adresini AX den DS e yüklüyoruz. Bu cok önemli cünkü 8086 Segment ve Offset lerle adreslemeye izin veriyor. “mov ah, 0x09” ilea ax registerinin üst 8 Bittine 9 degerini yüklüyoruz. “int 0x21” ile bu DOS icin ds:dx adresindeki satiri yaz anlamina geliyor. Tabi adresin offset kismini dx e “lea” ile yüklüyoruz. Sonrada yine ah ye 0x04c yükleyerek int 0x21 i cagiriyoruz, buda DOS icin “Program bitti CIK!” demek oluyor. Simdi gelelim NE DEMEK Segment NE DEMEK Offset isine. 8086 islemcisi 20 Bitlik bir Adressbus a sayipti. Yani 1MB lik adresleme olanagina. Ama sadece 16 Bitlik registerleri vardi, bu yüzden INTEL aklina gelen süper(Ne kadar süper oldugu tartisilamaz tabi) bir fikri hayata sundu. Buna göre adresler söyle hesaplaniyordu: Adres= 16*Segment+Offset Mesela havisada F6000 adresine ulasilmak istendiginde bu ister bu adresi F600:0000 olarak ister F000:6000 seklinde yazibilisiniz. Birinci kisimda Segment ikinci kisimda ise Offset in bulunmasi gerekiyor. Iste size 8086 nin registerleri:

8086:

ax ah al
bx bh bl
cx ch cl
dx dh dl

cs: ip
ds: di
es: si
fs
gs
ss: bp, sp

Flags

Aslinda 8086 nin gercektende az registere sahip oldugunu söyleyebiliriz. Ax, bx, cx, dx genel amacli registerlerdir. Cs, ds, es, fs, gs, ss adreslemede Segment kisminda kullanilabilir ip, di, si, bp ve sp ise offset kisminda kullanilabilirler. Bunun disinda her register 16- Bit boyutunda ve ax, bx, cx, dx registerleri üst ve alt kisimlari seklindede kullanmak bümkün. H üst 8 Bit L ise alt 8Bit icindir. Bu sekilde mesela ax registerine hem 6 hemde 4 degerini tutacak sekilde verebiliriz. Örnek:
mov ah, 6
mov al, 4
; iki degerde ax registerinin icinde bulunuyor.
Programcilar icin bir diger önemli gelisme ise 8386 ile gerceklesti. Bu islemci ilk IA32 destekli islemci olmakla beraber, kendi 32-Bitlik registerlerini sunuyordu. Hemde bu islemci üzerinde her registeri her islem icin kullanmak mümkün. Tabi CS ile EIP disinda. Cünkü CS:EIP programin o anda bulundugu durumu, yani bir sonraki komutun adresini tutar. Iste 8386 nin registerleri:

8386:

eax ax ah al
ebx bx bh bl
ecx cx ch cl
edx dx dh dl
cs
ds
es
fs
gs
ss
eip ip
edi di
esi si
ebp bp
esp sp
eflags

Önünde e harfi olan registerler 32 Bitlikler. Ve 8386 sayesinde artik adreslemek icin Segment lere ihtiyacimiz yok, 20 Bitlik adres kapestesi yerine 32- Bitlik bir adres kapestesi var 8386 nin, ve bu adresler tam bir registere sigiyorlar, yani 1MB lik adres kapestesi 4GB seviyesinde artik!

Eski(8086):
Merhaba db ‚Merhaba Dunya!’
lds di, merhaba
; merhaba nin adresi= ds:di

Simdi(8386)
Merhaba db ‘Merhaba Dunya!’
lea edi, merhaba
; merhabanin adresi= edi

Simdilik öncelikle en önemli Assembler komutlarini burda kisaca bir aciklayayim:
“mov register/segment/degisken, register/segment/degisken” virgülden önceki kisma, virgülden sonraki kismi yükler. Önemli olan ve dikkat edilmesi gereken en az bir tane registerin verilmis olmasi. Daha sonraki en önemli komutlar ise Matamatik komutlari. “add” toplama, “sub” cikarma “mul” carpma ve “div” bölme icindir.
Mesela deger1= deger2*16;
Assembler:
mov ax, deger2
shl ax, 4
mov deger1, ax
Burada dikkatinizi ceken komut “shl” olabilir. Shl belirtelen sekilde bitlerin sola kaydirir, fakat capma islemlerindede kullanilabilirler, üstelik mul dan 4-5 kat daha hizli calisirlar. 1 degerinde kaydirmak 2 ile capmak, 2 degerinde kaydirmak 4 ile carpmak , vs seklinde devam eder. Tabi matamatik komutlarini “lea” ile gerceklestirmekte mümkün, tabi 8386 dan itibaren, nasilmi? 8386 da her registerle adresleyebildigimizi söylemistim, artik cs, sp gibi registerleri kullanmak zorunda degiliz. Bu yüzden, simdik su komutun ne yaptigina bir bakalim:
lea eax, [eax+eax*4]
Bu komut eax e eax+eax*4 ün icerigini yüklüyor. Ama bu eax ile 5 in carpimindan baska bir sey degil!
mov ecx, eax
shl eax, 2
add eax, ecx
Burda “lea” ile sadece 3 satiri 1 satir haline getirmekle kalmiyoruz ayni zamanda bir registerin kullaniminida engellemis oluyoruz. Bu kadar derinlere girdikten sonra simdik kaldigimiz yerden devam edelim. Ilk programda “merhaba db ‘Merhaba Dunya!$” satirinda dikkatinizi ‘$’ cekmisdir herhalde. Bu isaret Dos icin cok önemli, satirin sonunu belirtiyor. Windows da 0 ile satir sonu belli edilebiliyor. Simdik en basta yazdigimiz “Merhaba Dünya!” programini birde Windows icin yazalim;
Constantin Ofline   Alıntı ile Cevapla