Bölüm 9: Makrolar

Mikroişlemciler
Makro kavramıMACRO / ENDMGenişletmeParametre tuzaklarıMakro ve prosedürBoyut hesabıLOCALPUTCPOWERemu8086.inc
Sercan KÜLCÜ · Giresun Üniversitesi · Elektrik-Elektronik Mühendisliği

Giriş

Öğrenme Çıktıları

Makro tanımı

MACRO / ENDM ile parametreli makro yazmak.

Genişletme

Derleyicinin makro çağrısını nasıl metin olarak açtığını izlemek.

Makro mu, prosedür mü?

Boyut, hız ve kullanım açısından iki yöntemi karşılaştırıp doğru olanı seçmek.

LOCAL

Etiket içeren makrolarda Duplicate declaration hatasını önlemek.

Uygulama

PUTC (ekrana karakter) ve POWER (üs alma) makrolarını adım adım çalıştırmak.

Tuzaklar

Parametre yan etkileri, yazmaç bozulması ve sınır durumlarını fark etmek.

Makro Kavramı

Makrolar

  • Makrolar prosedürlere benzer: tekrar eden bir kod parçasına ad verir.
  • Ancak çalışma zamanında çağrılmazlar; derleme aşamasında gerçek komutlarla değiştirilen geçici yapılardır.
  • Kod içinde kullanılmayan makrolar görmezden gelinir: makine koduna hiçbir bayt eklemezler.
  • Makrolar, prosedürlerden farklı olarak, kullanıldıkları kodun üzerinde (önce) tanımlanmalıdır; derleyici makroyu tanımadan çağrıyı açamaz.
Kaynak kodPUTC 'A'Derleyicimakroyu açarpush axmov al, 'A'mov ah, 0Ehint 10h / pop axmakine kodu(çağrı yok)

Makro Kavramı

Makro Tanımlama

name    MACRO  [parametreler,...]
        <komutlar>
        ENDM
nameMakronun adı; çağırırken komut gibi yazılır.
parametrelerVirgülle ayrılmış biçimsel adlar (isteğe bağlı). Çağrıdaki değerler bunların yerine metin olarak konur.
ENDMMakro gövdesini bitirir. Prosedürdeki gibi ad tekrar yazılmaz.
MyMacroMyMacrop1,4,p2,5,p3DXtanım: biçimsel adlarçağrı: yerine konan metinMOV CX, p3 →MOV CX, DX
Parametreler yazmaç, bellek ya da sabit olabilir: derleyici yalnızca metni değiştirir; sonuçta oluşan komutun geçerli olup olmadığına genişletmeden sonra bakılır.

Makro Kavramı

Makro Genişletme Adım Adım

MyMacro  MACRO  p1, p2, p3
         MOV AX, p1
         MOV BX, p2
         MOV CX, p3
ENDM

Önce tanım: derleyici MyMacro'yu ve p1, p2, p3 parametrelerini öğrenir; henüz kod üretmez.

MyMacro 1, 2, 3
MOV AX, p1
MOV BX, p2
MOV CX, p3

MyMacro 1, 2, 3: p1 = 1, p2 = 2, p3 = 3.

MyMacro 1, 2, 3
MOV AX, 1
MOV BX, p2
MOV CX, p3

1. satır: MOV AX, p1 → MOV AX, 1.

MyMacro 1, 2, 3
MOV AX, 1
MOV BX, 2
MOV CX, p3

2. satır: MOV BX, p2 → MOV BX, 2.

MyMacro 1, 2, 3
MOV AX, 1
MOV BX, 2
MOV CX, 3

3. satır: MOV CX, p3 → MOV CX, 3.

MyMacro 4, 5, DX
MOV AX, p1
MOV BX, p2
MOV CX, p3

MyMacro 4, 5, DX: p1 = 4, p2 = 5, p3 = DX.

MyMacro 4, 5, DX
MOV AX, 4
MOV BX, p2
MOV CX, p3

1. satır: MOV AX, p1 → MOV AX, 4.

MyMacro 4, 5, DX
MOV AX, 4
MOV BX, 5
MOV CX, p3

2. satır: MOV BX, p2 → MOV BX, 5.

MyMacro 4, 5, DX
MOV AX, 4
MOV BX, 5
MOV CX, DX

3. satır: MOV CX, p3 → MOV CX, DX.

MOV AX, 00001h
MOV BX, 00002h
MOV CX, 00003h
MOV AX, 00004h
MOV BX, 00005h
MOV CX, DX
RET

