32 Bit Intel İşlemcilerinde Komut Kalıpları

06:58
İşlemcilerdeki yazmaç ve bellek kullanım kalıplarına adresleme modları (addressing mode) denilmektedir. Intel’in 32 bit işlemcilerinde komut kalıplarını aşağıda maddeler halinde tek tek ele alacağız. Intel sisteminde komutlar çoğunlukla iki operandlıdır. Ayrıca örneklerimizde pek çok assembly derleyicisinin kabul ettiği gibi komutların hedef operandları sol taraftaki operandla belirtilmektedir. Aşağıda bu syntax'a (Intel Syntax) uygun bir kod parçası görülmektedir.

Intel Syntax
Aşağıda ise bunun tam tersi (AT&T Syntax) hedef operand sağ taraftaki operandlı bir kod parçası görülmektedir.

AT&T Syntax

Sembolik makine dillerinde genel olarak komutlarda belirtilen işlemlerin kaç bit düzeyinde yapılacağı eğer komutta yazmaç varsa yazmacın uzunluğuyla tespit edilir. Ancak komutta yazmaç yoksa işlemlerin kaç bit düzeyinde yapılacağı onların yanına getirilen qword, dword, word, byte gibi anahtar sözcüklerle belirlenmektedir. Tabii bu anahtar sözcükler assembly derleyicisinden derleyicisine farklılık gösterebilmektedir. 32 Bit Intel İşlemcilerinin komut kalıpları özet olarak şöyledir:
  1. Yazmaçlarla + sabitler 
  2. Yazmaçlarla + yazmaçlar 
  3. Yazmaçlarla + bellekteki değerler
  4. Bellekteki değerlerle + sabitler
Bellek operandı genellikle sembolik makine dillerinde köşeli parantezlerle gösterilmektedir. Bellek operandı herhangi bir biçimde oluşturulamaz. Köşeli parantezlerin içerisine nelerin yazılabileceği önceden belirlenmiştir. Şimdi komut kalıplarını daha ayrıntılı olarak tek tek ele alalım:

1) Yazmaçlarla sabitler işleme sokulabilirler. Örneğin:

ADD EAX, 100
ADD AH, 20
MOV EAX, 512

Sembolik makine dillerinde doğrudan yazılan sayılara kavram olarak "Immediate, Constant" ya da "literal" kelimeleri de kullanılmaktadır.

2) Yazmaçlarla yazmaçlar işleme sokulabilirler. Ancak yazmaç - uzunluk uyumunun sağlanmış olması gerekir. Örneğin:

ADD EAX, EBX
SUB AX, CX
XOR AH, BL

Örneğin aşağıdaki komutlar yazmaç uzunlukları aynı olmadığı için geçersizdir:
ADD EAX, BX
XOR BX, AL

3) Yazmaçlarla köşeli parantez içerisindeki sabit değerler işleme sokulabilirler (Burada sabit değerler hafıza alanında bir adres belirtmektedir). Genel olarak bütün işlemciler bellekteki değerlere onların adreslerini alarak erişirler. Sembolik makine dillerinin çoğunda bir bellek adresindeki değerler köşeli parantezlerle belirtilmektedir. Bu durumda o yazmaçtaki değer ile köşeli parantez içerisindeki bellek adresinden başlayan değer işleme sokulmuş olur. İşlemin kaç bit düzeyinde yapılacağı yazmacın uzunluğuna bağlıdır. Örneğin:

ADD EAX, [1FC14A]

Burada EAX yazmacındaki değer ile belleğin 1FC14A adresinden başlayan 32 bitlik değer toplanmıştır. Sonuç EAX yazmacındaki değer bozularak oraya aktarılmaktadır. Örneğin:

MOV BX, [1FC14A]

Burada BX’e 1FC14A adresinden başlayan 16 bit değer aktarılmaktadır. Örneğin:

ADD AH, [1FC14A]

Burada AH içerisindeki değerle 1FC14A adresinden başlayan 8 bitlik değer toplanmış, sonuç yine AH’ya atanmıştır. Örneğin:

ADD [1FC14A], EAX

Burada EAX yazmacı ile bellekte 1FC14A adresinden başlayan 32 bit değer işleme sokulmuştur. Fakat sonuç belleğin yine 1FC14A adresinden itibaren 32 biti etkileyecek biçimde aktarılmaktadır. Kalıptaki köşeli parantezin işlevine dikkat ediniz. Köşeli parantezler olmasaydı komut tamamen asssembly derleyicisi tarafından farklı yorumlanırdı. Örneğin:

ADD EAX, 1FC14A

Bu komutta EAX yazmacındaki değer doğrudan 1FC14A sabiti ile (immediate) ile toplanmıştır. Sonuç EAX’te bulunacaktır. Fakat örneğin:
ADD EAX, [1FC14A]
Burada EAX yazmacındaki değer ile 1FC14A adresinden başlayan 32 bit değer toplanmıştır.

