Assembler proqramlaşdırma dili

Proqramın icrasının başa çatması

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 prosedur­lardan 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 proseduruconvert ç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