Sonuç (emu8086'nın gösterdiği gibi): iki çağrı 6 komuta açıldı. Sabitler onaltılık olarak gösterilir.

Makro Kavramı · Kodu adım adım çalıştır

Açılmış Kodu Çalıştırmak

Yükleme sonrası CX = 0012h: programın boyutu 5 × 3 + 2 + 1 = 18 bayt. SP = FFFEh.

AX = 0001h.

BX = 0002h.

CX = 0003h. Birinci çağrı bitti; hiçbir CALL/RET yok.

AX = 0004h.

BX = 0005h.

CX ← DX = 0000h (DX başlangıçta sıfır).

RET: program biter.

ORG 100h
MOV AX, 00001h   ; MyMacro 1, 2, 3
MOV BX, 00002h
MOV CX, 00003h
MOV AX, 00004h   ; MyMacro 4, 5, DX
MOV BX, 00005h
MOV CX, DX
RET

SP hiç değişmedi: makro yığın kullanmaz (gövdesinde PUSH/POP yoksa). Prosedürde CALL/RET SP'yi değiştirirdi.

Makro Kavramı · Kodu adım adım çalıştır

Tuzak: Parametreler Metindir

MyMacro BX, AX, 0 çağrısının amacı: AX ← BX, BX ← AX (takas) sanılıyor.

AX = 1111h.

BX = 2222h.

Makronun 1. satırı: MOV AX, p1 → MOV AX, BX → AX = 2222h.

2. satır: MOV BX, AX. Programcı “eski AX” (1111h) bekliyordu ama AX bir önceki satırda değişti → BX = 2222h.

CX = 0.

Sonuç: AX = BX = 2222h. 1111h kayboldu.

ORG 100h
MOV  AX, 1111h
MOV  BX, 2222h
MOV  AX, BX  ; MyMacro BX,AX,0
MOV  BX, AX  ; p2 = AX (bozuk!)
MOV  CX, 0
RET

Makro parametresi bir değişken değil, yerine konan bir metindir: değeri, kullanıldığı satırda okunur. Makro gövdesinin değiştirdiği yazmaçlar parametre olarak geçirilmemelidir.

Makro Kavramı

Parametre Türleri: Aynı Makro, Farklı Açılım

TOPLA MACRO x, y, z
  MOV AX, x
  ADD AX, y
  MOV z, AX
ENDM
ÇağrıAçılımDurum
TOPLA a, b, cMOV AX, a · ADD AX, b · MOV c, AXgeçerli
TOPLA BX, 5, CXMOV AX, BX · ADD AX, 5 · MOV CX, AXgeçerli
TOPLA a, b, 7MOV 7, AXhedef sabit olamaz
TOPLA k, b, c (k DB)MOV AX, kboyut uyuşmazlığı
TOPLA a, bMOV , AXeksik işlenen
  • Parametre yazmaç, değişken, sabit ya da ifade olabilir; hangisinin kabul edileceğini makro değil, açılımda oluşan komut belirler.
  • Hata makronun kullanıldığı satırda bildirilir, ama nedeni gövdedeki bir satırdır: hata iletisini anlamak için açılım düşünülür.
  • Eksik parametre boş metinle değiştirilir. MASM'da z:REQ parametreyi zorunlu yapar, y:=<1> ona varsayılan değer verir.

Makro Kavramı · Kodu adım adım çalıştır

Kod İzleme: TOPLA ile İki Açılım

org 100h
mov ax, a      ; TOPLA a, b, c
add ax, b
mov c, ax
mov ax, c      ; TOPLA c, 5, d
add ax, 5
mov d, ax
ret
a dw 1200h
b dw 0345h
c dw ?
d dw ?
1200ha · 01140345hb · 01160000hc · 01180000hd · 011AAX1200h

1. açılım TOPLA a, b, c: x yerine a yazıldı → AX = 1200h.

1200ha · 01140345hb · 01160000hc · 01180000hd · 011AAX1545h

ADD AX, b: 1200h + 0345h = 1545h.

1200ha · 01140345hb · 01161545hc · 01180000hd · 011AAX1545h

MOV c, AX: c = 1545h. Bellekten belleğe toplama olmadığı için makro AX'i ara yazmaç olarak kullanır.

1200ha · 01140345hb · 01161545hc · 01180000hd · 011AAX1545h

2. açılım TOPLA c, 5, d: aynı gövde, başka metin. x = c → AX = 1545h.

1200ha · 01140345hb · 01161545hc · 01180000hd · 011AAX154Ah

y = 5 bu kez bir sabit: ADD AX, 5 → AX = 154Ah.

1200ha · 01140345hb · 01161545hc · 0118154Ahd · 011AAX154Ah

MOV d, AX: d = 154Ah. İki açılım 6 komut üretti; makro AX'i bozdu ve bunu çağıran bilmelidir.

1200ha · 01140345hb · 01161545hc · 0118154Ahd · 011AAX154Ah

RET. Toplam kod 2 × (3 + 4 + 3) = 20 bayt + RET; her TOPLA kullanımı gövdeyi yeniden yazar.

Makro: TOPLA MACRO x, y, z / MOV AX, x / ADD AX, y / MOV z, AX / ENDM. Kod, iki çağrının açılmış hâlidir.

Makro Kavramı

Parametre İfadeleri ve İşlem Önceliği

ALAN MACRO en, boy
  MOV AX, en*boy
ENDM

FARK MACRO p, q
  MOV CX, p-q
ENDM
  • Parametre bir değer değil metindir: ifadenin yerine konduğu satırda işlem önceliği yeniden uygulanır.
  • ALAN 2+3, 4: çarpma önce yapılır, AX = 14 olur; beklenen 20 idi.
  • Çözüm: gövdede parametreleri paranteze almak: (en)*(boy), (p)-(q).
ÇağrıAçılımSonuç
ALAN 2+3, 4MOV AX, 2+3*4AX = 000Eh (14)
düzeltilmiş ALAN 2+3, 4MOV AX, (2+3)*(4)AX = 0014h (20)
FARK 10, 4+1MOV CX, 10-4+1CX = 0007h
ALAN BX, 2MOV AX, BX*2hata: * yalnız sabitlerle

İfade derleme anında hesaplanır; yazmaç içeren bir ifade çalışma anında çarpılamaz. Yazmacı çarpmak için MUL ya da SHL komutu gerekir.

Makro Kavramı

Etkileşimli Makro Genişletici

Çağrı
Derleyicinin ürettiği kod

Boyut karşılaştırması: aynı gövde bir prosedür olsaydı gövde + RET bir kez yazılır, her kullanım yalnızca 3 baytlık bir CALL olurdu.

Makro ve Prosedür

Prosedür Özellikleri

  • Prosedür CALL komutu ile çağrılır.
  • Prosedür belleğin belirli bir adresinde tek kopya olarak bulunur.
  • Çağrıldığında CPU kontrolü bu bölgeye aktarır; RET ile kontrol programın ana kısmına geri döner.
  • Dönüş adresini saklamak için yığın kullanılır.
  • Aynı prosedür 100 kez çağrılırsa dosya boyutu çok az artar: yakın CALL komutu yalnızca 3 bayt yer kaplar.
  • Parametre geçirmek için yığın veya yazmaçlar kullanılır.
  • Prosedür, adı ve ENDP direktifiyle sonlandırılır.
YAZ_A PROC
      PUSH AX
      MOV  AL, 'A'
      MOV  AH, 0Eh
      INT  10h
      POP  AX
      RET
YAZ_A ENDP

      CALL YAZ_A  ; 3 bayt
      CALL YAZ_A  ; 3 bayt
ana programCALL YAZ_ACALL YAZ_AYAZ_A (tek kopya)PUSH AX … POP AXRET3 bayt, dönüş adresi yığınaRET: yığındaki adrese dön

Makro ve Prosedür

Makro Özellikleri

  • Makro sadece adı yazılarak kullanılır (CALL yok).
  • Makrolar program kodunda doğrudan genişletilir.
  • Aynı makro 100 kez kullanılırsa derleyici makroyu 100 kez genişletir; çalıştırılabilir dosyanın boyutu giderek büyür.
  • Parametre geçirmek için makro adının ardından değerler yazılır.
  • Makroyu sonlandırmak için ENDM direktifi yeterlidir.
  • Makro tanımında etiketler varsa ve makro birden fazla kez kullanılırsa Duplicate declaration hatası alınabilir; değişken, etiket ve prosedür adları için LOCAL direktifi kullanılır.
PUTC MACRO char
     PUSH AX
     MOV  AL, char
     MOV  AH, 0Eh
     INT  10h
     POP  AX
ENDM

     PUTC 'A'  ; 8 bayt
     PUTC 'B'  ; 8 bayt
PUTC 'A'PUTC 'B'50B041B40ECD10588 bayt50B042B40ECD10588 baytpush ax · mov al, char · mov ah, 0Eh · int 10h · pop ax (vurgulu: parametre)

Makro ve Prosedür

Makro mu, Prosedür mü?

ÖlçütMakroProsedür
Ne zaman işlenir?Derleme zamanı (metin değiştirme)Çalışma zamanı (CALL/RET)
KullanımPUTC 'A'CALL YAZ_A
Kod boyutuHer kullanımda gövde kadar artarGövde 1 kez + her çağrı 3 bayt
HızDaha hızlı (CALL/RET ve yığın erişimi yok)Her çağrıda CALL + RET maliyeti
ParametreAd sonrası değerler, metin olarakYazmaç ya da yığın
YığınKullanmaz (gövde kullanmadıkça)Dönüş adresi için kullanır
Tanım yeriKullanımdan önceHerhangi bir yerde
BitişENDMad ENDP
EtiketlerLOCAL gerekirSorun yok (tek kopya)

Kural: kısa ve sık kullanılan, hız gerektiren kod → makro; uzun ve çok yerde kullanılan kod → prosedür. İkisi birlikte de kullanılabilir: makro, parametreleri yazmaçlara koyup bir prosedürü çağırabilir.

Makro ve Prosedür

Boyut Hesabı: 1, 10 ve 100 Kullanım

Kod boyutu (bayt) · PUTC gövdesi 8 bayt; prosedür = aynı 8 bayt + RET (1 bayt)1 kullanımmakro: 1 × 8 = 8prosedür: 9 + 1 × 3 = 12

1 kullanım: makro 8 bayt; prosedür 8 bayt gövde + 1 bayt RET + 3 bayt CALL = 12 bayt. Burada makro daha küçük.

Kod boyutu (bayt) · PUTC gövdesi 8 bayt; prosedür = aynı 8 bayt + RET (1 bayt)1 kullanımmakro: 1 × 8 = 8prosedür: 9 + 1 × 3 = 1210 kullanımmakro: 10 × 8 = 80prosedür: 9 + 10 × 3 = 39

10 kullanım: makro 80 bayt; prosedür 9 + 30 = 39 bayt.

Kod boyutu (bayt) · PUTC gövdesi 8 bayt; prosedür = aynı 8 bayt + RET (1 bayt)1 kullanımmakro: 1 × 8 = 8prosedür: 9 + 1 × 3 = 1210 kullanımmakro: 10 × 8 = 80prosedür: 9 + 10 × 3 = 39100 kullanımmakro: 100 × 8 = 800prosedür: 9 + 100 × 3 = 309

100 kullanım: makro 800 bayt; prosedür 9 + 300 = 309 bayt. Fark kullanım sayısıyla büyür.

Hız tarafında tersi geçerlidir: her CALL + RET çifti 8086'da yaklaşık 19 + 8 = 27 saat turu ve iki yığın erişimi ekler. Makroda bu maliyet yoktur.

Makro ve Prosedür

Karar Alıştırması: Makro mu, Prosedür mü?

Beş durum: her birinde kod boyutu (kaç kopya?) ve hız (CALL/RET maliyeti) birlikte tartılır.

1. Ekrana tek karakter yazmak, 200 yerde → kısa gövde (8 bayt) ama 200 kopya = 1600 bayt. Prosedür 9 + 600 = 609 bayt. Boyut önemliyse prosedür; hız önemliyse makro.

2. İki yazmacı takas eden 1 satırlık iş → XCHG zaten tek komut; makro okunabilirlik için yeterli, prosedür gereksiz yük (makro).

3. 300 baytlık sıralama algoritması, 3 yerde → makro 900 bayt, prosedür 300 + 9 bayt: açıkça prosedür.

4. Sıkı bir döngü içinde her turda yapılan 2 komutluk iş → CALL/RET maliyeti işin kendisinden büyük: makro.

5. Parametreleri yazmaçlara koyup ortak kodu çağırmak → ikisi birlikte: makro YAZ_SAYI x → MOV AX, x + CALL print_num (emu8086.inc de böyle çalışır).

Makro ve Prosedür · Kodu adım adım çalıştır

Makro Parametreyi Hazırlar, Prosedür İşi Yapar

org 100h
mov  al, 4       ; YAZ_RAKAM 4
call rakam_yaz
mov  al, 7       ; YAZ_RAKAM 7
call rakam_yaz
ret
rakam_yaz:
add  al, '0'     ; rakam → ASCII
mov  ah, 0Eh
int  10h
ret
AL04hAH00hSPFFFEhIP sonra: 0102hşu an: makro kopyası 1ekran▌yığın (SS:bağıl konum)····FFF8····FFFA····FFFC0000hFFFESP

Makro YAZ_RAKAM d, derlemede iki satıra açıldı: mov al, d + call rakam_yaz. Gövdenin asıl işi prosedürde, tek kopya. İlk kopya: AL = 04h.

AL04hAH00hSPFFFChIP sonra: 010Bhşu an: makro kopyası 1ekran▌yığın (SS:bağıl konum)····FFF8····FFFA0105hFFFCdönüşSP0000hFFFE

CALL, dönüş adresini (CALL'dan sonraki komut, 0105h) yığına iter: SP = FFFCh. IP ← rakam_yaz.

AL34hAH0EhSPFFFChIP sonra: 0111hşu an: prosedür (tek kopya)ekran4▌yığın (SS:bağıl konum)····FFF8····FFFA0105hFFFCdönüşSP0000hFFFE

Prosedür gövdesi: AL + 30h = 34h ('4'), AH = 0Eh, INT 10h ekrana 4 yazar.

AL34hAH0EhSPFFFEhIP sonra: 0105hşu an: prosedür (tek kopya)ekran4▌yığın (SS:bağıl konum)····FFF8····FFFA0105hFFFC0000hFFFESP

RET yığından 0105h'yi çeker: SP = FFFEh, yürütme makronun ilk kopyasından sonraki satırda sürer.

AL07hAH0EhSPFFFEhIP sonra: 0107hşu an: makro kopyası 2ekran4▌yığın (SS:bağıl konum)····FFF8····FFFA0105hFFFC0000hFFFESP

Makronun ikinci kopyası: AL = 07h. Her kopya yalnız 5 bayt (2 bayt MOV + 3 bayt CALL).

AL07hAH0EhSPFFFChIP sonra: 010Bhşu an: makro kopyası 2ekran4▌yığın (SS:bağıl konum)····FFF8····FFFA010AhFFFCdönüşSP0000hFFFE

Yine CALL: bu kez dönüş adresi 010Ah. Aynı prosedür, farklı dönüş adresi.

AL37hAH0EhSPFFFChIP sonra: 0111hşu an: prosedür (tek kopya)ekran47▌yığın (SS:bağıl konum)····FFF8····FFFA010AhFFFCdönüşSP0000hFFFE

Aynı tek prosedür kopyası çalışır: AL = 37h ('7'). Ekranda 47.

AL37hAH0EhSPFFFEhIP sonra: 010Ahşu an: prosedür (tek kopya)ekran47▌yığın (SS:bağıl konum)····FFF8····FFFA010AhFFFC0000hFFFESP

RET → 010Ah. Yığın yine boşaldı; çağıranın SP'si korunmuş oldu.

AL37hAH0EhSP0000hIP sonra: 0000hşu an: ana programekran47▌yığın (SS:bağıl konum)····FFF8····FFFA010AhFFFCdönüş0000hFFFE

Program biter. Makro parametreyi yazmaca koydu, ortak kod prosedürde: emu8086.inc'deki DEFINE_... + makro ikilisi de böyle çalışır.

Makro: YAZ_RAKAM MACRO d / mov al, d / call rakam_yaz / ENDM. 10 kullanımda kod 10 × 5 + 7 = 57 bayt; gövdenin tamamı makroda olsaydı 10 × 8 = 80 bayt.

Makro ve Prosedür · Kodu adım adım çalıştır

Kod İzleme: Makronun İçindeki RET

org 100h
mov al, 'A'    ; YAZ 'A'
mov ah, 0Eh
int 10h
ret            ; makronun RET'i
mov al, 'B'    ; YAZ 'B'
mov ah, 0Eh
int 10h
ret
ret
AX0041hIP0102hSPFFFEhekran

1. açılım YAZ 'A': AL = 41h.

AX0E41hIP0106hSPFFFEhekranA

AH = 0Eh, INT 10h: ekrana A yazıldı.

AX0E41hIP0000hSP0000hekranAyığından 0000h

Makronun gövdesindeki RET: makro bir prosedür değildir, CALL ile gelinmedi. RET yığının tepesindeki 0000h'yi alır: IP = 0000h.

AX0E41hIP0000hSP0000hekranAsatır 6–10 hiç çalışmadı: YAZ 'B' kayıp

PSP:0000'daki INT 20h programı bitirir. YAZ 'B' ve ana programın kendi RET'i yürütülmedi; ekranda yalnızca A var.

Makro: YAZ MACRO c / MOV AL, c / MOV AH, 0Eh / INT 10h / RET / ENDM. RET yalnızca CALL ile girilen prosedürde anlamlıdır.

Makro ve Prosedür

Makro, EQU ve Prosedür

ÖlçütEQUMakroProsedür
Ne yerine konur?tek bir değer ya da ifadebir ya da daha çok satırhiçbir şey; CALL ile gidilir
Parametreyokvar (metin)yazmaç, yığın ya da bellek
Ne zaman?derlemederlemeçalışma
Bellekteyer kaplamazher kullanımda gövde kadartek kopya + her çağrıda 3 bayt
ÖrnekSATIR EQU 80PUTC 'A'CALL PRINT_NUM
Ortak noktaEQU ile makro, assembler'ın kaynak üzerinde yaptığı metin işlemleridir; işlemci ikisini de hiç görmez, yalnız ürettikleri komutları yürütür.
SeçimTek bir sayıya ad vermek için EQU, birkaç komutluk kısa kalıp için makro, uzun ya da çok yerde kullanılan iş için prosedür.

Etiketler ve LOCAL

Etiket İçeren Makrolar: Sorun

Gövdesinde etiket olan bir makro iki kez kullanılırsa, genişletme sonucu aynı etiket iki kez tanımlanmış olur:

BEKLE MACRO
ilk:  DEC CX
      JNZ ilk
ENDM

MOV CX, 5
BEKLE
MOV CX, 9
BEKLE

Derleyicinin gördüğü:

MOV CX, 5
ilk:  DEC CX    ; 1. kopya
      JNZ ilk
MOV CX, 9
ilk:  DEC CX    ; 2. kopya !
      JNZ ilk
emu8086: Duplicate declaration hatası. Hangi ilk:'e atlanacağı belirsizdir.
1. kopyailk:DEC CXJNZ ilk2. kopyailk:DEC CXJNZ ilk?aynı ad iki kez → Duplicate declaration

Etiketler ve LOCAL

Çözüm: LOCAL Direktifi

MyMacro2 MACRO
    LOCAL label1, label2
    CMP  AX, 2
    JE   label1
    CMP  AX, 3
    JE   label2
label1:
    INC  AX
label2:
    ADD  AX, 2
ENDM
  • LOCAL, makro gövdesinin ilk satırı olmalıdır (MACRO satırından hemen sonra).
  • Listelenen adlar her genişletmede derleyici tarafından benzersiz adlarla değiştirilir (MASM'da ??0000, ??0001, …).
  • Etiketler, değişkenler ve makro içindeki prosedür adları için kullanılabilir.
Kullanımlabel1label2
1. MyMacro2??0000??0001
2. MyMacro2??0002??0003

Etiketler ve LOCAL · Kodu adım adım çalıştır

MyMacro2'yi Çalıştırmak (AX = 2)

Etiketler LOCAL ile benzersiz adlara dönüştürülmüş hâli.

AX = 2.

CMP AX, 2: 2 − 2 = 0 → ZF = 1.

JE: ZF = 1 olduğundan ??0000'a (label1) atlanır.

INC AX → AX = 3.

ADD AX, 2 → AX = 5.

Program biter.

ORG 100h
MOV  AX, 2       ; MyMacro2 öncesi
CMP  AX, 2       ; MyMacro2 başlar
JE   ??0000
CMP  AX, 3
JE   ??0001
??0000:
INC  AX
??0001:
ADD  AX, 2       ; MyMacro2 biter
RET

AX = 3 olsaydı label2'ye atlar, AX = 5 olur. AX = 7 → hiçbir atlama yok, label1'e düşer: INC + ADD → AX = 10.

Etiketler ve LOCAL · Kodu adım adım çalıştır

LOCAL ile İki Kopya, İki Ayrı Etiket

org 100h
mov cx, 3
??0000: dec cx   ; BEKLE (1. kopya)
jnz ??0000
mov cx, 2
??0001: dec cx   ; BEKLE (2. kopya)
jnz ??0001
ret
CX0003hZF01. kopya · ilk → ??0000etiket adresi 0103h2. kopya · ilk → ??0001etiket adresi 0109hIP sonra: 0103h

Makroda LOCAL ilk var. Derleyici her açılımda ilk yerine yeni bir ad koydu: 1. kopyada ??0000 (0103h), 2. kopyada ??0001 (0109h). CX = 3.

CX0002hZF01. kopya · ilk → ??0000etiket adresi 0103hJNZ: atla2. kopya · ilk → ??0001etiket adresi 0109hIP sonra: 0103h

1. tur: DEC CX → CX = 2, ZF = 0; JNZ ??0000'a (0103h) döner.

CX0001hZF01. kopya · ilk → ??0000etiket adresi 0103hJNZ: atla2. kopya · ilk → ??0001etiket adresi 0109hIP sonra: 0103h

2. tur: CX = 1, ZF = 0 → yine 0103h.

CX0000hZF11. kopya · ilk → ??0000etiket adresi 0103hJNZ: geç2. kopya · ilk → ??0001etiket adresi 0109hIP sonra: 0106h

3. tur: CX = 0 → ZF = 1; JNZ atlamaz, 1. kopya bitti.

CX0002hZF11. kopya · ilk → ??0000etiket adresi 0103h2. kopya · ilk → ??0001etiket adresi 0109hIP sonra: 0109h

CX = 2: makronun ikinci kullanımı için sayaç.

CX0001hZF01. kopya · ilk → ??0000etiket adresi 0103h2. kopya · ilk → ??0001etiket adresi 0109hJNZ: atlaIP sonra: 0109h

2. kopya: DEC CX → CX = 1; JNZ ??0001'e (0109h) döner, 1. kopyanın etiketine değil.

CX0000hZF11. kopya · ilk → ??0000etiket adresi 0103h2. kopya · ilk → ??0001etiket adresi 0109hJNZ: geçIP sonra: 010Ch

CX = 0, ZF = 1: döngü biter. Aynı etiket adı iki kez tanımlanmadığı için Duplicate declaration hatası yok.

CX0000hZF11. kopya · ilk → ??0000etiket adresi 0103h2. kopya · ilk → ??0001etiket adresi 0109hIP sonra: 0000h

RET: program biter. Toplam 3 + 2 = 5 DEC çalıştı.

Makro: BEKLE MACRO / LOCAL ilk / ilk: DEC CX / JNZ ilk / ENDM; ana programda mov cx, 3 / BEKLE / mov cx, 2 / BEKLE.

Etiketler ve LOCAL · Kodu adım adım çalıştır

Kod İzleme: BUYUK p, q, r ile İki Açılım

org 100h
mov ax, x      ; BUYUK x, y, m1
cmp ax, y
jge ??0000
mov ax, y
??0000: mov m1, ax
mov ax, y      ; BUYUK y, 4, m2
cmp ax, 4
jge ??0001
mov ax, 4
??0001: mov m2, ax
ret
x  dw 7
y  dw -3
m1 dw ?
m2 dw ?
7x-3y0m10m2AX0007hZF0SF0OF0

1. açılım BUYUK x, y, m1: AX = x = 7.

7x-3y0m10m2AX0007hZF0SF0OF0

CMP AX, y: 7 − (−3) = 10 → SF = 0, OF = 0.

7x-3y0m10m2AX0007hZF0SF0OF0SF = OF: atla

JGE işaretli karşılaştırır: SF = OF → ??0000 etiketine atlanır. LOCAL bu kopyadaki ok etiketini ??0000 yaptı.

7x-3y7m10m2AX0007hZF0SF0OF0

m1 = 7.

7x-3y7m10m2AXFFFDhZF0SF1OF0

2. açılım BUYUK y, 4, m2: AX = y = −3 (FFFDh); CMP AX, 4: −3 − 4 = −7 → SF = 1, OF = 0.

7x-3y7m10m2AXFFFDhZF0SF1OF0SF ≠ OF

SF ≠ OF: JGE ??0001 atlamaz. İkinci kopyanın etiketi ??0001; birincisiyle çakışmadı.

7x-3y7m10m2AX0004hZF0SF1OF0

Büyük olan ikinci parametre: AX = 4.

7x-3y7m14m2AX0004hZF0SF1OF0

m2 = 4; RET. JAE kullanılsaydı −3 (FFFDh) işaretsiz 65533 sayılır ve m2 = −3 olurdu.

Makro: BUYUK MACRO p, q, r / LOCAL ok / MOV AX, p / CMP AX, q / JGE ok / MOV AX, q / ok: MOV r, AX / ENDM. Birinci çağrıda parametreler değişken, ikincide biri sabit.

PUTC Makrosu

PUTC: Ekrana Karakter Yazdırma

; karakter yazar, imleci ilerletir
PUTC  MACRO  char
      push  ax
      mov   al, char
      mov   ah, 0eh
      int   10h
      pop   ax
ENDM

ORG  100h
START:
      PUTC  'A'
      PUTC  'B'
      RET
  • Makro, char parametresindeki karakteri yazar ve imleci bir sağa ilerletir.
  • INT 10h, AH = 0Eh: BIOS teletype çıkışı. AL'deki karakter imleç konumuna yazılır; 0Dh, 0Ah, 07h, 08h gibi kontrol karakterleri yorumlanır.
  • push ax / pop ax: makro AX'i kullandığı için çağıranın AX değerini korur. Makronun “görünmez” yan etkisi kalmaz.
  • Bu makro emu8086.inc kütüphanesindeki PUTC makrosunun aynısıdır.
PUTC 'B''den sonraki RET programı bitirir; o olmasa işlemci program sonundaki rastgele baytları çalıştırmaya devam ederdi.

PUTC Makrosu · Kodu adım adım çalıştır

PUTC 'A' ve PUTC 'B' Çalışırken

····FFFA····FFFC0000hFFFESPSS:bağıl konum · küçük adres yukarıda

Yükleme sonrası CX = 0011h: 2 kopya × 8 bayt + RET = 17 bayt. Ekran boş.

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

AX (0000h) yığına saklanır; SP = FFFCh.

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

AL = 41h ('A').

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

AH = 0Eh → AX = 0E41h.

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

INT 10h: ekrana A yazılır, imleç ilerler.

····FFFA0000hFFFC0000hFFFESPSS:bağıl konum · küçük adres yukarıda

AX eski değerine (0000h) döner; SP = FFFEh.

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

İkinci kopya: AX yine saklanır.

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

AL = 42h ('B').

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

AX = 0E42h.

····FFFA0000hFFFCSP0000hFFFESS:bağıl konum · küçük adres yukarıda

INT 10h: ekranda AB.

····FFFA0000hFFFC0000hFFFESPSS:bağıl konum · küçük adres yukarıda

AX = 0000h; makro çağıranın AX'ini bozmadı.

····FFFA0000hFFFC0000hFFFESS:bağıl konum · küçük adres yukarıda

RET: program biter.

ORG  100h
push ax          ; PUTC 'A'
mov  al, 'A'
mov  ah, 0eh
int  10h
pop  ax
push ax          ; PUTC 'B'
mov  al, 'B'
mov  ah, 0eh
int  10h
pop  ax
RET

emu8086 ekran penceresinde (80×25) çıktı: AB. Her PUTC kopyası 8 bayt: 50 B0 41 B4 0E CD 10 58.

PUTC Makrosu

Yazmaç Saklama Makroları

SAKLA MACRO
  PUSH AX
  PUSH BX
  PUSH CX
  PUSH DX
ENDM

GERI_AL MACRO
  POP DX
  POP CX
  POP BX
  POP AX
ENDM
  • PUTC'deki push ax / pop ax kalıbı büyük makrolarda dört yazmaca çıkar; bu kalıp da bir makro olabilir.
  • GERI_AL, SAKLA'nın ters sırasıyla çeker: yığın son giren ilk çıkar. Sıra aynı yazılırsa AX ile DX, BX ile CX yer değiştirir.
  • Her SAKLA + GERI_AL çifti 8 bayt ve 8 yığın erişimi ekler: 8086'da 4 × 11 (PUSH) + 4 × 8 (POP) = 76 saat turu.
  • Bu iki makro bir gövdede birlikte kullanılmalıdır; araya giren bir koşullu çıkış yığını dengesiz bırakır.
80186 ve sonrasında tek komutluk PUSHA / POPA bütün genel amaçlı yazmaçları saklar; 8086'da bu komutlar yoktur, bu yüzden makroyla yazılır.

POWER Makrosu

Üs Alma: POWER Makrosu

POWER macro b, e, r
    mov ax, 1        ; geçici sonuç = 1
    mov cx, e        ; üs → CX
    mov bx, b        ; taban → BX
powerloop:
    mul bx           ; DX:AX = AX * BX
    loop powerloop   ; e kez tekrarla
    mov r, ax        ; sonucu yaz
endm
ORG 100h
start:
    POWER base, exponent, result
    ret
base     dw 2     ; taban
exponent dw 3     ; üs
result   dw ?     ; sonuç
  • Sonuç r = be: AX'i 1 ile başlatıp e kez taban ile çarpar.
  • MUL BX: DX:AX ← AX × BX (işaretsiz). DX de değişir!
  • LOOP: CX'i 1 azaltır, CX ≠ 0 ise etikete atlar.

POWER Makrosu · Kodu adım adım çalıştır

POWER 2, 3 Adım Adım

Veriler kodun hemen arkasında: base = 0113h, exponent = 0115h, result = 0117h (kod 19 bayt).

AX = 1 (geçici sonuç).

CX ← [0115h] = 3 (üs).

BX ← [0113h] = 2 (taban).

1. tur: DX:AX = 1 × 2 = 0002h.

LOOP: CX = 2 ≠ 0 → powerloop.

2. tur: AX = 2 × 2 = 0004h.

LOOP: CX = 1 → powerloop.

3. tur: AX = 4 × 2 = 0008h.

LOOP: CX = 0 → döngüden çık.

result ← AX: [0117h] = 0008h = 23.

RET: program biter.

ORG 100h
mov ax, 1        ; POWER açılımı
mov cx, exponent
mov bx, base
powerloop:
mul bx
loop powerloop
mov result, ax
ret
base     dw 2    ; 0113h
exponent dw 3    ; 0115h
result   dw ?    ; 0117h

MUL sonrası DX = 0 olduğundan CF = OF = 0. Sonuç 16 biti aşsaydı (ör. 216) DX ≠ 0 ve CF = 1 olurdu; makro yalnızca AX'i sakladığı için sonuç yanlış olurdu.

POWER Makrosu

POWER Makrosunun Tuzakları

1. Üs = 0CX = 0 iken LOOP önce CX'i azaltır: FFFFh → döngü 65 536 kez döner; b0 = 1 olmalıydı. Çözüm: JCXZ.
2. Etiketpowerloop LOCAL değil: ikinci kullanımda Duplicate declaration.
3. Yazmaç bozulmasıAX, BX, CX ve (MUL yüzünden) DX değişir.
4. TaşmaSonuç 65 535'i aşarsa yüksek kısım DX'te kalır ve yazılmaz.

Düzeltilmiş sürüm:

POWER MACRO b, e, r
      LOCAL p_loop, p_end
      PUSH BX
      PUSH CX
      PUSH DX
      MOV  AX, 1
      MOV  CX, e
      MOV  BX, b
      JCXZ p_end   ; e = 0 → 1
p_loop: MUL BX
      LOOP p_loop
p_end: MOV r, AX
      POP  DX
      POP  CX
      POP  BX
ENDM

POWER Makrosu · Kodu adım adım çalıştır

Düzeltilmiş POWER 7, 2 Adım Adım

org 100h
push bx          ; POWER açılımı
push cx
push dx
mov  ax, 1
mov  cx, us
mov  bx, taban
jcxz ??0001      ; us = 0 → 1
??0000: mul bx
loop ??0000
??0001: mov sonuc, ax
pop  dx
pop  cx
pop  bx
ret
taban dw 7
us    dw 2
sonuc dw ?
AX0000hBX0AAAhCX0BBBhDX0CCChsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

Çağıranın yazmaçları BX = 0AAAh, CX = 0BBBh, DX = 0CCCh. Düzeltilmiş makro önce üçünü de yığına saklar: SP = FFF8h.

AX0001hBX0007hCX0002hDX0CCChsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

AX = 1, CX ← us = 2, BX ← taban = 7. Yazmaçlar artık makronun.

AX0001hBX0007hCX0002hDX0CCChsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

JCXZ: CX = 2 ≠ 0, atlama yok. us = 0 olsaydı doğrudan ??0001'e gidilir, sonuç 1 olurdu (LOOP'un 65 536 tur tuzağı yok).

AX0007hBX0007hCX0002hDX0000hsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

1. MUL: DX:AX = 1 × 7 = 0007h. MUL, DX'i de yazar (DX = 0).

AX0007hBX0007hCX0001hDX0000hsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

LOOP: CX = 1 ≠ 0 → ??0000.

AX0031hBX0007hCX0001hDX0000hsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

2. MUL: DX:AX = 7 × 7 = 0031h = 49.

AX0031hBX0007hCX0000hDX0000hsonuc????yığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

LOOP: CX = 0 → döngüden çık.

AX0031hBX0007hCX0000hDX0000hsonuc0031hyığın0CCChFFF8DXSP0BBBhFFFACX0AAAhFFFCBX0000hFFFE

sonuc ← AX: [011Fh] = 0031h = 7². Etiketler LOCAL ile ??0000 / ??0001 adını aldı.

AX0031hBX0AAAhCX0BBBhDX0CCChsonuc0031hyığın0CCChFFF80BBBhFFFA0AAAhFFFC0000hFFFESP

Üç POP, PUSH'ların tersi sırada: DX = 0CCCh, CX = 0BBBh, BX = 0AAAh geri geldi; SP = FFFEh. Makro yalnız AX'i değiştirdi.

AX0031hBX0AAAhCX0BBBhDX0CCChsonuc0031hyığın0CCChFFF8DX0BBBhFFFACX0AAAhFFFCBX0000hFFFE

RET: program biter.

Kod, düzeltilmiş makronun POWER taban, us, sonuc açılımıdır; LOCAL adları derleyicinin ürettiği biçimde gösterildi.

POWER Makrosu

İç İçe Makrolar

PRINT2 MACRO c1, c2
       PUTC c1
       PUTC c2
ENDM

PRINT2 'O', 'K'
; 1. düzey: PRINT2 açılır
PUTC 'O'
PUTC 'K'

Önce dıştaki makro açılır: gövdedeki iki satır da birer makro çağrısıdır.

PRINT2 MACRO c1, c2
       PUTC c1
       PUTC c2
ENDM

PRINT2 'O', 'K'
PRINT2 'O', 'K'PUTC 'O'5 komut · 8 baytPUTC 'K'5 komut · 8 bayt
; 2. düzey: PUTC'ler açılır
push ax
mov  al, 'O'
mov  ah, 0eh
int  10h
pop  ax
push ax
mov  al, 'K'
mov  ah, 0eh
int  10h
pop  ax

Derleyici iç makroları da açar: tek satırlık çağrı 10 komut (16 bayt) üretir. Ekranda: OK.

PUTC, PRINT2'den önce tanımlanmış olmalıdır. Bir makro kendini çağırırsa (özyineleme) koşullu derleme olmadan genişletme hiç bitmez.

Makro Kütüphaneleri

Makro Kütüphaneleri: emu8086.inc

  • Sık kullanılan makrolar ayrı bir dosyada toplanır ve INCLUDE ile programa eklenir.
  • Kullanılmayan makrolar kod üretmediği için büyük bir kütüphaneyi eklemek dosyayı büyütmez.
  • Makrolar başka makroları çağırabilir (iç içe genişletme).
  • Kütüphane, makroların yanında DEFINE_... makrolarıyla prosedürler de sunar (ör. DEFINE_SCAN_NUM): ikisi birlikte kullanılır.
Makroİşlev
PUTC chTek karakter yazar
PRINT 'metin'Metin yazar
PRINTN 'metin'Metin + yeni satır
GOTOXY x, yİmleci taşır
CURSOROFFİmleci gizler
include 'emu8086.inc'
ORG 100h
    GOTOXY 10, 5
    PRINT 'Merhaba'
    PUTC  '!'
    RET

Makro Kütüphaneleri · Kodu adım adım çalıştır

emu8086.inc: PRINT 'OK' Açılımı

org 100h
push ax          ; PRINT 'OK'
push si
jmp  ??0003      ; veriyi atla
??0001 db 'OK', 0
??0003: lea si, ??0001
??0000: mov al, cs:[si]
cmp  al, 0
jz   ??0002
inc  si
mov  ah, 0Eh
int  10h
jmp  ??0000
??0002: pop si
pop  ax
ret
kod kesimindeki dizgi'O'0104h'K'0105h00h0106hAL00hSI0000hekran▌yığın0000hFFFASP0000hFFFC0000hFFFE

PRINT 'OK' açıldı. Makro AX ve SI'yı kullanacağı için önce ikisini yığına saklar.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hAL00hSI0000hekran▌yığın0000hFFFASP0000hFFFC0000hFFFE

Dizgi, makronun içinde kodun arasına gömülü (0104h: 'O', 'K', 0). JMP, işlemcinin bu baytları komut sanmaması için üzerinden atlar.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hSIAL00hSI0104hekran▌yığın0000hFFFASP0000hFFFC0000hFFFE

SI ← dizginin adresi 0104h. LOCAL adları (??0000…) her PRINT için yenidir.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hSIAL4FhSI0104hekran▌yığın0000hFFFASP0000hFFFC0000hFFFE

AL ← CS:[SI] = 4Fh ('O'). Dizgi kod kesiminde olduğu için CS: öneki kullanılır. 0 değil → devam.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hSIAL4FhSI0105hekranO▌yığın0000hFFFASP0000hFFFC0000hFFFE

SI bir ilerler, INT 10h/0Eh ekrana O yazar, JMP döngü başına döner.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hSIAL4BhSI0105hekranO▌yığın0000hFFFASP0000hFFFC0000hFFFE

AL = 4Bh ('K'); sonlandırıcı değil.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hSIAL4BhSI0106hekranOK▌yığın0000hFFFASP0000hFFFC0000hFFFE

Ekranda OK.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hSIAL00hSI0106hekranOK▌yığın0000hFFFASP0000hFFFC0000hFFFE

AL = 00h: CMP → ZF = 1, JZ çıkışa atlar.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hAL00hSI0000hekranOK▌yığın0000hFFFA0000hFFFC0000hFFFESP

SI ve AX yığından geri alınır: makro çağıranın yazmaçlarını bozmadı.

kod kesimindeki dizgi'O'0104h'K'0105h00h0106hAL00hSI0000hekranOK▌yığın0000hFFFA0000hFFFC0000hFFFE

RET: program biter. Tek satırlık PRINT 'OK', 27 baytlık kod + veri üretti.

emu8086.inc'deki PRINT makrosunun açılımı (LOCAL adları derleyicinin ürettiği biçimde). PRINTN aynı işi yapıp sonuna CR LF ekler.

İleri Makro Özellikleri

Makro İşleçleri: &, <>, !, %, ;;

İşleçGöreviÖrnek ve açılım
&parametreyi bitişik metne eklerSIFIRLA MACRO r · XOR r&X, r&X → SIFIRLA B: XOR BX, BX
< >virgül ya da boşluk içeren metni tek parametre yaparYAZ <'A', 'B'> → tek parametre: 'A', 'B'
!sonraki karakteri sıradan karakter yapar<5 !> 3> → metin: 5 > 3
%ifadeyi hesaplar, sonucu metin olarak koyarGOSTER %(4*8) → parametre 32
;;makro açıklaması; açılıma kopyalanmaz;; yalnızca tanımda görünür
  • Bu işleçler MASM ve TASM'da tanımlıdır; makro tanımı yazılırken metni parçalamak ve birleştirmek için kullanılır.
  • & olmadan rX tek bir ad sayılır ve parametre yerine konmaz.
  • Tek ; ile yazılan açıklama her açılımda tekrarlanır; ;; liste dosyasını kısaltır.

İleri Makro Özellikleri

Tekrar Blokları: REPT, IRP, IRPC

REPT n
REPT 3
  SHL AX, 1
ENDM
açılım: üç kez SHL AX, 1 (AX × 8)
IRP p, <liste>
IRP r, <AX,BX,CX>
  PUSH r
ENDM
açılım: PUSH AX · PUSH BX · PUSH CX
IRPC p, metin
IRPC c, OK
  PUTC '&c'
ENDM
açılım: PUTC 'O' · PUTC 'K'
  • Tekrar blokları adı olmayan, tanımlandığı yerde hemen açılan makrolardır; ENDM ile biter.
  • REPT gövdeyi n kez, IRP listedeki her öğe için bir kez, IRPC metindeki her karakter için bir kez yazar. MASM 6'da IRP ve IRPC, FOR ve FORC adlarıyla da yazılır.
  • Döngü sayacına gerek kalmaz ama kod büyür: REPT 100 gövdeyi 100 kez kopyalar. Sayaçlı LOOP ise tek kopyayla çalışır.
  • En yaygın kullanım derleme anında tablo üretmektir: sayı tabloları, maskeler, kare ya da sinüs değerleri.

İleri Makro Özellikleri · Kodu adım adım çalıştır

Kod İzleme: REPT ile Üretilen Kare Tablosu

org 100h
lea  bx, kare
mov  al, 5
xlat           ; AL = kare[5]
mov  dl, al
mov  al, 7
xlat           ; AL = kare[7]
add  al, dl
ret
kare db 0, 1, 4, 9, 16, 25, 36, 49
0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL00hDL00h

Tablo REPT ile derlemede üretildi; bellekte yalnızca 8 bayt var. LEA BX, kare: BX = 010Fh.

0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL05hDL00h

AL = 5: karesi aranan sayı, aynı zamanda tablo indisi.

0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL19hDL00h[BX + AL]

XLAT: AL ← [BX + AL] = kare+5 = 25 (19h). Çarpma yapılmadı, tablodan okundu.

0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL19hDL19h

DL = 19h: ilk sonuç saklanır.

0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL31hDL19h

AL = 7, XLAT → kare+7 = 49 (31h).

0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL4AhDL19h25 + 49

ADD AL, DL: 49 + 25 = 74 (4Ah) = 5² + 7².

0kare+01kare+14kare+29kare+316kare+425kare+536kare+649kare+7BX010FhAL4AhDL19h

RET. XLAT 11 saat turudur; 8086'da 8 bitlik MUL ise 70–77 tur sürer.

Tablonun kaynağı: n = 0 / kare LABEL BYTE / REPT 8 / DB n*n / n = n + 1 / ENDM. Kod bu bloğun açılmış hâliyle çalıştırıldı. EQU sabiti değiştirilemez; = ile tanımlanan sembol her turda yeni değer alır.

İleri Makro Özellikleri

Koşullu Derleme: IF, IFB, IFIDN

KAYDIR MACRO r, n
  IFB <n>          ;; n verilmedi mi?
    SHL r, 1
  ELSE
    MOV CL, n
    SHL r, CL
  ENDIF
ENDM

HATA_AYIKLA = 1
IF HATA_AYIKLA
  PUTC '*'         ; yalnız deneme sürümünde
ENDIF
DirektifKoşul
IF ifadeifade ≠ 0
IFE ifadeifade = 0
IFB <p>parametre boş
IFNB <p>parametre dolu
IFIDN <a>,<b>iki metin aynı
IFDIF <a>,<b>iki metin farklı
  • Koşul derleme anında değerlendirilir: seçilmeyen dal makine koduna hiç girmez, çalışma anında bayrak ya da atlama yoktur.
  • EXITM açılımı o noktada bitirir; IFIDN <r>, <CX> ile gövdenin bozacağı yazmacın parametre olarak verilmesi yakalanabilir.

İleri Makro Özellikleri · Kodu adım adım çalıştır

Kod İzleme: KAYDIR AX ve KAYDIR BX, 3

org 100h
mov ax, 5
mov bx, 3
shl ax, 1      ; KAYDIR AX
mov cl, 3      ; KAYDIR BX, 3
shl bx, cl
ret
AX0005hBX0003hCL00hAL = 00000101BL = 00000011CF = 0

AX = 5, BX = 3: kaydırılacak değerler.

AX000AhBX0003hCL00hAL = 00001010BL = 00000011CF = 0IFB dalı

KAYDIR AX: n boş, IFB dalı seçildi → tek komut SHL AX, 1. AX = 000Ah (5 × 2).

AX000AhBX0003hCL03hAL = 00001010BL = 00000011CF = 0ELSE dalı

KAYDIR BX, 3: n = 3, ELSE dalı → MOV CL, 3. 8086'da 1'den büyük kaydırma sayısı CL'de verilir.

AX000AhBX0018hCL03hAL = 00001010BL = 00011000CF = 0

SHL BX, CL: 3 × 2³ = 0018h (24). Aynı makro iki farklı uzunlukta kod üretti: 2 bayt ve 4 bayt.

AX000AhBX0018hCL03hAL = 00001010BL = 00011000CF = 0

RET. KAYDIR AX açılımı CL'ye dokunmadı; yalnız ikinci açılım CL'yi değiştirdi.

Kod, KAYDIR makrosunun iki çağrısının açılmış hâlidir. Hangi dalın yazılacağına derleyici karar verdi; çalışma anında karşılaştırma yapılmadı.

İleri Makro Özellikleri

Makroda Hata Ayıklama ve Listeleme

Açılımı görmekemu8086'nın öykünücü penceresindeki komut listesi, makro adlarını değil açılmış komutları gösterir; tek adım çalıştırma da bu komutlar üzerinde ilerler.
Liste dosyasıMASM'da .LISTMACROALL açılımın bütün satırlarını, .LISTMACRO yalnız kod üretenleri listeler, .NOLISTMACRO açılımı gizler.
Hata satırıGövdedeki bir hata, makronun kullanıldığı her satırda ayrı ayrı bildirilir. Aynı hata birkaç kez görülüyorsa neden çoğunlukla gövdededir.
Önce elle açmakYeni bir makro, gövdesi önce düz kod olarak yazılıp denenerek geliştirilir; çalıştıktan sonra parametreli makroya dönüştürülür.
Makro etiketleri LOCAL ile ??0000 gibi adlar aldığı için öykünücüdeki atlama hedefleri kaynaktaki adlarla görünmez; hangi kopyanın çalıştığını bu numaralar gösterir.

İleri Makro Özellikleri

Sık Yapılan Makro Hataları

Kullanımdan sonra tanımlamakAssembler makroyu tanımadan çağrıyı açamaz; tanımlar dosyanın başına ya da INCLUDE dosyasına.
ENDM'i unutmakDosyanın geri kalanı makro gövdesi sayılır; hata çok aşağıdaki bir satırda görünür.
Etiketi LOCAL yapmamakİkinci kullanımda Duplicate declaration.
Gövdede RETMakro CALL ile çağrılmaz; RET çağıranın dönüş adresini alır.
Bozulan yazmacı parametre vermekTOPLA AX, BX, CX gibi çağrılarda gövde parametreyi okunmadan değiştirebilir.
Parantezsiz ifadeen*boy yerine (en)*(boy); aksi hâlde öncelik değişir.
Makroyu döngü sanmakREPT 1000 1000 kopya üretir; çalışma anında tekrar için LOOP gerekir.
Uzun gövdeyi çok kullanmakKod boyutu kullanım sayısıyla büyür; uzun iş prosedüre taşınır.

Özet

Özet

KonuHatırlanacak nokta
Tanımad MACRO p1, p2 … ENDM; kullanımdan önce tanımlanır.
GenişletmeDerleme zamanında metin değiştirme; çalışma zamanında CALL yok.
ParametrelerMetin olarak yerine konur; değerleri kullanıldıkları satırda okunur.
Boyut / hızMakro: her kullanımda gövde kadar büyür, daha hızlıdır. Prosedür: 3 bayt CALL, CALL/RET maliyeti.
LOCALEtiketlerin her genişletmede benzersiz olması için gövdenin ilk satırı.
Yan etkilerMakronun değiştirdiği yazmaçlar PUSH/POP ile korunur (PUTC gibi).
Sınır durumlarıLOOP'tan önce CX = 0 kontrolü (JCXZ).

Özet

Alıştırmalar

  1. MyMacro AX, BX, CX çağrısının genişletilmiş hâlini yazın. Hangi satır gereksizdir?
  2. İki sözcük değişkeni toplayıp üçüncüsüne yazan TOPLA a, b, c makrosunu yazın.
  3. PUTC makrosu 50 kez, aynı işi yapan prosedür 50 kez çağrılırsa kod boyutları ne olur?
  4. POWER makrosu POWER base, exponent, result ile iki kez kullanıldığında hangi hata alınır? Nasıl düzeltilir?
  5. exponent = 0 iken orijinal POWER makrosu kaç kez MUL çalıştırır?
  6. Bir makronun AX dışında hiçbir yazmacı bozmaması için hangi komutlar eklenmelidir?
Cevaplar
  1. MOV AX, AX / MOV BX, BX / MOV CX, CX: üçü de etkisizdir (derlenir ama hiçbir şey değiştirmez).
  2. TOPLA MACRO a, b, c / MOV AX, a / ADD AX, b / MOV c, AX / ENDM (bellek–bellek işlemi olmadığı için AX aracı).
  3. Makro: 50 × 8 = 400 bayt. Prosedür: 9 + 50 × 3 = 159 bayt.
  4. Duplicate declaration (powerloop). LOCAL powerloop eklenir.
  5. 65 536 kez (CX: 0 → FFFFh → … → 0).
  6. Gövdenin başında kullanılan yazmaçlar için PUSH, sonunda ters sırada POP.

Özet

Kaynaklar

  • emu8086 yardım belgeleri: 8086 Assembler Tutorial, Part 10 (Macros) ve emu8086.inc.
  • Microsoft, MASM Programmer's Guide — MACRO, ENDM, LOCAL direktifleri.
  • K. R. Irvine, Assembly Language for x86 Processors, 7. baskı, Pearson, 2014 — Bölüm 10 (Makrolar).
  • B. B. Brey, The Intel Microprocessors, 8. baskı, Pearson, 2009.

Son

Bölüm 9: Makrolar
Sonraki bölüm: Bölüm 9: emu8086.inc Kütüphanesi · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.