Not : RISC işlemcilerinde yazmaç ile bellek bölgesinin işleme sokulamamaktadır. Yazmaç-bellek işlemleri tipik olarak CISC tarzı eski işlemcilerde karşılaşılan komut kalıplarıdır.

Normal olarak köşeli parantez içerisindeki sabit adresler 32 bit korumalı modda 32 bit uzunluğundadır. Ancak köşeli parantez içerisindeki bellek adresi 16 bitten de oluşabilir. Ancak komutlardaki 16 bit adresler 32 bit korumalı modda 0x67 öneki gerektirmektedir. Bu nedenle böyle komutlarla 32 bit programlamada pek karşılaşmayız.

4) Köşeli parantez içerisindeki adresler ile sabitler işleme sokulabilirler. Bu durumda sembolik makine dili derleyicileri komutta yazmaç olmadığı için işlemin kaç bit üzerinden yapılacağını ek anahtar sözcükler yardımıyla işleme sokarlar. Örneğin:
ADD dword [1FC14A], 100
Burada belleğin 1FC14A adresinden başlayan 32 bitlik değer 100 ile toplanmıştır, sonuç yine 1FC14A adresinden başlayarak oraya aktarılmıştır. Komuttaki dword işlemin 32 bit (double word = 4 byte ( 8 bit ) = 32 bit) olduğunu assembly derleyicisine anlatmak için gerekmektedir. Bellekteki değerlerle sabitler işleme sokulurken köşeli parantez içerisindeki bellek adresi sonraki maddelerde olduğu gibi yazmaçlarla da oluşturulabilmektedir.

Not : RISC işlemcilerinde bellekteki değerlerle sabitler işlemlere sokulamamaktadır. 

5) Bir yazmaçla köşeli parantez içerisindeki bir yazmaç işleme sokulabilir. Bu durumda bellekte o yazmacın içerisindeki değerle belirtilen adresteki bilgi işleme sokulur. Örneğin:

MOV EAX, 1FC10A
MOV EBX, [EAX]

Burada EAX yazmacının içerisinde 1FC10A değeri vardır. O halde bellekteki 1FC10A adresinden başlayan 32 bit değer EBX yazmacına aktarılmıştır. Örneğin:

MOV EAX, 1FC10A
MOV EBX, [EAX]
ADD EAX, 4
MOV EBX, [EAX]
ADD EAX, 4
MOV EBX, [EAX]
...

Bu adresleme modunun neden kullanıldığı yukarıdaki örnek kodla anlaşılabilir. Biz bu sayede örneğin bir yazmaca bir dizinin adresini atayıp sonra o yazmacı köşeli parantez içerisinde kullanarak dizinin tüm elemanlarına erişebiliriz. Benzer biçimde gösterici işlemleri de derleyici tarafından bu komut kalıbıyla yapılmaktadır. Örneğin:

int *pi = (int *) 0x1FC41A;
*pi = 20;
Bu işlem aşağıdaki gibi makine komutlarına dönüştürülebilir (örneğimizdeki pi, pi göstericisinin adresini belirtiyor olsun):

MOV dword [pi], 1FC41A
MOV EAX, [pi]
MOV dword [EAX], 20

Anahtar Notlar: Sembolik makine dillerinde (ve tabii doğal makine dillerinde) değişkenlerin isimleri yoktur. Dolayısıyla biz onlara isimleriyle erişmeyiz. Biz ancak onlara onların adresleriyle erişebiliriz. Yani yüksek seviyeli dillerdeki değişken isimleri aslında programcılar tarafından uydurulmuş isimlerdir. Kaynak program derlendikten sonra artık çalıştırılabilen program bir değişken ismi içermez. Yüksek seviyeli dillerin derleyicileri belli adreslerden başlayan bilgileri bize belli bir isimle sunmaktadır. Tabii yazmaçlar bir adres belirtmezler. Onlar CPU içerisinde yeri belli olan küçük bellek bölgeleridir. Makine komutları bile yazmaçları bilmektedir. İşin aslı yazmaçların da makine komutlarında isimleri yoktur. Yazmaçlar ikilik sisteme dönüştürülmüş makine komutlarında numaralarla temsil edilirler.

Köşeli parantez içerisindeki yazmaçlar 16 bitlik yazmaçlar olabilir. Ancak 8 bitlik yazmaçlar olamaz. Örneğin:

ADD EAX, [BX]

komutu geçerlidir. Ancak:

ADD EAX, [BL]

komutu geçersizdir. Köşeli parantez içerisine 16 bit yazmaç yerleştirmek 32 bit programlamada çok nadir görülebilecek bir durumdur. Çünkü 16 bit yazmaç ile ancak belleğin tepesindeki 64K’ya erişebiliriz.

