ASSEMBLY DİLİ
Assembly dili alt düzey bir programlama dilidir. Konuyla alakalı herhangi birşeyi anlamak için bilgisayar mimarisi hakkında bilgi edinmek gerekir. Basit bir bilgisayar modeli aşağıda verilmiştir.
Sistem Veriyolu(System Bus) bilgisayarın çeşitli parçalarını birbirine bağlar. CPU bilgisayarın kalbidir.Hesaplamaların çoğu CPU’nun içerisinde gerçekleşir. RAM programların bilgisayarda yürütülmek için yüklendiği yerdir.
CPU’nun içi:
8086 CPU’nun 8 tane registeri vardır.
AX: biriktirici(accumulator) registerdir.(AH/AL olarak bölünmüştür) BX: temel(base) registerdir.(BH/BL olarak bölünmüştür) CX: sayaç(counter) registerdir.(CH/CL olarak bölünmüştür) DX: veri(data) registeridir.(DH/DL olarak bölünmüştür) SI: kaynak(source) indeks registeri DI: gidilecek(destination) indeks registeri BP: temel(base) işaretçisi SP: yığıt(stack) işaretçisi
Registerların bu şekilde isimlendirilmesine rağmen, ne amaçla kullanılacağına programcı karar verir. Registerların esas görevi bir sayı(değişken) tutmaktır. Yukarıdaki registerlar 16 bit büyüklüğündedir.Örnek: 0011000000111001b(binary) or 12345 (decimal)
Genel amaçlı 4 register (AX, BX, CX, DX), iki farklı 8 bitlik registerlardan oluşmuştur.Eğer AX= 0011000000111001b ise AH=00110000b ve AL=00111001b olur. Aynı şey diğer 3 register içinde geçerlidir.
Bölüt(Segment) Registerları
CS: Geçerli programı çalıştıran bölüte işaret eder. DS: Genellikle değişkenlerin tanımlandığı bölüte işaret eder. ES: ekstra bölüt registeri, kullanım amacını programcı belirler. SS: yığıtları içeren bölüte işaret eder.
Özel Amaçlı Registerlar
IP: komut işaretçisi FP(Bayrak yazmacı) Mikroişlemcinin geçerli durumunu gösterir.
IP registerları CS bölüt registerıyla birlikte çalışır ve yürütülen komuta işaret eder.
Belleğe Erişim(Memory Access)
Belleğe erişim için 4 tane registerı kullanabiliriz: BX, SI, DI, BP
Bu registerları [ ] sembolü içerisine koyarak değişik bellek yerlerine işaret edebiliriz.
MOV Komutu
MOV REG, memory
REG: AX, BX, CX, DX, AH, AL, BL,
BH, CH, CL, DH, DL, DI, SI, BP, SP.
Bölüt registerları için sadece bu şekildeki MOV komutları desteklenir
MOV SREG, memory
SREG: DS, ES, SS, and only as second operand: CS.
MOV komutu CS ve IP registerlarının değerini değiştirmek için kullanılamaz.
Aşağıdaki kısa program MOV komutunun kullanımını göstermektedir.
ORG 100h ; this directive required for a simple 1 segment .com program. MOV AX, 0B800h ; set AX to hexadecimal value of B800h. MOV DS, AX ; copy value of AX to DS. MOV CL, 'A' ; set CL to ASCII code of 'A', it is 41h. MOV CH, 1101_1111b ; set CH to binary value. MOV BX, 15Eh ; set BX to 15Eh. MOV [BX], CX ; copy contents of CX to memory at B800:015E RET ; returns to operating system.
Yukarıdaki kısa programı kod editorunde ‘; add your code here’ yazan yere kopyalayıp yapıştırın ve [Compile and Emulate] butonuna ya da klavyeden F5’e basın.
Emulator penceresi program yüklenmiş şekilde açılacak, daha sonra [Single Step] butonuna basarak registerların değerini takip edebilirsiniz.
Yukarıdaki program direkt olarak video hafızasına yazar, burdan MOV’un çok etkili bir komut olduğunu anlıyabilirsiniz.
Değişkenler
Değişken bir bellek yeridir.Programcı için herhangi bir değeri 5A73:235B isimli bir adreste tutmaktansa , ‘var1’ isimli bir değişkende tutmak daha kolaydır, özellikle 10 veya daha fazla değişken varsa.
Bizim derleyicimiz iki türlü değişknei kabul etmektedir: BYTE yada WORD Değişken bildirim sentaksı: İsim DB değer İsim DW değer
DB- Define Byte DW-Define Word
İsim: Bir harfle başlaması gerekmesine rağmen, herhangi bir harf yada sayı kombinasyonu olabilir. İsimsiz bir değişkende tanımlanabilir, o zaman değişkenin bir adresi olur ama ismi olmaz.
Değer: Herhangi bir numaralandırma sistemi(hexadecimal, binary yada decimal) tarafından desteklenen bir sayısal değer olabilir yada henüz başlangıç değeri atanmamış değişkenler için ‘?’ sembolüde olabilir.
Biraz öncede söyledğimiz gibi MOV komutu değerleri kaynaktan gidilecek yere kopyalamak için kullanılır.MOV komutuyla ilgili başka bir örnek görelim:
ORG 100h
MOV AL, var1
MOV BX, var2
RET ; stops the program.
VAR1 DB 7
var2 DW 1234h
Yukarıdaki kodu kaynak editörüne kopyalayın, derlemek için F5’e basın ve emulatore yükleyin. Aşağıdaki gibi bir netice almanız gerekir: Derleyici Makine Kodunu ürettiği zaman, bütün değişken isimleri offsetleriyle yer değiştirir.
Bellek listesinde ilk sıra offseti, ikinci sıra hexadecimal değeri, üçüncü sıra decimal değeri ve son sırada ASCII karakter değerini ifade eder.
Derleyici karakter duyarlı değildir, ‘VAR1’ ve ‘var1’ aynı değişkeni ifade eder.
VAR1’in offset değeri 0108h , ve tam adresi 0B56:0108dir. var2’nin offset değeri 0109h ve tam adresi 0B56:0109 dir. Bu değişken WORD’dur ve 2 bytelık yer tutar. Alttaki byte, alttaki adreste tutulur, dolayısıyla 34h 12h’dan önce yer alır.
Arrays(Dizilimler)
Arrayler, değişkenler zinciri olarak adlandırılabilir. Bir metin dizgisi, her bir karakterin bir ASCII karakter(0...255) ile ifade edildiği bir byte arrayidir.
Aşağıda bazı array tanımları bulunmaktadır.
a DB 48h,
65h, 6Ch, 6Ch, 6Fh, 00h
b a’nın tıpatıp kopyasıdır. Derleyici tırnak işareti içinde bir string gördüğü zaman, otomatik olarak onu bir bytelar kümesine dönüştürür. Aşağıdaki şekil, bu arrayler tanıtıldığı zamanki hafızanın bir bölümünü göstermektedir.
Arrayin herhangi bir elemanına köşeli ayraçlar vasıtasıyla ulaşabilirsiniz.
MOV AL, a[3]
Ayrıca herhangi bir dizin yazmacı(BX, SI, DI, BP) kullanabilirsiniz. Örneğin;
MOV SI, 3
Büyük bir array tanıtmak istiyorsanız DUP operatorünü de kullanabilirsiniz. DUP’un sentaksı
number DUP ( value(s) ) şeklindedir. Number kaç kopya istendiğini gösteren sayıdır, value kopyalanacak ifadedir.
Örneğin:
c DB 5 DUP(9) ifadesi c DB 9, 9, 9, 9, 9 ifadesinin başka bir şeklidir. Değeri 255’ten büyük yada -128’den küçük sayıları tutmak için DB yerine DW de kullanılabilir.
Bir Değişkenin Adresini Alma
LEA(Load Effective Address) komutu ve alternatif OFFSET operatörü bulunmaktadır. OFFSET ve LEA komutlarının ikiside bir değişkenin offset (bağıl konum) adresini elde etmek için kullanılabilir.
Örnek ORG 100h
MOV AL, VAR1 ; VAR1’in değerini AL registerının içine atarak kontrol eder.
LEA BX, VAR1 ; VAR1 in adresini BX registerının içine alır.
MOV BYTE PTR [BX], 44h ; VAR1’in içeriğini değiştirir.
MOV AL, VAR1 ; VAR1’in değerini AL registerının içine atarak kontrol eder.
RET
VAR1 DB 22h
END Aşağıdaki örnekte LEA yerine OFFSET kullanılmıştır.
ORG 100h
MOV AL, VAR1 ; VAR1’in değerini AL registerının içine atarak kontrol eder.
MOV BX, OFFSET VAR1 ; VAR1 in adresini BX registerının içine alır.
MOV BYTE PTR [BX], 44h ; VAR1’in içeriğini değiştirir.
MOV AL, VAR1 ; VAR1’in değerini AL registerının içine atarak kontrol eder.
RET
VAR1 DB 22h
END
Constants(Sabitler)
Sabitler, değişkenler gibidir, ancak sadece program derlenene kadar varlıklarını sürdürürler. Bir sabit tanımlandıktan sonra değeri değişmez. Sabitleri tanıtmak için EQU komutu kullanılır.
name EQU < any expression >
Örneğin:
k EQU 5
ile
MOV AX, 5
Kodları aynı işi yapmaktadır.
Değişkenlere, programınız yürütülürken emulatorun “View” menüsünden “Variables” ı seçerek bakabilirsiniz.
Değişkenlere herhangi bir numaralandırma sistemindede bakılabilir.
Programınız çalışırken değişkeninizin üzerine çift tıklayarak ve ya sağ tıklayıp edit diyerek yeniden düzenleyebilirsiniz.
Interrupts(İş Kesme İşareti) Interruptlar, bir dizi fonksiyondan oluşur. Bu fonksiyonlar programı kolaylaştırır, bir karakter bastırmak için kod yazmaktansa, kısa yoldan interrupt’ı çagırabilirsiniz, o herşeyi yapar. Disk sürücüsüyle ve diğer donanımsal cihazlarla çalışan interrupt fonksiyonları da vardır. Bu çeşit interruptlara software interrupts(yazılımla iş kesme) denir.
Interruptlar değişik donanımlar tarafından da tetiklenebilir, bunlara hardware interrupts (donanımla iş kesme) denir. Biz şuan software interruptlarla ilgilenmekteyiz. Interrupt(İş kesme işareti) göndermek için INT komutunu yazmak yeterlidir. Sentaksı: INT value Value 0’la 255 arası yada 0’la 0FF arası bir sayı olabilir. Genellikle hexadecimal sayılar kullanılır. O zaman sadece 256 tane fonksiyon vardır, bu durum mantıklı değil diye düşünebilirsiniz. Her interruptın alt fonksiyonları olabilir. Alt fonksiyon tanımlamak için, AL registerı interrupt çağırmadan önce hazırlanmalıdır. Her bir interrupt 256 alt fonksiyona sahip olabilir. Dolayısıyla (256*256=65536) Genellikle AH registerı(yazmacı) kullanılır ama bazen diger registerlarda kullanılabilir. Aşağıdaki örnek: INT 10H ve 0EH alt fonksiyonunu kullanarak ekrana “Hello!”mesajı bastırır. Bu fonksiyon imleci ilerleterek ve ekranı gerektiği kadar akıtarak ekranda karakter gösterir. ORG 100h ;. Derleyiciye tek bölütlü .com dosyası oluşturması için talimat verir
;Kullandığımız alt fonksiyon geri dönüşte
; AH registerını değiştirmez, dolayısıyla AH’yi sadece
;bir kere hazırlanır.
MOV AH, 0Eh ; alt fonksiyonu seç.
;INT 10h/0Eh alt fonksiyonu AL
; registerının içindeki bastırılacak
;olan karakterin ASCII kodunu alır
MOV AL, 'H' ; ASCII code: 72
INT 10h ;bastır
MOV AL, 'e' ; ASCII code: 101
INT 10h ; bastır
MOV AL, 'l' ; ASCII code: 108
INT 10h ; bastır
MOV AL, 'l' ; ASCII code: 108
INT 10h ; bastır
MOV AL, 'o' ; ASCII code: 111
INT 10h ; bastır
MOV AL, '!' ; ASCII code: 33
INT 10h ; bastır
RET ; işletim sistemine dön
Yukardaki kodu editorun kod bölümüne giderek kopyalayıp yapıştırın [Compile and Emulate] butonuna basarak çalıştırın.
Aritmetik ve Mantıksal Komutlar Birçok aritmetik ve mantıksal komut işlemcinin durum yazmacını etkiler. Gördüğünüz gibi bu yazmaçta 16 bit vardır, her bir bit bayrak(flag) olarak adlandırılır ve 0 yada 1 değeri alır.
3 tane komut grubu vardır. Birinci grup: ADD, SUB,CMP, AND, TEST, OR, XOR Şu çeşit işlenenler kabul edilir:
REG, memory
REG: AX, BX, CX, DX, AH, AL, BL,
BH, CH, CL, DH, DL, DI, SI, BP, SP. İşlenenler arasında işlem bittiği zaman, sonuç hep ilk işlenende tutulur. CMP ve TEST komutları sadece flagları etkiler ve sonucu kaydetmezler.(Bu komutlar program çalıştığı esnada karar vermek için kullanılır) Bu komutlar şu flagları etkiler: CF, ZF, SF, OF, PF, AF.
1 AND 1 = 1 Gördüğünüz gibi sadece her iki tarafda 1 olduğu zaman 1 sonucunu elde ediyoruz.
1 OR 1 = 1 Gördüğünüz gibi en az bir bit 1 olduğu zaman 1 sonucunu elde ediyoruz.
1 XOR 1 = 0 Gördüğünüz gibi bitler birbirinden farklı olduğu zaman 1 sonucunu elde ediyoruz. İkinci grup: MUL, IMUL, DIV, IDIV Şu çeşit işlenenler kabul edilir:
REG
REG: AX, BX, CX, DX,
AH, AL, BL, BH, CH, CL, DH, DL, DI, SI, BP, SP.
DIV ve IDIV komutları için flag tanımsızdır.
İşlenen byte
olduğu zaman: İşlenen word
olduğu zaman:
İşlenen byte
olduğu zaman: İşlenen word
olduğu zaman:
İşkenen byte
olduğu zaman: işlnenen word
olduğu zaman:
İşlenen byte
olduğu zaman: İşlenen word
olduğu zaman:
Üçüncü grup: INC, DEC, NOT, NEG Şu çeşit işlenenler kabul edilir:
REG REG: AX, BX, CX, DX, AH, AL, BL,
BH, CH, CL, DH, DL, DI, SI, BP, SP. INC, DEC komutları sadece şu flagları
etkiler: NOT komutu
hiçbir flagı etkilemez
Yordamlar(Procedures) Yordamlar, belirli bir görevi yapmak için programınızdan çağırabileceğiniz kod parçasıdır. Yordamlar programı daha yapısal ve kolay anlaşılır bir hale getirir. Genellikle programda çağırıldıkları yere geri dönerler. Yordam bildiriminin sentaksı:
name PROC name – yordamın adıdır,altta ve üstte aynı isim olmalıdır.Yordamların düzgün bir şekilde kapanıp kapanmadığını kontrol eder. Muhtemelen, RET komutunun işletim sisteminden dönmek için kullanıldığını zaten biliyorsunuz.Aynı komut yordamdan dönmek için de kullanılır.(işletim sistemi programınızı özel bir yordam olarak görür)
CALL komutu yordamı çağırmak için kullanılır. Örnek: ORG 100h
CALL m1
MOV AX, 2
RET ; işletim sistemine döner.
m1 PROC MOV BX, 5 RET ; çağırana döner. m1 ENDP END Yukarıdaki örnek m1 yordamını çağırır, m1 yordamı MOV BX, 5 komutunu yürütür. Daha sonra program sonraki komutu yani MOV AX, 2 komutunu yürütür. Parametleri yordamlara göndermek için çeşitli yollar vardır. Bunlardan en kolayı register kullanmaktır. Aşağıdaki örnek iki parametreyi AL ve BL registerlarına alır, bu parametreleri çarpar ve sonucu AX registerına yazar. ORG 100h
MOV AL, 1 MOV BL, 2
CALL m2 CALL m2 CALL m2 CALL m2 RET ; işletim sistemine döner
m2 PROC MUL BL ; AX = AL * BL. RET ; çağıran yere döner. M2 ENDP END Yukarıdaki örnekte, yordam her çağrıldığında AL registerı güncellenir, BL registerı değişmez. Bu algoritma 2’nin 4.kuvvetini alır. AX registerının içindeki sonuç 16(10h) olur. Aşağıda yordam kullanarak ekrana Hello World! Mesajı yazan bir örnek yer almaktadır. ORG 100h
LEA SI, msg ; Mesajın adresini SI’ya yükler
CALL print_me
RET ; işletim sistemine döner
; ========================================================== ;Bu yordam bir string bastırır, bu string sıfır ile bitmelidir. Stringin adresi SI da tutulmalıdır. print_me PROC
next_char: CMP b.[SI], 0 ; durmak için sıfır olup olmadığını kontrol eder. JE stop ;
MOV AL, [SI] ; bir sonraki ASCII karakteri alır.
MOV AH, 0Eh ; uzakyazıcı fonksiyon numarası INT 10h ; AL’de bir karakter bastırmak için iş kesme işaretçisi kullanma
ADD SI, 1 ; string diziliminin indexini ilerletir.
JMP next_char ; geriye dön ve başka bir karakter yaz.
stop: RET ; çağırana döner. print_me ENDP ; ==========================================================
msg DB 'Hello World!', 0 ; sıfırla biten string END "b."- [SI]’dan önceki öntakı, wordleri değil byteları karşılaştırmamız gerektiği anlamına gelir. Wordleri karşılaştırmak istediğimiz zaman öntakı olarak "w." yazarız. Karşılaştırılan işlenenlerden biri register(yazmaç) ise, bunları yazmamıza gerek yok. Çünkü derleyici her bir registerın boyutunu bilir. Makrolar(Macros) Makrolar, yordamlara benzerler ama aslında öyle değildir. Yordamlar gibi görünürler ancak kodunuz derlenene kadar varlıklarını sürdürürler, derlemeden sonra bütün macrolar gerçek komutlarla yer değiştirir. Eğer bir makro tanımladıysanız ve kodunuzda kullanmadıysanız derleyici onu görmezden gelir.
Makro tanımlaması:
name MACRO [parameters,...]
<instructions>
ENDM Yordamların tersine , makrolar onu kullanan kodun üstünde yer almalıdır. Örneğin: MyMacro MACRO p1, p2, p3
MOV AX, p1
MOV BX, p2
MOV CX, p3
ENDM
ORG 100h
MyMacro 1, 2, 3
MyMacro 4, 5, DX
RET
Yukarıdaki kod aşağıdaki gibi genişletilebilir. MOV AX,
00001h Macrolar ve yordamlarla ilgili bazı önemli bilgiler:
CALL MyProc
MyMacro
MyMacro 1, 2, 3
Makrolar doğrudan kodun içinde genişletilir, bu nedenle eğer kodun içinde etiketler(labeller varsa) , makroyu birden fazla kullandığınız takdirde "Duplicate declaration" hata mesajını alırsınız. Bu tür problemleri engellemek için, değişkenler, etiketler ve yordamlar tarafından takip edilen LOCAL bildirimler kullanınız. MyMacro2 MACRO LOCAL label1, label2
CMP AX, 2 JE label1 CMP AX, 3 JE label2 label1: INC AX label2: ADD AX, 2 ENDM
ORG 100h
MyMacro2
MyMacro2
RET Eğer makroları çeşitli programlarda kullanmayı planlıyorsanız, bütün makroları ayrı bir dosyada tutmak iyi bir fikir olabilir. Bu dosyayı Inc klasörünün içine koyun ve INCLUDE dosya_adı bildirimiyle makroları kullanın. Böyle bir dosya örneği için Library of common functions - emu8086.inc linline tıklayın.
|