Debug ve Kullanımı
İster DOS olsun isterse Windows, çalıştırılabilir iki tipte dosya bulunur.
Com veya exe tipindedir. Com tipi dosyalar birebir programın bellekteki şeklinin
aynısıdır. Exe tipi dosyalarda ise programın başında işletim sisteminin
anlayacağı tipte bir başlık bulunur. İşletim sistemi bu kısımdaki direktiflere
göre code, data ve diğer segmentleri bellekte boş olan yerlere göre hafızaya
yükler ve ilgili segmentlerin adreslerini registerlere aktararak programin ilk
komutu ile işlemi programa bırakır. Com tipi programlarda böyle bir düzenleme
yapılmaz, sadece diskten okunur, boş bir bellek adresine yerleştirilerek yürütme
programa bırakılır. Tabii dos altında olsa idik tam olarak böyle idi. Windows
altında dos için yazılmış olan tüm programlar bir dos emülasyon penceresi
altında sanal bir ortamda çalışırlar. (Com dosyaları 64k dan daha uzun
olamazlar, exe tipi dosyalarda bu tür bir sınırlama olmayıp gelişmiş özellikler
içerirler. Bu nedenlerle exe tip dosyalar daha çok kullanılırlar.)
Exe tipi programlar derlenerek hazırlabilirler, fakat com tipi dosyaların
derlenmeye ihtiyacı yoktur ve Debug.exe isimli komut satırı programı ile bunlar
programlanabilir. Debug.exe tüm dos ve windows işletim sistemleri ile birlikte
geldiği için ek bir program kurmanıza gerek yoktur. Tabii bu programı sadece
komutların kullanımlarını görmek, programımızı satır satır çalıştırarak
registerleri nasıl etkilediğini görmek amacıyla kullanacağız. Fakat kullandıkça
vazgeçmesi zor bir programdır, yani bağımlılık yapar. (Şunu unutmamalıyız: Debug
ile 16 bit registerlere ulaşabilir ve bu şekilde program yazabiliriz, 32bit ile
çalışmalar bir sonraki bölümden itibaren başlayacaktır.)
Başlat -> Çalıştır yolunu izleyerek
command yazıyoruz. Sonra debug yazıp enterleyin.
Karşımıza sadece '-' işareti geldi. Artık debug bizden komut girmemizi
bekliyor. Aşağıda ilk programımızı yazdık, şimdi biraz anlatalım.
Komut satırını açarak debug'a geçiş yaptık. 'a100'
şeklinde bir ifade var. 'a' komutu bizim assembly
kodlarının girişine başlayacağımızı bildirir. sonundaki '100' ise komutları
yazmaya başlayacağımız adrestir. Debug ile sadece com tipi dosyalar
yazılabiliyor ve bu tür programlar 100h adresinden itibaren yazılırlar. (Debug
altında gireceğimiz tüm matematiksel ifadeler hexadecimal sistemdedir!!! Yani
100h aslında decimal 256'ya denk gelir.)
mov ah,2 : MOV
komutu bizim en çok kullanacağımız komutlardan biri. Sağdaki register içeriğini
veya herhangi bir hexadecimal sabit değerin soldaki registere kaydedilmesidir.
Tabii bu durumda ah'ın eski değeri kaybolur, zaten bizim için şu anda bunun
önemi yok. (com tipi dosyalarda program ilk çalışmaya başladığında çoğu
registerin değeri sıfırdır.)
mov dl,3 : Yukarıdaki MOV
komutu gibi burada da bir atama söz konusu. DL
isimli 8bit registere 3h değeri kaydediliyor.
int 21, int 20 : Bu komutlar dos kullanıldığı
zamanlarda geçerli idi. Benzer işlemde şu anda windows altında API fonksiyonları
görev yapmaktadır. Bunları bir tür dos işletim sisteminin bize sunduğu hazır
fonksiyonlar olarak görebiliriz. Elbette sadece 20 ve 21 bulunmamakta. Fakat
bunlara değinmeyeceğiz. (int=interrupt) Interrupt 20 parametresiz çağırılır ve
bizim com tipi programımızı sonlandırır. Interrupt 21 dos ile gelen dev bir
fonksiyonlar kütüphanesidir. Hangi numaralı fonksiyonun çağırılacağını ah
registerine koymak zorundayız. Fonksiyonun tipine göre istenen başka değerler
bulunuyor ise bunlar da ilgili registerlara atanmalıdır. Daha sonra interrup
çağrısı yapılır. Biz iki numaralı fonksiyonu (yani ekrana karakter yollama
fonksiyonu) çağırıyoruz, bunun için ah a 2 atadık. Daha sonra ASCII karakter
tablosuna göre hangi değer ekrana getirilecek ise onun hexadecimal değerini DL
registerine atıyoruz. (Burada 3h kalp şeklinde bir karakter, eğer 41h değeri
atanırsa 'A' harfi ekrana basılır.) (Bunlardan sonraki satırı ENTER ile boş
geçin.)
g : ile programa çalışma emri veriliyor.
Gördüğünüz gibi bir karakter ekrana basılıp program int 20 ye geldiğinde normal
olarak sonlanıyor.
n : ile programımıza isim veriyoruz.
r cx ile cx
registerinin değerini değiştirerek 8 giriyoruz çünkü programımızın son satırı
0108 adresini gösteriyor. Ilk satır
0100 ise arada 8 byte yokmu? Yani programımız 8byte
uzunluğunda ve biz bunu cx'e aktararak diske kaydedilecek programın boyutunu
belirtiyoruz ve w ile işlem tamamlanıyor. Artık q komutunu verip Debug'dan çıkın
ve bulunduğunuz dizinde 8 byte uzunluğunda bir kalp.com isimli program var mı
bir bakın. Veya hemen kalp yazıp ekran çıktısının debug içinde g komutu ile
aldığımızın aynısı olduğunu görebilirsiniz. Bu bizim ilk programımız oldu.
Yukarıdaki çalışma yine aynı program üzerinde yapıldı. Burada
t (trace, izle) komutu ile programımızı satır satır
çalıştırdık ve registerler üzerindeki etkilerine baktık. Interruptlar birer dev
kod bloğu olduğuna göre ve bunları da trace eder isek sayfalar sonra içinde
çıkabileceğimiz için bunları pas geçmek için p kullanıldı. Ilk komut işlendikten
sonra ekrana ilk gelen bölümü inceleyelim. Ilk komut mov
ah,2 idi. Gördüğünüz gibi AX=0200 bölümünde
AX in üst 8 bitine yani AH'a 2 değeri atanmış.
Burada dikkat ederseniz DS,ES,SS,CS değerleri yani
segment registerları aynı blok adresini gösteriyorlar. Yani com tipi dosyalarda
kodlar ile datalar aynı yerde bulunuyor. Bu da bize program yazarken dikkatli
olmamız gerektiği anlamında önemli bir not. IP pointeri daima sırada işlenecek
olan komıtu gösterir. Ilk komut işlendiğine göre 0102 değerini gösteriyor. IP
nin hemen sağ tarafındaki ifadeler flagların durumlarını göstermektedir, şu anda
önemli değil. Üçüncü satırda sırayla şunlar yer alıyor: CS:IP
<MAKINA KODU> <ASSEMBLY KARŞILIĞI>
Ikinci trace'de DL ye 3 değerinin aktarılmış
olduğu rahatlıkla görülebilir. Bundan sonraki p komutu ile
int 21 işleme girer ve ekranda görülen kalp işareti geliyor.
int 20 de programdan çıkılıyor. Bu basit bir örnek
oldu, daha karmaşık bir örnek inceleyelim.
mov ah,2 : Interrupt 21 içindeki 2 numaralı
fonksiyon yani ekrana karakter basmamız için atıyoruz.
mov cx,FF : Şu ana kadar görmediğimiz döngü
işlemi için kullanılacak. FF yani decimal 255
değeri CX e atanıyor. Aşağıdaki
loop <adres> komutuna gelindiğinde cx in değeri bir
azaltılıyor ve sıfıra eşit değil ise <adres> değerine atlıyor program. CX
içindeki sayı kadar bu loop döngüsü devam ediyor, yani 255 defa. CX sıfıra eşit
olduğunda ise hiçbir işlem yapılmıyor ve bir alttaki komut ile programa devam
ediliyor. Diyebiliriz ki LOOP komutu gizli olarak cx registerini kullanmaktadır.
inc dl : inc komutu karşısındaki registerin
değerini bir artırır. Biliyorsunuz ki ekrana gönderilecek karakter dl içinde.
Biz 255 döngü içinde 1 ila 255 arasındaki tüm ASCII karakterleri ekrana basmak
istiyoruz. Bunun için toplama işlemi de yapabilirdik (add dl,1) fakat bu işlemin
okunurluğu daha iyidir.
int 21 : Ekrana karakter yazma fonksiyonu
çağırılıyor.
loop 105 : CX
sıfıra eşit değil ise 105 adresine zıpla.
int 20 : Programdan çık.
Aşağıda g (go) komutu ile çıktı alınıyor. Tabii
buradaki karakter seti dos altındaki; windows altındaki ile uyuşmayabilir. Daha
sonra ise ascii.com şeklinde kaydediliyor.
Aşağıda bazı assembly komutları ve açıklamaları bulunuyor:
MOV : Değer aktarmak için kullanılır.
mov ah,2 mov ax,FFFF mov bx,cx mov dl,bh mov [200],ah mov
dl,[382] gibi. (Köşeli parantez 'adresindeki' anlamındadır. Yani ah
içeriğini 200 adresine transfer et gibi.) XCHG :
İki registerin içeriklerini karşılıklı olarak değiştirmelerini sağlar.
xchg ah,bh xchg ax,dx gibi.
ADD : İki değerin toplanması amacıyla kullanılır.
Sonuç değer soldaki registere kaydedilir. add ax,bx add
ah,AF add dl,1 add al,ah gibi. SUB :
Çıkarma işlemi yapar. Sonuç ilk registere kaydedilir. sub
ah,1 sub ax,bx sub cx,10 gibi. MUL : Çarpma işlemi yapar. Tabii ki tüm
işlemlerde olduğu gibi değerler ve sonuçlar hexadecimaldir. 3 farklı durumda
incelenebilir. 8bit*8bit yani
byte*byte : Çarpılacak değerlerden biri
al ye
kaydedilir mov al,5F gibi. Daha sonra çarpma
işlemi yapılır, mul bl gibi. Sonuç ise
ax registerindedir. (ax=al*bl işlemi)
16bit*16bit yani word*word
: Çarpılacak değerlerden biri ax ye
kaydedilir mov ax,05FF gibi. Daha sonra çarpma
işlemi yapılır, mul bx gibi. Sonuç ise
dx,ax ikilisine aktarılmıştır. Yani üst 16bitlik
kısım dx de, alt 16bitlik kısım ise
ax dedir. (dx,ax=ax*bx) 32bit*32bit yani
dword*dword Çarpılacak değerlerden biri
eax ye kaydedilir mov eax,A055FF10
gibi. Daha sonra çarpma işlemi yapılır, mul ebx
gibi. Sonuç ise edx,eax ikilisine aktarılmıştır.
Yani üst 32bitlik kısım edx de, alt 32bitlik
kısım ise eax dedir. (edx,eax=eax,ebx)
DIV : Bölme işlemi için kullanılır. Ayrıntılarına
girmiyorum. INC : Register içeriğini bir
artırır. inc ah gibi DEC
: Register içeriğini bir azaltır. dec cx gibi.
NEG : Sayının ikili tamamlayıcısını bulur. Örneğin
al de 11110000 binary değeri bulunuyor ise neg al
işleminden sonra bu değer 00001111 olur. PUSH :
Stack a yani stack segmente değer göndermek için kullanılır.
push ax gibi. POP :
Stack dan değer çekmek için kullanılır. pop cx
gibi.
Aşağıda assembly komutlarının çoğunun bulunduğu
bir liste mevcuttur. Geliştirilen her yeni komutseti ile bu liste büyümektedir:
A
AAA ASCII Adjust After Addition
AAD ASCII Adjust AX Before Division
AAM ASCII Adjust AX After Multiply
AAS ASCII Adjust AL After Subtraction
ADC Add with Carry
ADD Add
AND Logical AND
ARPL Adjust RPL Field of Segment Selector
B
BOUND Check Array Index Against Bounds
BSF Bit Scan Forward
BSR Bit Scan Reverse
BSWAP Byte Swap
BT Bit Test
BTC Bit Test and Complement
BTR Bit Test and Reset
BTS Bit Test and Set
C
CALL Call Procedure
CBW/CWDE Convert Byte to Word/Convert Word to Doubleword
CDQ Convert Double to Quad
CLC Clear Carry Flag
CLD Clear Direction Flag
CLI Clear Interrupt Flag
CLTS Clear Task-Switched Flag in CR0
CMC Complement Carry Flag
CMOVcc Conditional Move
CMP Compare Two Operands
CMPS/CMPSB/CMPSW/CMPSD Compare String Operands
CMPXCHG Compare and Exchange
CMPXCHG8B Compare and Exchange 8 Bytes
CPUID CPU Identification
CWD/CDQ Convert Word to Doubleword/Convert Doubleword to Quadword
CWDE Convert Word to Doubleword
D
DAA Decimal Adjust AL after Addition
DAS Decimal Adjust AL after Subtraction
DEC Decrement by 1
DIV Unsigned Divide
E
EMMS Empty MMX(TM) Technology State
ENTER Make Stack Frame for Procedure Parameters
F
F2XM1 Compute 2x-1
FABS Absolute Value
FADD/FADDP/FIADD Add
FBLD Load Binary Coded Decimal
FBSTP Store BCD Integer and Pop
FCHS Change Sign
FCLEX/FNCLEX Clear Exceptions
FCMOVcc Floating-Point Conditional Move
FCOM/FCOMP/FCOMPP Compare Real
FCOMI/FCOMIP/ FUCOMI/FUCOMIP Compare Real and Set EFLAGS
FCOS Cosine
FDECSTP Decrement Stack-Top Pointer
FDIV/FDIVP/FIDIV Divide
FDIVR/FDIVRP/FIDIVR Reverse Divide
FFREE Free Floating-Point Register
FICOM/FICOMP Compare Integer
FILD Load Integer
FINCSTP Increment Stack-Top Pointer
FINIT/FNINIT Initialize Floating-Point Unit
FIST/FISTP Store Integer
FLD Load Real
FLD1/FLDL2T/FLDL2E/FLDPI/FLDLG2/FLDLN2/FLDZ Load Constant
FLDCW Load Control Word
FLDENV Load FPU Environment
FMUL/FMULP/FIMUL Multiply
FNOP No Operation
FPATAN Partial Arctangent
FPATAN Partial Archtangent
FPREM1 Partial Remainder
FPTAN Partial Tangent
FRNDINT Round to Integer
FRSTOR Restore FPU State
FSAVE/FNSAVE Store FPU State
FSCALE Scale
FSIN Sine
FSINCOS Sine and Cosine
FSQRT Square Root
FST/FSTP Store Real
FSTCW/FNSTCW Store Control Word
FSTENV/FNSTENV Store FPU Environment
FSTSW/FNSTSW Store Status Word
FSUB/FSUBP/FISUB Subtract
FSUBR/FSUBRP/FISUBR Reverse Subtract
FTST TEST
FUCOM/FUCOMP/FUCOMPP Unordered Compare Real
FWAIT Wait
FXAM Examine
FXCH Exchange Register Contents
FXTRACT Extract Exponent and Significand
FYL2X Compute y * log2x
FYL2XP1 Compute y * log2(x +1)
H
HLT Halt
I
IDIV Signed Divide
IMUL Signed Multiply
IN Input from Port
INC Increment by 1
INS/INSB/INSW/INSD Input from Port to String
INT n/INTO/INT 3 Call to Interrupt Procedure
INVD Invalidate Internal Caches
INVLPG Invalidate TLB Entry
IRET/IRETD Interrupt Return
J
Jcc Jump if Condition Is Met
JMP Jump
L
LAHF Load Status Flags into AH Register
LAR Load Access Rights Byte
LDS/LES/LFS/LGS/LSS Load Far Pointer
LEA Load Effective Address
LEAVE High Level Procedure Exit
LES Load Full Pointer
LFS Load Full Pointer
LGDT/LIDT Load Global/Interrupt Descriptor Table Register
LGS Load Full Pointer
LLDT Load Local Descriptor Table Register
LIDT Load Interrupt Descriptor Table Register
LMSW Load Machine Status Word
LOCK Assert LOCK# Signal Prefix
LODS/LODSB/LODSW/LODSD Load String
LOOP/LOOPcc Loop According to ECX Counter
LSL Load Segment Limit
LSS Load Full Pointer
LTR Load Task Register
M
MOV Move
MOV Move to/from Control Registers
MOV Move to/from Debug Registers
MOVD Move 32 Bits
MOVQ Move 64 Bits
MOVS/MOVSB/MOVSW/MOVSD Move Data from String to String
MOVSX Move with Sign-Extension
MOVZX Move with Zero-Extend
MUL Unsigned Multiply
N
NEG Two's Complement Negation
NOP No Operation
NOT One's Complement Negation
O
OR Logical Inclusive OR
OUT Output to Port
OUTS/OUTSB/OUTSW/OUTSD Output String to Port
P
PACKSSWB/PACKSSDW Pack with Signed Saturation
PACKUSWB Pack with Unsigned Saturation
PADDB/PADDW/PADDD Packed Add
PADDSB/PADDSW Packed Add with Saturation
PADDUSB/PADDUSW Packed Add Unsigned with Saturation
PAND Logical AND
PANDN Logical AND NOT
PCMPEQB/PCMPEQW/PCMPEQD Packed Compare for Equal
PCMPGTB/PCMPGTW/PCMPGTD Packed Compare for Greater Than
PMADDWD Packed Multiply and Add
PMULHW Packed Multiply High
PMULLW Packed Multiply Low
POP Pop a Value from the Stack
POPA/POPAD Pop All General-Purpose Registers
POPF/POPFD Pop Stack into EFLAGS Register
POR Bitwise Logical OR
PSLLW/PSLLD/PSLLQ Packed Shift Left Logical
PSRAW/PSRAD Packed Shift Right Arithmetic
PSRLW/PSRLD/PSRLQ Packed Shift Right Logical
PSUBB/PSUBW/PSUBD Packed Subtract
PSUBSB/PSUBSW Packed Subtract with Saturation
PSUBUSB/PSUBUSW Packed Subtract Unsigned with Saturation
PUNPCKHBW/PUNPCKHWD/PUNPCKHDQ Unpack High Packed Data
PUNPCKLBW/PUNPCKLWD/PUNPCKLDQ Unpack Low Packed Data
PUSH Push Word or Doubleword Onto the Stack
PUSHA/PUSHAD Push All General-Purpose Registers
PUSHF/PUSHFD Push EFLAGS Register onto the Stack
PXOR Logical Exclusive OR
R
RCL/RCR/ROL/ROR Rotate
RDMSR Read from Model Specific Register
RDPMC Read Performance-Monitoring Counters
RDTSC Read Time-Stamp Counter
REP/REPE/REPZ/REPNE /REPNZ Repeat String Operation Prefix
RET Return from Procedure
ROL/ROR Rotate
RSM Resume from System Management Mode
S
SAHF Store AH into Flags
SAL/SAR/SHL/SHR Shift
SBB Integer Subtraction with Borrow
SCAS/SCASB/SCASW/SCASD Scan String
SETcc Set Byte on Condition
SGDT/SIDT Store Global/Interrupt Descriptor Table Register
SHL/SHR Shift Instructions
SHLD Double Precision Shift Left
SHRD Double Precision Shift Right
SIDT Store Interrupt Descriptor Table Register
SLDT Store Local Descriptor Table Register
SMSW Store Machine Status Word
STC Set Carry Flag
STD Set Direction Flag
STI Set Interrupt Flag
STOS/STOSB/STOSW/STOSD Store String
STR Store Task Register
SUB Subtract
T
TEST Logical Compare
U
UD2 Undefined Instruction
V
VERR, VERW Verify a Segment for Reading or Writing
W
WAIT/FWAIT Wait
WBINVD Write Back and Invalidate Cache
WRMSR Write to Model Specific Register
X
XADD Exchange and Add
XCHG Exchange Register/Memory with Register
XLAT/XLATB Table Look-up Translation
XOR Logical Exclusive OR
Easy Assembler Shell v3.99 Copyright(C) 1999 Roman Novgorodov
|