Not: 32 bit korumalı modda köşeli parantez içerisine 16 bit yazmaç yerleştrmek için komutun başında 0x67 önekinin bulunması gerektiğini anımsayınız. Bu önek komutu 1 byte büyütmektedir.

6) Bir yazmaçla "köşeli parantez içerisindeki bir yazmaç + 8 bit sabit" ya da "köşeli parantez içerisindeki yazmaç + 32 bit sabit" işleme sokulabilir. Bu gösterimi Intel [ base + disp8 ] ve [ base + disp32 ] ile belirtmektedir. Buradaki disp "displacement" sözcüğünden gelmektedir. Örneğin:

ADD EAX, [EBX + 1F] ; yazmaç + 8 bit
ADD EAX, [EBX + 1001FC01] ; yazmaç + 32 bit

Burada köşeli parantezin içindeki ifadeden bir bellek adresi elde edilmektedir. Bu bellek adresi oradaki yazmacın içerisindeki değerle o sabit değerin (displacement) toplamıyla oluşturulmaktadır. Örneğin:

MOV EBX, 1FC010
MOV EAX, [EBX + 1C]

Burada EBX değerinin içerisindeki değerle 1C değeri toplanarak bellek adresi elde edilmiştir. Yani işlemci 1FC010 + 1C = 1FC02C adresinden başlayan 32 bit değeri EAX yazmacına yerleştirir.

Köşeli parantez içerisinde 16 bit yazmaç kullanılırsa sabit değer (displacement) 8 bit ya da 16 bit olabilmektedir. (Fakat bu biçimdeki komutların önüne 0x67 öneki getirildiğini anımsayınız. Bu da makine komutunu bir byte büyüteceğini anımsayınız!) Örneğin:

MOV EAX, [BX + 1FC0]

Burada BX yazmacının içerisindeki değerle 16 bitlik 1FC0 değeri toplanarak bellek adresini oluşturmaktadır.

7) Bir yazmaçla "köşeli parantez içerisindeki iki yazmaç toplamı" işleme sokulabilir. Örneğin:

ADD EAX, [EBX + ECX]

Burada EAX yazmacının içerisindeki değer bellekte EBX ve ECX yazmaçlarının içerisindeki değerlerin toplamıyla belirtilen adresteki 32 bit değer ile toplanmaktadır. Sonuç EAX yazmacına aktarılmaktadır. Örneğin bir dizinin başlangış adresi EBX’te olsun. ECX’te de 0 değerinin bulunduğunu varsayalım:

MOV EAX, [EBX + ECX]
ADD ECX, 4
...
MOV EAX, [EBX + ECX]
ADD ECX, 4
...
MOV EAX, [EBX + ECX]
ADD ECX, 4

Not: Yine 32 bit korumalı modda bellek operandı ve bit düzeyini belirten yazmaçlar 16 bit olabilir. Bu durumda 0x66 ve 0x67 önekleri gerekecektir.

8) Bir yazmaçla köşeli parantez içerisindeki yazmaç + yazmaç + 8 bit sabit ya da yazmaç + yazmaç + 32 bit sabit işleme sokulabilir. Örneğin:

MOV EAX, [EBX + ECX + 1C] ; yazmaç + yazmaç + 8 bit sabit

Burada EAX yazmacına EBX, ECX yazmacının içindeki değerlerin toplamıyla 1C değerinin toplanması sonucunda elde edilen bellek adresindeki 32 bit değer aktarılmaktadır. Örneğin:

MOV EAX, [EBX + ECX + 001A121C] ; yazmaç + yazmaç + 32 bit sabit

9) Yukarıdaki 7’inci ve 8’inci kalıplarda toplama işlemine sokulan yazmaçlardan yalnızca bir tanesi iki ile, 4 ile ya da 8 ile çarpılabilir. Örneğin:

MOV EAX, [EBX + ECX * 4]

ya da örneğin:

MOV EAX, [EBX + ECX * 4 + 1C]

ya da örneğin:

MOV EAX, [EBX + ECX * 4 + 001a121C]

Burada ECX’in içerisindeki değer 4 ile çarpılıp toplama işlemine sokulmuştur. Yukarıdaki kalıplarda köşeli parantezler içerisinde hangi yazmaçların bulunabileceği konusunda da bazı kısıtlar vardır. Genel olarak EIP ve EFLAGS yazmaçlarının dışındaki 32 bit yazmaçların hepsi köşeli parantez içerisinde kullanılabilir. Fakat köşeli parantez içerisinde hem 32 bit yazmaçlar hem de 16 bit yazmaçlar toplama işlemine sokulamazlar. Ayrıca köşeli parantez içerisinde 16 bit yazmaçların kullanımı konusunda bazı ayrıntılar vardır.