Proqramın icrasının başa çatması
İstifadəçinin tərtib etdiyi proqramın icrasını başa çatdır-maq və idarəni əməliyyat sisteminə qaytarmaq üçün aşağıdakı imkanlardan istifadə etmək olar:
1. 20h kəsilməsindən;
2. 21h kəsilməsinin 4ch funksiyasından;
3. 27h kəsilməsindən;
4. 21h kəsilməsinin 31h funksiyasından.
1-ci və 2-ci bəndlərdəki kəsilmələr proqramın icrasını dayandıraraq idarəni əməliyyat sisteminə qaytarır və əməliyyat sistemi isə bu proqramın yerləşdiyi sahəni boşaldır. 20h kəsilməsindən *.com genişlənməli proqram-ların icrasını dayandırmaq üçün istifadə olunur. *.com genişlənməli proqramların həcmi 64 kb-dan kiçik olub, əmrlər, verilənlər və stek seqmentləri bir seqmentdə yerləşir. Yəni, bu proqramlarda ASSUME direktivinin yazılışı aşağıdakı kimi olur:
ASSUME CS:A1, DS:A1, SS:A1
21h kəsilməsinin 4 Ch funksiyası istənilən proqramların başa çatmasına imkan yaradır və bu halda dayandırma kodu əməliyyat sisteminə ötürülür ki, buda başqa proqramların analizi üçün istifadə oluna bilər.
27h kəsilməsindən də yalnız .com genişlənməli proqramların dayandırılmasında istifadə edilir. Lakin bu dayandırmadan sonra proqram yaddaşda qalır və proqram əməliyyat sisteminin bir hissəsinə çevrilir. Belə kəsilməsindən adətən rezident proqramların məsələn, ekran drayverlərinin, klaviaturanın və printerin və s. proqram-larında istifalə edilir.
21h kəsilməsinin 31h funksiyasından da rezident proqramlarının başa çatdırılması məqsədi ilə istifadə oluna bilər. Lakin 21h kəsilməsinin 31h funksiyası bu halda həcmi 64 kb-dan çox olan proqramların yaddaşda saxlanmasına imkan yaradır.
Göstərilən kəsilmələrin bəzilərinin tətbiq ilə məsələnin proqramına baxaq. Aşağıdakı proqram, -32767-dən +32767 diapozanındakı tam ədədin klaviaturadan daxil edilməsinə imkan verir, daxil edilmiş sətri ədədə çevirərək ondan 10 çıxır və nəticəni çıxışa verir. Bilirik ki, klaviaturadan daxil edilən simvollar ASCİİ kodlarında olur. Ona görədə onu proqramda ikilik verilənə çevirmək lazım gəlir. Sonra isə çevrilmiş nəticədən 10 çıxılır. Nəticəni displeyin ekranında əks etdirmək üçün o, ASCİİ kodlarına çevrilir və ekrana çıxarılır.
MASM MODEL SMALL .STACK 256 .DATA string DB 7 DUP (?) string1 DB 6 DUP (?) str_len DW 0 result DW 0 mes1 DB ” ədədi daxil et::$” mes2 DB 0Ah,0Dh DB ” səhv: ədəd (modula görə)” DB ”32767 ədədindən kiçik olmalıdır” DB 0Ah,0Dh ,‘$’ Mes3 DB 0Ah,0Dh,”səhv:daşma!”, 0Ah,0Dh, ‘$’ Mes4 DB 0Ah,0Dh “daxil edilən ədəd 10” DB “vahid azaldılmış”,’$’ .CODE ; ƏSAS PROSEDURA main PROC MOV AX, @DATA MOV DS, AX ; ədədi daxil et məlumatının ekrana çıxarılması LEA DX, mes1 MOV AH,9 INT 21h ; sətrlərin daxil edilməsi prosedurun cağırılmısı LEN BX, string1 CALL string_enter ; sətri ədədə çevirən prosedurun cağırılmısı LEN BX, string1 MOV CX, str_len CALL convert ; çevirilmiş (klaviaturadan daxil edilmiş) ;ədədlər üzərində ;hər hansı hesab əməliyyatlarını, məsələn, result yaddaş ; xanasında yerləşən alınmış ədəddən 10 ədədini çıxaq MOV AX,result ; result -> AX SUB AX, 10 ; AX-10 -> AX JNO fox ; daşma haqqında məlumatı ekrana çıxarmaq ; daşma baş vermədikdə fox ünvanına keçid ; əks halda “daşma baş verib” ;məlumatını ekrana çıxarmaq LEA DX, mes3 MOV AH,9 INT 21h JMP exit ; exit nişanına keçid (proqramın sonu) ; conv prosedurası vasitəsi ilə AX registrindəki ədədi ; sətrə çevirib string-ə yazmaq. ; ədədi sətrə çevirən prosedurun çağırılması fox: LEN BX,string CALL conv ;çevirilmiş sətri çıxışa vermək MOV AH,9 LEA DX, mes4 INT 21h LEA DX, string INT 21h ; proqramın sona çatması exit: MOV AH,4Ch INT 21h main ENDP ;sətr simvollarının daxiledilməsi proseduru string_enter PROC ;CX registrində daxil edilən sətrlərin uzunluğu ; saxlanacaq MOV CX,6 ; simvolların sayı CX registrinə göndərilir SUB SI,SI ; SI=0 ; bir simvolun ekranda əks olunmadan daxil edilməsi dig_6: MOV AH,8h ; simvolu AL registrinə ;daxil etməli ; ekranda görünmür INT 21h ; daxil edilən simvol - ? CMP AL,0Dh JE finish ; bərbər isə finish-e keçid CMP AL,’-‘ ; daxil edilən –işarə”-” ? JNE f4 ; bərabər deyilsə f4 keçid CMP SI,0 ; daxil olan ‘-‘ 1-ci simvoldursa, JE save ; save keçid JMP dir_6 :dir_6 –ya şərtiz keçid ;rəqəm daxil edilibmi? -yoxlamaq f4: CMP AL, ‘0’ JL dir_6 ; dir_6 keçid CMP AL, ‘9’ JG dir_6 ; dir_6 keçid CMP SI,0 JNE save ;bərabər deyilsə, save keçid DEC CX ; daxil edilmiş simvolu yaddaşa yazmaq save: MOV [BX][SI], AL ;AL registrindəki ;ədədi BX+ SI ; ünvanına göndərmək onun təsvirini ekrana verir MOV DL,AL MOV AH,2 INT 21h INC SI LOOP dir_6 ; dövrün təkrarı ; daxil edilən sətrlərin uzunluğunun yazılması finish: MOV str_len,SI RET Strig_enter ENDP ;sətrləri ədədə çevirən prosedur convert proc PUSH BX ; sətrləri ədədə çevirən dövrə MOV SI,10 SUB DI,DI AGAIN: MOV AX,DI MUL SI MOV DI,AX SUB AH,AH MOV AL,[BX] CMP AL,’-‘ JE ort SUB AL,30h ADD DL,AX Otr: INC BX LOOP AGAIN ;alınmış ədəd <32767 şətri ilə yoxlanır CMP DL, 32767 JBE norm ; “daha böyük ədədin alıması” haqqıqında məlumatın ; ekrana verilməsi MOV AH,9 LEA DX,mes2 INT 21h JMP exit1 ;əgər mənfi ədəd daxil edilərsə ədədi əlavə koda ; çevirmək norm: SUB SI,SI POP BX CMP BYTE PTR [BX][SI],’-‘ JNE kon NEG DI ;çevirilmiş sətrləri yaddaşa yazmaq kon: MOV result, DI exit l: RET convert ENDP ;ədədi sətrə çevirən prosedur conv proc SUB DI,DI MOV CX,6 ;yoxlama: əgər ədəd mənfidirsə,onda ; onu əlavə koddan düz koda çevirmək OR AX,AX JNS buff MOV DI, 1 DEC CX INC BX NEG AX ;buferi boşluq sətri ilə doldurmaq (bu kənar ; simvolların yaranmasının qarşısını almaq üçün lazımdır) buff: MOV BYTE PTR [BX],’’ INC BX LOOP buff ; buferin (sətrlərin )sonuna ’$’yazmaq MOV BYTE PTR [BX],’$’ MOV SI,10 ; ədədin sətrə çevirilməsi dövri cont: SUB DX,DX DIV SI ADD DX,’0’ DEC BX MOV [BX],DL OR AX,AX JNZ cont ;əgər ədəd mənfidirsə, onda buferə “-”işarəsini daxil etmək CMP DI,1 JNE K1 DEC BX MOV BYTE PTR [BX],’-’ K1: RET Conv ENDP END main
İndi isə proqramın əsas məqamlarını izah edək. Proqramın özü main əsas prosedurundan və bu prosedur tərəfindən çağırılan strig_enter, convert, conv prosedurlardan təşkil olunub.
strig_enter proseduru klaviaturadan (əgər müsbət rəqəmlər olarsa) 5–dən çox olmayan rəqəmləri daxil etməyə imkan verir. Əgər daxil edilən ədəd mənfidirsə, onda birinci daxil ediləcək simvol təbii ki, mənfi işarəsi olacaq. Rəqəmin daxil edilməsini enter düyməsini sıxmaqla başa çatdırmaq olar. Daxil edilən simvolların kodları string1 xanasında saxlanır. Str_len xanasında isə daxil edilən sətrin uzunluğu qeyd olunur.
Sətri ədədə çevirən convert prosedurunun işini izah etməzdən öncə qeyd edək ki, əgər klaviaturadan daxil edilən ədədirsə, onda onlar üzərində hesab əməliyyatları aparmazdan öncə onları ikilik ədədə çevirmək və, əksinə ədədi ekrana və ya printerə çıxarmazdan əvvəl onu ASCII koduna gətirmək lazımdır. Bilirik ki, onluq rəqəmlərin ASCII kodu 30h və 39h diapazonunda dəyişir. Başqa sözlə, onluq rəqəmlərin ikilik ekvivalentinin kiçik dörd biti onun ASCII kodunu təsvir edir. ASCII kodundan ikilik sistemə çevirilmə alqoritmi ümumi halda aşağıdakı kimidir:
1. ədədin böyük rəqəmini ikilik ədədə çevirmək üçün onun ASCII kodunun böyük dörd mərtəbəsini sıfırlaşdırıb, bu ikilik ədədi aralıq nəticə kimi saxlamaq;
2. növbəti rəqəmləri ikilik ədədə çevirmək üçün aralıq nəticəni 10 vurub, alınan hasilə rəqəmin qiymətini əlavə etmək.
Convert prosedurunu çağırmamışdan əvvəl CX registrinə str_len (sətrin uzunluğu) xanasının qiymətini, BX registrinə isə string1 xanasının qiymətini göndərmək lazımdır. Prosedurdan çıxdıqda DI registrindən result xanasına çevirmənin nəticəsi göndərilir.
Ədədi sətrə çevirən conv proseduru, convert çevirmə prosedurunun əksinə olan proseduru yerinə yetirir. Çeviriləcək ədəd AX registrində olur. Alınan sətr (ədəd ASCII kodunda) string xanasına göndərilir.
İndi isə ASCII kodunda yazılmış onluq ədədi ikilik ədədə çevirən prosedura aid bir neçə misala baxaq.
-bu prosedur verilənlər seqmentindəki ASCII simvollar sətrini əks kodda, onun 16- bitlik ikilik ekvivalentinə çevirir;
-sətrin başlanğıc ünvanı BX registrində yerləşdirilir və sətrin başlanğıc ünvanı bu registrindən götürülür:
-simvolların sayı CX registrində saxlanır;
- qayıtma zamanı 16 bitlik qiymət AX registrinə yazılır;
- onluq nöqtədən sonrakı rəqəmlər üçün ədədi sayğac kimi DX registri götürülür;
- birinci çevirilməmiş simvolun ünvanı DL registrində olur;
-əgər sətrdə simvolların sayı 6-dan çox olarsa və ya, ədəd, mümkün qiymətlər diapazondan (32767 böyük və ya –32768 –dan kiçik) kənara çıxarsa və ya sətrdə çevirilməyən simvol olarsa onda CF köçürmə bayrağının qiyməti 1 qəbul olunur. Əgər çevirmə səhvsiz başa çatarsa, CF=0 və DL registrinin məzmunu isə 0FFh olacaqdır;
BX və CX registrlərinin məzmunu dəyişməyəcək
ascii_bin PROC PUSH BX ; BX və CX məzmunu saxlamaq PUSH CX SUB AX,AX ; başlağıc qiymət: nəticə = 0, SUB DX,DX ; onluq nöqtədən sonrakı ; rəqəmlərin sayı = 0 MOV DI,0FFh ; ‘artıq’ (pis) simvol yoxdur CMP CX,7 ; kifayət qədər uzun sətr? JA NO_GOOD ;bəli. CF tənzimləmək və ; dövrdən çıxmaq blanks: CMP BYTE PTR [BX],' ' ; aparıcı probeli buraxmaq JNE chk_neg INC BX LOOP blanks chk_neg: CMP BYTE PTR [VX],'-' ; ədəd mənfidirmi? JNE chk_pos INC BX ; bəli. DEC CX ; sayğacı azaltmaq və CALL conv_ab ; sətri çevirmək JC thru CMP AX,32768 ;ədəd kifayət qədər kiçikdirmi? JA no_good NEG AX ;Yox.nəticənin işarəsinə baxmaq JS good chk_pos: CMP BYTE PTR [BX],'+' ;ədəd müsbətdirmi? JNE go_conv INC BX ;Bəli. BX=BX+1 DEC CX ; sayğacı azaltmaq və go_conv: CALL conv_ab ; sətri çevirmək JC thru CMP AX,32767 ;ədəd böyükdürmü? JA no_good good: CLC JNC thru no_good: STC ;bəli. CF tənzimləmək thru: POP CX ;registrlərin məzmunu bərpa etmək POP BX RET ; və prosedurdan çıxış ascii_bin ENDP ; növbəti prosedur isə xüsusi çevirməni yerinə yetirir conv_ab PROC PUSH BP ;işçi registrlərin məzmunu saxlamaq PUSH BX PUSH SI MOV BP,BX ; göstəricini BP yerləşdirmək SUB BX,BX ; və BX sıfırlaşdırmaq chk_pt: CMP DX,0 ; onluq nöqtə artıq tapılıbmı? JNZ range ;Bəli. Sonrakı yoxlamanı burax CMP BYTE PTR DS:[BP],'.' ;onluq nöqtədirmi? JNE range DEC CX ;Bəli. Sayğacı azalt və MOV DX,CX ; onu DX –də yerləşdir JZ end_conv ; əgər CX=0, çıx INC BP ; BP=BP+1 range:CMP BYTE PTR DS:[BP],'0’ ;əgər simvol ; rəqəm deyilsə... JB non_dig CMP BYTE PTR DS:[BP],'9' JBE digit non_dig: MOV DI,BP ; onda onun ünvanını DI yerləşdir STC ; köçürmə bayrağını tənzimlə və JC end_conv ; prosedurdan çıx digit: MOV SI,10 ; simvol-rəqəm, PUSH DX MUL SI ; onun üçün də AX- nu 10 vur, POP DX MOV BL,DS:[BP] ; ASCII-kodunu çıxarmaq, AND BX,0Fh ; ancaq onun kiçik bitlərin saxlamaq ADD AX,BX ; və xüsusi nəticə ilə tamamla JC end_conv ; əgər, çox böyükdürsə çıx INC BP ; əgər, yox, göstəricini artır LOOP chk_pt ; və davam et CLC ; əgər dövr başa çatıbsa, CF sıfırlaşdır end_conv: POP SI ; registrlərin qiymətini bərpa et POP BX POP BP RET ; ilə çağırılan prosedura qayıt conv_ab ENDP
Növbəti prosedur da conv prosuduru kimi ikilik ədədi ASCII- kodlar sətrinə çevirir. Bu prosedurdan nəticəni ekrana və ya printerə çıxarmazdan əvvəl istifadə etmək olar. Prosedurla işləyərkən aşağıdakıları nəzərə almaq lazımdır:
- prosedur verilənlər seqmentində yerləşən 6 baytlıq işarə ilə birlikdə (işarə üstəgəl 5 rəqəm) ikilik ədədi ASCII- sətrinə çevirir.
-çeviriləcək ədəd AX registrindən, yaddaşda buferin başlanğıc ünvanı isə BX registrindən götürülür.
-qayıtma zamanı BX registrində çeviriləcək çıxış sətrinin ünvanı, CX registrində isə sətrlərin uzunluğu olur.
-başqa registrlər isə qiymətini saxlanır.
Bin_ascii PROC PUSH DX ;istifadə olunan regitsrlərin məz.saxlamaq PUSH SI PUSH AX ; ikilik qiyməti saxlamaq MOV CX,6 ; buferi probellə doldurmaq Fill_buff: MOV BYTE PTR [BX], ‘ ‘ INC BX LOOP fill_buff MOV BYTE PTR [BX], ‘$ ‘ MOV SI,10 ; 10 –a bölməyə hazırlıq OR AX,AX ; əgər qiymət mənfidirsə, JNS clr_dvd NEG AX ; onun işarəsini dəyişdirmək clr_dvd:SUB DX,DX ; bölünənin böyük yarısını ; sıfırlaşdırmaq DIV SI ; ( AX) –nunu 10 bölmək ADD DX,’0’ ; qalığı ASCII- rəqəmə çevirmək DEC BX MOV [BX],DL ; bu simvolu sətrə daxil etmək INC CX ; çevirilmiş simvolları hesablamaq OR AX,AX ; bütün simvollara baxılıbmı? JNZ clr_dvd ;yox. Növbəti simvolu götürmək POP AX ;hə. Cari qiyməti götürmək OR AX,AX ; o mənfidirmi? JNS no_more DEC BX ; hə. İşarəni sətrə daxil et MOV BYTE PTR [BX], ‘-‘ INC CX ; və simvollar sayğacını artır no_more: POP SI POP DX RET Bin_ascii ENDP