پیوند و اجرای اسمبلی

saalek110

Well-Known Member
انگار تكه آخر برنامه را توضيح نداديم. اين قسمت را:

mov cx,100 ; length of string
mov si,OFFSET Buffer ; DS:SI - address of string
xor bh,bh ; video page - 0
mov ah,0Eh ; function 0Eh - write character

NextChar:

lodsb ; AL = next character in string
int 10h ; call BIOS service
loop NextChar

به شرح سرويس 0E از وقفه 10 كه از آموزشهاي اموليتور نقل مي كنم توجه كنيد:
کد:
INT 10h / AH = 0Eh - teletype output.


input:
AL = character to write. 
This functions displays a character on the screen,
 advancing the cursor and scrolling the screen as necessary.
 The printing is always done to current active page.

اين سرويس خروجي تله تايپ مي دهد.
اين سرويس چاپ مي كند و بعد كرزر را جلو مي برد و در صورت نياز صفحه را اسكرول مي كند . و در صفحه جاري مي نويسد.

و اينجا:
xor bh,bh ; video page – 0
آمده ايم با xor كردن ، bh را صفر كرده ايم. (تنظيم صفحه جاري.)
در :
mov cx,100 ; length of string
آمده ايم cx را تنظيم كرده ايم تا در لوپ استفاده شود.
اين خط هم:
mov si,OFFSET Buffer ; DS:SI - address of string
احتمالا براي استفاده lodsb است. اين كه مي گويم احتمالا چون من تا نروم با lodsb يك برنامه نسازم مطمئن نمي شوم. ولي همينه به احتمال زياد.
خلاصه تكه برنامه :

mov cx,100 ; length of string
mov si,OFFSET Buffer ; DS:SI - address of string
xor bh,bh ; video page - 0
mov ah,0Eh ; function 0Eh - write character

NextChar:

lodsb ; AL = next character in string
int 10h ; call BIOS service
loop NextChar

اين ميشه كه از قطعه داده در al بار ميشه با lodsb و بعد سرويس 0E از وقفه 10 مي آيد محتواي al را چاپ مي كند. و حلقه هم كارش اين است كه كار بار شدن و چاپ را 100 بار تكرار كند.
 
آخرین ویرایش:

saalek110

Well-Known Member
از صفحه 5 باز مانده كه ايجاد فايل – جستجوي فايل و غيره است كه فعلا حسش نيست بگم.
== = = = = = ==
اما راجع به پرشهاي شرطي عكس زير كه مقايسه بعضي پرشهاي شرطي با همتاي زبان سي است را مي گذارم كه فكر كنم جالب باشه.


2ebqvsi.gif


اين هم يك مثال از jnz :
کد:
MOV CX, 20            ;We will execute COUNT_LOOP 20 times
 COUNT_LOOP:          ;Main entry point for loop
    DEC CX            ;Subtract 1 from CX
    JNZ COUNT_LOOP    ;If CX is zero, continue on to
                      ;next code, otherwise JMP back to COUNT_LOOP

يعني وقتي cx صفر بشه ديگه پرش انجام نميشه.
= = = = = == ==
اين هم يك مثال از jz :
کد:
MOV AX, 0010B ;move the decimal value '2' into the AX register
 MOV CX, 0001B ;mov the decimal value '1' into the CX register
 CMP AX, CX    ;Compare AX and CX by subtracting the contents of CX from AX
  JZ Was_zero  ;Jumpt to Was_zero label if result from CMP was ZERO
 ....          
 ....          ;Code to implement if Values were not equal

در كد بالا ،وقتي نتيجه تفريق(تفريق انجام نميشه با cmp ، فقط فلاگها تنظيم مي شوند. تفريق واقعي همان sub است. ) صفر باشد پرش مي كند.
 

saalek110

Well-Known Member
ليست وقفه ها :
در اين سايت :
http://www.cs.cmu.edu/afs/cs/user/ralf/pub/WWW/files.html

همان بالاي صفحه يك سري فايل براي دانلود هست كه من اولي را دانلود كردم.

اما با ديدن محتواي اين فايل كه پسوند هاي غيرمعمولي داشتند و با word و اديتور كدوايز توانستم باز كنم ، بايد بگم كه،

نه توصيه به دانلود مي كنم نه پرهيز از دانلود.

اگر مجموعه اي مي خواهيد و مي خواهيد كارهاي تحقيقي كنيد(عشق به اسمبلي – اعصاب و ...) ......
ولي اگر وقت نداريد و حوصله كم داريد.....
 

saalek110

Well-Known Member
اگر مي خواهيد برنامه اي داشته باشيد كه كليدي را از كيبورد بگيرد و ضمن نمايش آن حرف بر صفحه كد آن را هم در al بريزد، از برنامه زير استفاده كنيد.
کد:
.model small
.stack 
.data 
.code 
asli proc
;------------------
mov ah, 1
int 21h
;------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli
برنامه بالا را من امتحان كردم. قبل اجراي وقفه و بعد آن آمدم al را چاپ كردم كه الو صفر بود بعد شد كد كاراكتر زده شده.
وقتي كليدي را بزنيم و آن كليد چاپ شود بر صفحه ، مي گوييم داراي اكو است.

اگر همين كار يعني گرفتن و ذخيره در al را بدون اكو مي خواهيد از سرويس 7 به جاي سروي 1 استفاده كنيد.
mov ah, 7


راهنماي آن:
کد:
INT 21h / AH=1 - read character from standard input,
 with echo, result is stored in AL.
if there is no character in the keyboard buffer, 
the function waits until any key is pressed. 

example: 


mov ah, 1
int 21h

قبلا من يك برنامه حلقه تو در تو ساختم تا وقفه زماني ايجاد كنم ولي وقفه اي هست كه تاخير ايجاد مي كند و راهنماي آن را در زير مي آورم. البته شايد وقفه هاي ديگري نيز براي اين كار باشد.
نكته : اين وقفه در ويندوز xp عمل نمي كند.
کد:
INT 15h / AH = 86h - BIOS wait function. 
input:

CX:DX = interval in microseconds 
return:

CF clear if successful (wait interval elapsed),
CF set on error or when wait function is already in progress. 

Note: 
the resolution of the wait period is 977 microseconds
 on many systems (1 million microseconds - 1 second). 
Windows XP does not support this interrupt (always sets CF=1).
اگر cf به يك تغيير كند به معني شكست كه در ويندوز ايكس پي بايد چنين شود.
همين طور كه در زير مي بينيد:
INT 15h / AH = 86h - BIOS wait function.
input:

CX:DX = interval in microseconds
شماره سرويس آمده و اين كه زمان دلخواه را بايد در چه رجيسترهايي بريزيم.
 
آخرین ویرایش:

saalek110

Well-Known Member
كار با ماوس:
وقفه 33 براي اين كار به كار مي رود.
براي استفاده از ماوس اول بايد راهش انداخت:
mov ax, 0 ; initilize mouse
int 33h

mov ax, 1 ; show mouse
int 33h
در دو سرويس بالا ، اولي اينيتيالايز و دومي show ماوس است. من امتحان كردم . يكي هم كه كم باشه ماوس نشان داده نمي شود.
به برنامه زير دقت كنيد:
کد:
.model small
.stack 
.data 
.code 
asli proc
;------------------
mov ax, 0 ; initilize mouse
int 33h

mov ax, 1 ; show mouse
int 33h
;-------- wait ----------------
MOV AH,00H 
INT 16H 
;-------------------------------
mov ax, 2  ;makhfi kardane(hide) moushe
int 33h
;------------------
;-------- wait ----------------
MOV AH,00H 
INT 16H 
;-------------------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli

در اين برنامه ابتدا ماوس اينيتيالايز و show شده.
بعد من با دو خط كد حالت انتظار در برنامه بوجود آورده ام براي گرفتن كليدي.
و با زدن كليد مي رود به دو خط بعدي. يعني:
mov ax,4c00h ; return to dos DOS
int 21h
اين دو خط ماوس را hide ، يعني مخفي مي كند. اگر اين دو خط نباشد بعد اختتام برنامه هم باز ماوس وجود خواهد داشت.
من يك wait هم بعد خاموشي ماوس گذاشته ام در كد بالا ، تا خاموشي ماوس را ببينيد.

نكته: در حالت full screen بايد ماوس را ببينيد. با همين نام دكمه اي روي تولبار پرومپت داس خود داريد كه آن را بزنيد.

= == = = = = == = = =
نكات ماوس:
اول راهنماي اينيتيالايز:
کد:
INT 33h / AX=0000 - mouse ininialization. any previous mouse pointer is hidden. 

returns: 
if successful: AX=0FFFFh and BX=number of mouse buttons.
if failed: AX=0

با موفقيت آميز بودن ax مساوي 0ffff و bx مساوي تعداد دكمه هاي ماوس مي شود. و در صورت شكست ax صفر مي شود. من امتحان كردم به من ffff داد ax را و عدد 2 براي bx . ماوس من دو دكمه چپ كليك و راست كليك دارد. شايد براي اين است. وسط كليك ندارد.
= = =
سرويس show و hide راهنما ندارد.

در برنامه بالا ، سرويس هاي صفر و يك و دو استفاده شده بود براي اينيتيالايز و show و hide .
سرويس ديگري داريم با شماره 3 .
راهنما:
کد:
INT 33h / AX=0003 - get mouse position and status of its buttons. 

returns: 
if left button is down: BX=1
if right button is down: BX=2
if both buttons are down: BX=3
CX = x
DX = y 
example: 

mov ax, 3
int 33h

; note: in graphical 320x200 mode the value of CX is doubled.

مي دانيد كه برنامه قبلي ما كار خاصي انجام نمي داد. چون فقط روشن و خاموش مي كرد ماوس را. اصل قضيه همين سرويس 3 است. حالا چه برنامه اي بنويسيم تا اين را بكار ببريم؟!
يك حلقه خوبه نه؟ كه مدام مختصات ماوس را نشان دهد.
در راهنماي بالا مي بينيد كه مختصات ماوس در cx و dx ريخته مي شود. پس من در زير برنامه اي مي گذارم كه در حلقه اي مدام cx و dx را چاپ كند:
کد:
.model small
.stack 
.data 
.code 
asli proc
;------------------
mov ax, 0 ; initilize mouse
int 33h

mov ax, 1 ; show mouse
int 33h
;========= halgheh =================
lable_first:
;---------service 3
mov ax, 3
int 33h
;---------curser be avale safeh
push dx
mov dh,0  ;DH = row. 
mov dl,0  ;DL = column.
mov bh,0
mov ah,2  ;service
int 10h
pop dx
;------------------------------

mov bl,ch
call bl_print
mov bl,cl
call bl_print 

mov bl,dh
call bl_print
mov bl,dl
call bl_print

jmp lable_first
;=================================
mov ax, 2  ;makhfi kardane(hide) moushe
int 33h
;------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
; ============ sub bl_print ===========
bl_print PROC NEAR
push ax
push bx
push cx
push dx
;----------part 1
mov ah,2h
mov dl,bl  

mov cl,04h
shr dl,cl

add dl,30h

cmp dl,3ah
jl lable1

add dl,07h

lable1:
int 21h

; -----------part 2

mov dl,bl
and dl,0fh

add dl,30h

cmp dl,3ah
jl lable2

add dl,07h

lable2:
int 21h
;------------
pop dx
pop cx
pop bx
pop ax

ret ; return to where it was called
bl_print ENDP
;================================

     end asli

شرح برنامه:
يك حلقه با دستور jmp يعني جامپ ساخته شده كه با خطهايي كه با مساوي كشيده ام ، محدوده حلقه مشخص شده. قبل حلقه هم كه ماوس قبلا روشن شده بود.
اما ، داخل حلقه ، اول ليبل است كه جامپ به آنجا انجام مي شود. بعد سرويس 3 از وقفه 33 را داريم. و بعد هم 7 خطي كه كرزر را به اول صفحه مي برد. مي توانيد اين 7 خط را حذف كنيد ولي با اين كار اعداد همين طور به پايين مي روند و منظره خوبي ندارد.
بعد اين 7 خط هم من با صدا كردن bl_print آمده ام cx و dx را چاپ كرده ام.

كار قشنگ تر اينه كه cx و dx را چاپ نكنيم. بلكه در مكان موس كاري چاپي انجام بشود كه خودتان برنامه اش را بسازيد.
آخرين خط داخل حلقه هم همان دستور جامپ است.
== = == = =
بايد برنامه اي هم بنويسيد براي دريافت bx براي تست اين قسمت:
if left button is down: BX=1
if right button is down: BX=2
if both buttons are down: BX=3
براي اين كار به جاي اين قسمت در برنامه بالا:
;---------curser be avale safeh
push dx
mov dh,0 ;DH = row.
mov dl,0 ;DL = column.
mov bh,0
mov ah,2 ;service
int 10h
pop dx
;------------------------------

mov bl,ch
call bl_print
mov bl,cl
call bl_print

mov bl,dh
call bl_print
mov bl,dl
call bl_print
اين قسمت را جايگزين كنيد:
;---------curser be avale safeh
push bx
mov dh,0 ;DH = row.
mov dl,0 ;DL = column.
mov bh,0
mov ah,2 ;service
int 10h
pop bx
;------------------------------

push bx
mov bl,bh
call bl_print
pop bx
call bl_print

با اين جايگزيني ، باعث چاپ bx مي شويد و با كليك چپ عدد ((يك)) و با كليك راست عدد ((دو)) چاپ مي شود.

اما در قسمت جايگزين شده دقت كنيد كه اطراف آن 7 خط انتقال كرزر قبل جايگزيني من dx را push كردم و بعد جايگزيني bx را push كردم . چون در برنامه اول ما مي خواستيم dx را چاپ كنيم ولي در برنامه دوم مي خواستيم bx را چاپ كنيم.

در قسمت جايگزين شده به اين خط ها نگاه كنيد:
push bx
mov bl,bh
call bl_print
pop bx
call bl_print
در خط :
mov bl,bh
مي بينيد كه bl دارد نابود مي شود ، در صورتي كه بايد در خطهاي بعدي چاپ شود. پس قبل نابودي اش من آنرا push كرده ام تا مصون بماند. و بعد pop مستقيما آمده ام bl_print را احضار كرده ام چون ديگه نياز نيست كه bl را روي bl بريزم.

نكته: در مود كاراكتري موس به شكل مستطيل است و در مود گرافيكي به شكل رايج موس يعني فلش مانند.
همچنين در اين پست در راهنماها به تغيير اندازه اي در مود گرافيكي اشاره شده كه به آن توجه كنيد.

; note: in graphical 320x200 mode the value of CX is doubled.
 
آخرین ویرایش:

simona

New Member
جا داره همین جا یکی از کاربردهای زبان اسمبلی را بگم. البته ممکنه که قبلا" آقا سالک مطرح کرده باشن.پس اگه تکراری بود بگذارید به حساب مهم بودن موضوع.:D
می توان از کدهای زبان اسمبلی در زبان های سطح بالایی مثل Cو پاسکال به کار برد.
حالا شاید بعضی ها بگن چه کاریه؟به جای نوشتن کدهای زیاد اسمبلی مثلا" برای محاسبه یک عبارت از یک کد در زبان C استفاده می کنیم.
در جواب باید گفت بعضی پروزه ها open source هستند ولی ما نمی خواهیم دیگران به راحتی به برنامه ی ما دسترسی داشته باشند . خوب با استفاده از کدهای اسمبلی و کمی برنامه های بازگشتی می توان برنامه را به اصطلاح پیچوند.
حتی در مسابقات رباتیک که اخیرا" در تهران برگذار شد, بعضی از تیم ها از زبان اسمبلی استفاده کرده بودند.
این بود یکی از دلایل علاقه مندی من به اسمبلی.
پس چه خوبه که این زبان رو یاد بگیریم و هی نگیم فسیل شده.
 

simona

New Member
ورودی و خروجی اعداد
برای ورود اعداد , باید عددی را که به صورت رشته وارد شده است به عدد تبدیل کنیم.
ولی متاسفانه من در نوشتن کدش مشکل دارم :cry: :
کد:
.model small
.stack 64
.data
msg1 db "please enter first num",'$'

str label byte
max db 20
len db ?
buffer db 20 dup (' ')
dolar db '$'
.code
  main proc far
    mov ax,@data
    mov ds,ax
 ;--------------
lea ax,msg1
mov ah,9h  ;chape payam1
int 21h
 ;--------------
mov ah,0ah
lea dx,str ;khandane reshte
int 21h
;--------------
lea bx,buffer
mov ax,0
mov si,0 ; shomarande

l1:   ;tabdile reshte be addad
 
   cmp [bx],'$'
   jz  l2
   mov cx,10
   mul cx
   mov cl,[bx]
   sub cx,'0'
   add ax,cx
   inc si
   inc bx
   jmp l1
 
l2:    

   mov ax,4c00h
   int 21h
      main endp
          end main
اسمبلر هیچ خطایی نمی گیرد .ولی در صفحه ی خروجی پیام ها و علامت های نامربوط چاپ می شود.
می شه لطفا" اشکال برنامه ای که نوشتم را بگید.
 

simona

New Member
مسئله به این صورت است که 2 عدد مثبت 8 بیتی را از ورودی می گیرد و ب.م.م آن دو را با ذکر روش به دست می آورد.یعنی به هر عددی که در خلال برنامه رسیدیم چاپ می کنیم.
حالا من خواستم برنامه را به این طریق خرد کنم تا راحتر حل شود.
در اسمبلی برای ورود عدد باید آن را به صورت رشته بگیریم بعد تبدیل به عددش کنیم.
در زبان C برای این تبدیل این کار را می کردیم:
کد:
int atoi(char*str)
{
int x=0,i=0;
while(str[i]!='0')
x=x+(str[i]-'0');
x=x*10;
i++;
{
return x;
}

حالا برای عدد به رشته:
کد:
char*itoa(int num)
{
char str=new char[6]={' '};
stack s[5];
int 1=0;
while(num!=0)
{
s.push (num%10)+'0');
num/=10;
}
while(!s.isempty())
str[i++]=s.pop;
return str;
}
این جوری
 

simona

New Member
این هم برنامه ای که ب.م.م دو عدد را حساب می کند.
کد:
.model small
.stack 64
.data
   num1 label byte
   max1 db 5
   len1 db ?
   buffer1 db 5 dup('0')
   dollar1 db '$'

   num2  label byte
   max2 db 5
   len2 db ?
   buffer2 db 5 dup('0')
   dollar2 db '$'

   enter1 db 'Enter first number: ',"$"
   enter2 db 'Enter second number: ',"$"
   str db 'number1:number2:remainder',"$"
   r db ':is bmm',"$"
  
   remain dw ?
   char db ?
   count1 db 0
   count2 db 1
   n1 dw ?
   n2 dw ?
;-------------------------------------------------------------------------------------end data
.code
main proc far
      mov dx,@data
      mov ds,dx

      ;clear screen
      mov ah,6h
      mov al,25
      mov ch,0
      mov cl,0
      mov dh,24
      mov dl,79
      mov bh,7
      int 10h
 
; cursor position(1,1)---------------------------------------------
      mov ah,2h
      mov dh,1
      mov dl,1
      mov bh,0
      int 10h

      ; print message
      mov ah,9h
      lea dx,enter1
      int 21h

      ;Enter first number
      mov ah,0ah
      lea dx,num1
      int 21h

      lea bx,buffer1	 ; place first number in n1-----------------------
      mov ax,0
chartonum1:
       cmp byte ptr [bx],'0'
       jl number1
       cmp byte ptr [bx],'9'
       jg number1
       mov cx,10
       mul cx
       mov cl,[bx]
       and cx,000fh
       add ax,cx
       inc count1
       inc bx
       jmp chartonum1 
number1:
      mov n1,ax 

;cursor position (2,1)----------------------------------------------
      mov ah,2h
      mov dh,2
      mov dl,1
      mov bh,0
      int 10h

      ; print message
      mov ah,9h
      lea dx,enter2
      int 21h

      ;Enter second number
      mov ah,0ah
      lea dx,num2
      int 21h
 
      lea bx,buffer2       ;place second number in n2-----------------------
      mov count1,0 
      mov ax,0
chartonum2:
       cmp byte ptr [bx],'0'
       jl number2
       cmp byte ptr [bx],'9'
       jg number2
       mov cx,10
       mul cx
       mov cl,[bx]
       and cx,000fh
       add ax,cx
       inc count1
       inc bx
       jmp chartonum2 
number2:
      mov n2,ax 

      
     ;print message:

;cursor position (3,1)----------------------------------------------
      mov ah,2h
      mov dh,3
      mov dl,1
      mov bh,0
      int 10h

      ; print message
      mov ah,9h
      lea dx,str
      int 21h

 ;-------------------------calculation-----------------------------------


  ;print the result of this level..................................
	  
           mov count1,4
     ;print n1 in its position:
           mov bx,n1
           mov si,0
           mov di,3
   while1:
           dec di
           cmp dx,0
           jz loop3
     loop1:
           
           cmp  bx,0   
           je loop2     
          
           ;else:

                   ;si is loop1 counter         
           mov ax,bx
           mov dx,0
            inc si
           mov cx,10
           div cx
           push dx

           mov bx,ax
         
           jmp loop1

     loop2:
           cmp si,0         ;if si==0 it means the number to print is 0 
           jz loop4         ; so: go to loop3 to print 0
           mov ah,0  
           pop ax
           add ax,30h
           mov char,al
       ;print char.....................
           inc count2
           ;mov cursor
           mov ah,2h
           mov dh,count1
           mov dl,count2
           mov bl,0
           int 10h
           
           mov dl,char
           mov ah,2h
           int 21h
          
           dec si
           cmp si,0
           jne loop2
           
           cmp si,0
           jz loop4
              
         
      loop3:
             ;mov cursor
           mov ah,2h
           mov dh,count1
           mov dl,1
           mov bl,0
           int 10h
           
           mov char,0
           mov dl,char
           mov ah,2h
           int 21h


     loop4:      ;calculate bmm-------------------------------

  
        mov bx,n2
        mov count2,10
        cmp di,2
        je while1

        mov bx,remain
        mov count2,17
        cmp di,1
        je while1
       
      	 
           inc count1
           mov count2,1
           mov si,0
           mov di,3
           mov dx,0 
           mov ax,n1
	   div n2  
           mov ax,n2    
	   mov n1,ax 
           mov n2,dx      ;; find b.m.m
           mov remain,dx   
           mov bx,n1
            cmp n2,0
           jz result
  
          

        mov bx,n1
        mov count2,1
        cmp di,3
        je while1

    
        mov bx,n2
        mov count2,10
        cmp di,2
        je while1

    result:       
       mov bx,n1
     f1:
           
           cmp  bx,0   
           je f2     
          
           ;else:

                   ;si is loop1 counter         
           mov ax,bx
           mov dx,0
            inc si
           mov cx,10
           div cx
           push dx

           mov bx,ax
         
           jmp f1

     f2:
           cmp si,0          
           jz done         
           mov ah,0  
           pop ax
           add ax,30h
           mov char,al
       ;print char.....................
           inc count2
           ;mov cursor
           mov ah,2h
           mov dh,count1
           mov dl,count2
           mov bl,0
           int 10h
           
           mov dl,char
           mov ah,2h
           int 21h
          
           dec si
           cmp si,0
           jne f2
           
           cmp si,0
           jz done
              
           
    done:    

         add count2,4
             ;mov cursor
           mov ah,2h
           mov dh,count1
           mov dl,count2
           mov bl,0
           int 10h
           
          ; print message
          mov ah,9h
          lea dx,r
          int 21h

MOV AH,00H 
INT 16H 

  
      mov ax,4c00h
      int 21h
main endp
      end main
البته این برنامه یکی از دوستانم نوشتند .من فقط آخر برنامه را اضافه کردم.
 

saalek110

Well-Known Member
این برنامه نوعی تمرین بر مباحث قبلی است. کار این برنامه چاپ یک رجیستر در مبنای 2 است.
کد:
.model small
.stack 
.data 
.code 
asli proc
;------------------------------------
mov bl,6

mov ah,2
mov cx,8
my_lable:
mov dl,0
rcl bl,1
adc dl,30h
int 21h
loop my_lable
; -------- key --------------
xor ax,ax ; function 00h - get a key
int 16h ; call BIOS service
; ---------------------------
;-------------------------------------
mov ax,4c00h ; return to dos DOS 
int 21h 

asli endp
     end asli
برنامه را بین دو خط افقی محصور کردم تا با قالب برنامه که شما می توانید قالب دلخواه خود را جایگزین کنید مخلوط نشود.
یک تکه هم که باز با خط افقی محصور شده و با کلمه key عنوان داده شده همان طور که در برنامه های قبلی هم بکار بردیم برای این است که بعد چاپ نتایج برنامه از حالت اجرا خارج نشود تا ما بتوانیم نتیجه اجرا را ببینیم. تا کلیدی زده نشود برنامه به پایان نمی رسد.

شرح برنامه:
در خط اول یعنی
mov bl,6
به bl مقدار اولیه داده ایم. عدد 6 یعنی که بیت دوم و سوم عدد از سمت راست باید 1 باشد و بقیه صفر باشد. برای سادگی این عدد را انتخاب کرده ام. البته با اعداد دیگر هم امتحان کرده ام من ولی با اجرای برنامه بالا باید به:
00000110
برسید.
یعنی همان 6 در مبنای 2 . اگر می خواهید همه یک شوند باید به bl مقدار0ffh بدهید. می دانید که اگر عددی با حرف شروع شود یک صفر قبل آن باید گذاشت.

خط دوم یعنی
mov ah,2
که می دانید آمادگی چاپ است برای وقفه
int 21h

بقیه برنامه را کلی توضیح می دهم چون همه به هم مربوط است.
ما می آییم bl را با دستور rcl چرخش می دهیم. دستور چرخش با دستور شیفت که قبلا در این تاپیک استفاده کردیم فرق دارد. در چرخش عدد از آن طرف دوباره به خود برمیگردد. شما اینجا بیتهای bl که 8 تا است (و به همین دلیل cx که تعداد چرخش حلقه است 8 تنظیم شده) و بیت فلاگ نقل را با هم در نظر بگیرید.
یک چرخش بین این 9 بیت در جریان است. یعنی هر بیت اول به فلاگ نقل می رود و بعد از آن طرف دوباره وارد bl می شود. و وقتی محتوای بیت داخل فلاگ نقلی است فرصت خوبی است تا آن را چاپ کنیم. فکر کنم دستورات دیگر هم باشد که چرخش بدهد ولی داخل فلاگ نقلی نیاندازد ولی برای ما در اینجا رفتن به فلاگ نقل یک فرصت است.
دستور adc قبلا هم شرح داده شده در این تاپیک. ولی باز می گویم . کارش این است که دو عدد را جمع می کند و همزمان با جمع دو عدد می آید فلاگ نقل را هم جمع می زند. ما آمده ایم با 30h جمع زده ایم تا موقع چاپ ((صفر یا یک )) چاپ شود. قبلا در برنامه bl_print شرح دادیم که فلسفه این عدد 30h چیست.
فکر کنم توضیح کافی باشد. با تغییر دادن برنامه می توانید بیشتر بفهمید که کار هر دستور چیست.
 
آخرین ویرایش:

simona

New Member
اشکال در کشیدن مستطیل

سلام
کد زیر برنامه ای برای کشیدن مستطیل است ولی اجرا نمی شه :cry: . اگه ممکنه اشکال برنامه را به من بگید.
کد:
.model small
.stack 256
.code
;______________________
rec proc
push bp
mov bp,sp
mov cx,[bp+10] ;y1
mov bh,0
mov ax,[bp+4];color
l4:
   cmp cx,[bp+6];y2
   jz l1
   mov dx,[bp+12];x1
   l3:
       cmp dx,[bp+8];x2
       jz l2
       mov ah,0ch
       int 10h
       inc dx
       jmp l3
       l2:
          inc cx
          jmp l4
          l1: 
             pop bp
             ret 10
 rec endp
;________________________
 main proc far
 mov ax,@data
 mov ds,ax
 mov ax,15;x1
 push ax
 mov ax,15;y1
 push ax
 
mov ax,30;x2
push ax
mov ax,30;y2
push ax
mov ah,00h
mov al,12h
int 10h
mov ah,0
push ax

call rec
mov ax,4c00h
int 21h
main endp
  end main
 

simona

New Member
لطفا" یک نفر کمک کنه. برنامه ی اصلی کشیدن صفحه شطرنج است. حالا من در کشیدن یک مستطیل مشکل دارم.
 

saalek110

Well-Known Member
شما از پشته برای انتقال اطلاعات به تابع استفاده کرده اید. یعنی سخت ترین راه. البته سختی آن مهم نیست ولی به نظر من استفاده از آن اینجا مناسب نیست چون تابع شما عناصر را از پشته برنمی دارد و بعد برگشت از تابع باید خودتان در برنامه اصلی این کار را کنید.

یعنی کار 3 مرحله می شود:
اول قرار دادن مقادیر در پشته.
فراخوانی تابع.
خالی کردن آنچه در پشته قرار داده ایم(خالی کردن بعد برگشت از تابع در برنامه اصلی).

ولی به نظر من از دو راه دیگر یعنی ((انتقال با رجیستر)) و (( انتقال با متغیر(از حافظه) )) روش انتقال از راه متغیر اینجا بهتر است.

چون که شما به راحتی با داشتن 4 متغیر می توانید داده ها را به تابع منتقل کنید. و بعد فراخوانی تابع هم دیگه خالی کردن پشته نداریم. چون این متغیرها بعدا برای کشیدن شکل های دیگر استفاده می شوند. کلا خوانایی برنامه فکر کنم بالاتر بشه. چون ما می دانیم این متغیرها کارشان چیست و راحت از آنها استفاده می کنیم.
ولی در فراخوانی با پشته به دردسری بیشتری می افتیم.
من فکر می کنم اگر مثل زبان سی بشه احضار تابع خیلی بهتره. یعنی فقط بعد مقدار دادن به متغیرها تنها کاری که ما می کنیم ((فراخوانایی تابع )) است. ولی در روش ارسال توسط پشته دیگه مثل زبانهای سطح بالا نیست و یک کار اضافه یعنی خالی کردن پشته را هم داریم.

=============
حالا 3 راه وجود دارد:

یکی اینکه شما برنامه را به همین شکل فعلی حفظ کنید و بعد هر فراخوانی تابع باید پشته را در برنامه اصلی خالی کنید.
راه دوم اینکه تابع خود را طوری بسازید که خودش پشته را خالی کند.
راه سوم اینکه با همان روش فراخوانی با روش ارسال توسط متغیر (یا حتی روش ارسال توسط رجیستر) برنامه را بنویسید.

یکی از روشها را انتخاب کنید.

================================
در راستای پیشنهاد دوم از سه راه بالا من برنامه زیر را ساختم:
اولا بگم که این روش همین امروز به ذهنم رسید و از جایی نخواندم. کار می کنه ولی نمی دانم بعدها مشکلاتی ایجاد کنه یا نه.
فلسفه این روش بر این دانش استوار است که در اسمبلی آدرس برگشت از زیر برنامه در پشته نگه داری میشه.
پس وقتی ما وارد زیربرنامه می شویم رویی ترین چیز همان آدرس برگشت است. من آن را برداشتم و در رجیستری ذخیره کردم. حالا پشته حاوی اطلاعاتی است که برنامه اصلی ارسال کرده به زیربرنامه. و می توانیم برداشت را شروع کنیم. چون من در برنامه اصلی فقط ax را ارسال کردم حالا پس اجازه دارم که فقط یک برداشت کنم. بعد این یک برداشت من آدرس برگشت را دوباره در پشته قرار داده ام.
خلاصه کار من این بود که رویه پشته که مانع برداشت اصلاعات ارسالی از تابع main بود را کنار زدم و اطلاعات ارسالی را برداشتم و بعد رویه را سرجایش قرار دادم. مثل برداشتن در ظرفی و برداشتن چیزی از داخل ظرف و مجددا در ظرف را گذاشتن.

برنامه bl_print را هم فقط جهت چک کار گذاشته ام تا ببینم واقعا اطلاعاتی که در زیربرنامه برداشته ام همانهایی است که از طرف برنامه اصلی ارسال شده یا نه که درست بود.
برای اطمینان در زیربرنامه مقدار برداشتی را در cx ریختم و cx را چاپ کردم. اگر در ax باز می ریختم شاید شک پیش می آمد که این همان ax ئی است که در برنامه اصلی تنظیم شده.
کد:
.model tiny 
.code
org 100h

Start: 
mov ax,8473h
push  ax         ; put number into the stack 

call PrintString ; print our string

;-------- wait ----------------
MOV AH,00H 
INT 16H 
;-------------------------------
mov ax,4C00h ;terminate program 
int 21h
; ======== start sub s ============
PrintString PROC NEAR
pop bx    ; zakhireye adrese bargasht

pop cx   ; bardasht az poshteh (daryafte data az main program)
push bx  ; bazyabie adrese bargasht

;----------
mov bl,ch
call bl_print

mov bl,cl
call bl_print
;----------

ret ; return to where it was called
PrintString ENDP
;=========================================================
bl_print PROC NEAR
push ax
push bx
push cx
push dx
;----------part 1
mov ah,2h
mov dl,bl  

mov cl,04h
shr dl,cl

add dl,30h

cmp dl,3ah
jl lable1

add dl,07h

lable1:
int 21h

; -----------part 2

mov dl,bl
and dl,0fh

add dl,30h

cmp dl,3ah
jl lable2

add dl,07h

lable2:
int 21h
;------------
pop dx
pop cx
pop bx
pop ax

ret ; return to where it was called
bl_print ENDP



end Start

فرق این برنامه با برنامه شما این است که شما یک کپی از پشته برداشته و استفاده می کنید ولی برنامه من به طور حقیقی از پشته دارد یونیت برمی دارد. پس من بعد احضار تابع نیاز ندارم که پشته را خالی کنم. چون خود زیربرنامه پشته را خالی می کند.
برنامه من com است. و فراخوانی ها near است. در ادامه تمرینات هر وقت برخورد کردیم تمریناتی روی فرق far و near انجام می دهیم. در برنامه شما از کلمه far استفاده شده. یعنی فراخوانی دور که با دو واحد(بایت یا کلمه فعلا یادم نیست. هر کلمه دو بایت است.) آدرسها تنظیم می شود. حالا این آدرسهای دو واحدی کجا استفاده میشه من هم دقیقا کار نکرده ام و نمی دانم.
------------------------
راهنمایی برای خوانندگان:
در صفحات قبلی این تاپیک 3 روش ارسال مقدار به زیربرنامه گفته شده.
با رجیستر - با متغیر سازی - توسط پشته.
در پست حاضر من از روش ارسال توسط پشته استفاده کرده ام ولی ابداع من این بوده که در زیر برنامه پشته را هم خالی کردم از مقادیر ارسالی.
راهنمایی دوم: زیر برنامه bl_print کارش چاپ bl در مبنای 16 است. این برنامه را در همین تاپیک طرز کارش گفته شده. من بعد ساخت این برنامه برای چک برنامه ها از آن استفاده می کنم.
 
آخرین ویرایش:

saalek110

Well-Known Member
من یک فایل از این آدرس :
http://debug.persiangig.com/debug.ppt
دانلود کردم که کار با دیباگ است.

اجرای دستورات و برنامه اسمبلی در محیط نرم افزار دیباگ
کاری از آقای سعید رضا ولی زاده
استاد راهنما: آقای عباسی

پسوند فایل اصلی ppt است.

رنگ آمیزی قشنگی کرده و دستورات مفیدی هم دارد که مطالعه کنید.

=========================================

مطلب زیر هم برای یک مرور فکر کنم دید بدهد:
از تاپیک: آموزش crack...فقط علاقه مندان لطفاً
http://forum.persiantools.com/showthread.php?t=2701

os ها يکی از کاراشون اجرا برنامه ها هست...هر os يک نوع خاص از برنامه ها رو اجرا ميکنه...مثلاً Wav,txt,exe و غيره
اما بعضی از این فرمت ها نشان دهنده اینند که این برنامه ها بايد کد داخلشون اجرا بشه..مثل exe و com و همچنين dll,ocx,vxd همه اینها به نوعی شامل کد
اجرايی ميباشند...این کد ها بوسيله زبان های برنامه نويسی نوشته ميشوند مثلاً برلند پاسکال!
کاری که این compiler ها انجام ميدهند تبديل زبانی که شما استفاده کرديد به زبان کامپيوتر بعلاوه اضافه کردن
يک مشت guideline برای osای که شما ميخواهيد برنامه شما در آن اجرا شود.
در سيستم های ويندوز اکثراً نوع فايل ها از پسوند آنها مشخص ميشوند..ما این فرمت ها را برای برنامه های اجرايی داريم:exe,ocx,dll,vxd اینها تقريباً مهمترين ها هستند که
شما با اکثر compiler ها ميتونيد برای این حالات برنامه بنويسيد...

الان کمتر از بافت com استفاده ميشود اما بهترين بافت برای يادگيری برنامه نويسی به زبان اسّمبلی هست..چون هيچ گونه فرمت خاصی ندارد
و از ابتدا فايل کد اجرايی ميباشد...

اما اینها اصلاً به چه درد ميخورند؟!!
شما برای crack کردن و يا يادگی نحوه نوشته شدن برنامه خاصی قاعدتاً نياز به تحقيق در فايل اجرايی آن برنامه داريد!
برای همين معمولاً در ويندوز فايل های اجرايی دارای پسوند exe هستند پس شما بايد فايل exe را بخوبی بشناسيد!!
کمتر با com,ocx,vxd برخورد ميکنيد و فکر نکنم ما هيچ وقت به اون مرحله برسيم اما يک برسی هم برای فايل dll ميگزارم
چون امکان برخورد با این فايل رو هم خواهيد داشت!

اما خوب ما اصلاً چگونه يک برنامه/فايل اجرايی رو ميخواهيم برسی کنيم؟
فعلاً در ابتدا نيازی به برسی به صورت binary فايل exe نخاهيم داشت اما نياز به يک dissassembler و يا يک debugger خواهيم داشت.
اما اینها اصلاً چی هستند؟
dissassembler برنامه شما رو تبديل به برنامه ای با کد assembly ميکند و با debugger هم شما ميتونيد کد assembly را ببينيد...اما خوب چه فرقی ميکنند...
ببينيد تمامی برنامه های اجرايی در سيستم های intel based از يک کد زبن استفاده ميکنند که در هر صورت برنامه شما بايد تبديل به این کد ها شود برای قابل فهم شدن برای کامپيوتر شما
اما ما يک زبان macro assembly داريم که کمی پيشرفته تر از assembly شايد بشه گفت هست و اینکه شما يک راست کد نميکنيد چون
هيچ وقت اطلاع درستی از آدرس های حافظه نداريد برای همين باز هم کد assembly خوب را به يک COMpiler ميفرستيد تا به خوبی تبديل به يک برنامه قابل فهم بشه
کل این حرفا بدين معنی که debugger ها هرچند که هدف اصليشون debug کردن و يافتن مشکلات در برنامه ها هست اما
باز هم به خوبی امکان برسی را به ما ميدهند و debugger ها در حقيقت فقط قسمت کوچکی از حافظه را
disassemble ميکنند اما dissassembler ها سعی ميکنند که کل برنامه را به يکديگر ارتباط داده و نشان دهند
به همين علت dissassembler ها در اکثر مواقع مشکلتی در نمايش کد خواهند داشت اما debugger ها نه؟

حالا ما چه استفاده ای از debuger ميکنيم؟
ما برنامه را از ابتدا با debuger اجرا ميکنيم و پله پله با برنامه پيش ميريم بدين ترتيپ ميتونيم بفهميم که
هدف برنامه نويس از این کد ها چه بوده و چگونه این کار را انجام داده...که ميبينيد برای این کار نياز به دانستن
assembly خواهيد داشت...البته خوب شايد برتون سؤال پيش بياد که اینجوری چرا مثلاً ملت چرا از code های ديگران استفاده نميکنند
و يا مثلاً رقبا با این کار پی به رمز نوشته شدن این برنامه نميبرند؟؟؟
اگر برنامه نويس باشيد حتماً توجه کرديد که خواندن برنامه فرد ديگر چقدر سخت است...
حال در نظر بگيريد که خواندن برنامه طرف آن هم در زبان assembly و با n برابر شدن مقدار source آيا ميشود يا نه؟؟؟؟
که البته هدف از reverse engeeniring هم همين است که سعی ميشود با کارهايی این فرايند ساده تر شود و بتونيم چنين کاری انجام دهيم

چگونه ما حافظه رو آدرس دهی ميکنيم؟

برای راحتی به این نتيجه رسيدند که بهترين کار بری حافظه تبديل آن به واحد های بزرگ و سپس تبديل آن به واحد
های کوچکتر هست.

!!!!!!!!!!!!!!!!
البته يک نکته که بحث اسمبلی ما فعلاً در محدوده پردازنده های 16 بيتی هست و وابسته به interl architecture
تمامی این بحثا در غير intel based ها منتفی هست(amd هم اینتل based هست ناراحت نشيد)
!!!!!!!!!!!!!!!!!

چرا 16 بيت؟برای اینکه پردازنده ما 16 بيت هست بدين معنی که تمامی کرها با 16 بيت انجام ميشه و در نتيجه
ثبات ها نيز 16 بيتی هستند که با اینها ما آدرس دهی ميکنيم(more on this later)

پس محدوده مجاز برای ما از 0000h )h برای نشان دادن hex بودن عدد بکار ميرود)تا
FFFFh که ميشود 64kb.
البته این خيلی کم هست اما با ایجاد تکنيکی که از 20 بيت برای آدرس دهی استفاده ميشود این مقدار افزيش پيدا
کرد.
آدرس ها به شکل segment و offset تقسيم ميشوند و آدرس واقعی با جمع ایندو حاصل ميشود
پس آدرس موثر=segment + offset
پس با بالا و پايين کردن offset ميتوانيم يک محدوده 64k را نيز پوشش بديم.
حرکت آدرس موثر در محدوده 00000H تا FFFFFH خواهد بود که در نتيجه با داشتن این 20 بيت ميتوانيم
1mg را آدرس دهی کنيم(و صد در صد نه 640kb که اکثراً به اشتباه فکر ميکنند)

يک نکته بسيار مهم اینجاست به پين توجه کنيد!!
Segment Offset effective addres
8000h 1111h 81111h
8001h 1110h 81111h
نکته بسيار مهمی هست ها...روش فکر کنيد چرا...
اما چگونه آدرس را نشان ميديم به این شکل segment : offset که حتماً بعداً خواهيد ديد.

همينجا pascal کاران عزيز و احتمالاً basic کاران(داس) فهميدند که چرا نميتونستيد يک آرايه بزرگتر از 65536 بسازيد
و يا error هايی چون data segment is full رو مواجه ميشديد!!چرا؟

يک نکته ديگر هم اینکه باز تمامی این مطالب بيشتر در real-mode کاربرد دارند و نه Virtual/protected mode
که کل این مباحث به شکل ديگری هستند؟اگر نمدونيد فرق REal با PRotected چی هست هم خوب اگر وقت شد توضيح ميدم اما
اونهمه مهم نيست!

نکته مهم ديگری که هست این است که Intel 80XX family به صورت little endian مقادير را در حافظه نگاه داری ميکنند
که باعث اکثر اشتباهات شما همين دردسر خواهد بود...
بديم معنی که مقادير را وارونه در حافظه نگاه داری ميکنن و هميشه مقادير پايينی اول مياند و بعد بالايی
يعنی اگر عدد 1234H را ذخيره کنيد در آدرس 100h در 100h خواهيد داشت 34 و در 101h خواهيد داشت 12h
مسخرست نه؟به هر حال خيلی خيلی خيلی مهم هست...مخصوصاً در crack که بايد يادتون باشه اینها رو برای ياداشت
کردن وارونه کنيد!1(البته اکثر برنامه ها این عمل رو از شما مخفی ميکنند اما توصيه من اینه که بفهميد چی به چی شد)
البته توجه کرديد که گفتم مقادير پايين و بالا...حالا بگيد ببينم اگر يک مقدار 4 word رو نگاه داريم چجوری ذخيره ميشه؟!

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1 byte=byte
2 byte=word
3 byte= نداريم
4 byte= DWord(Double Word)
8 byte=Quad Word
16 byte=Paragraph
این 2 تا آخری البته به دردتون نميخوره
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
آخرین ویرایش:

totemism

New Member
با سلام.یه لینک برای دانلود برنامه emu8086 میخوام که بدون خطا باز بشه
ممنون میشم
 

hobab1987

Member
[FONT=&quot]سلام [/FONT]
[FONT=&quot]اولين باره كه كد اسمبلي رو مينويسم و فايل هاي [/FONT]tasm,tlink,a.asm[FONT=&quot] رو در يك پوشه بنام aگذاشتم[/FONT]
[FONT=&quot] با برنامه [/FONT]command prompt
اما error هاي هر خط اين بود:extra characters on line
HTML:
stacksg segment stack 'stack'
stacksg ends
datasg segment 'data'
datasg ends
codsg segment 'code'
assume ss:stacksg,ds:datasg,cs:codsg
main proc near 
    mov AX,datasg
    mov DX,ax
    mov AH,06 h
    mov CX,0000 h
    mov DX,182f h
    mov BH,07 h
    int 10 h
    mov AH,06 h
    mov CX,0027 h
    mov DX,184f h
    mov BH,70 h
    int 10 h
    mov AX,4c00 h
    int 21 h
    main endp
    codsg ends

end main
 
آخرین ویرایش:

the_king

مدیرکل انجمن
برنامه با یک ویرایش کوچک به راحتی قابل کامپایل و اجرا شدن است، در سطر هایی که عدد های مبنای 16
را نوشته اید، بین اعداد و کاراکتر h فاصله وجود دارد که از نظر نحوی اشتباه است، مثلا در عدد 06h بین 06 و h
فاصله افتاده.

کد:
stacksg segment stack 'stack'
stacksg ends
datasg segment 'data'
datasg ends
codsg segment 'code'
assume ss:stacksg,ds:datasg,cs:codsg
main proc near 
    mov AX,datasg
    mov DX,ax
    mov AH,06h
    mov CX,0000h
    mov DX,182fh
    mov BH,07h
    int 10h
    mov AH,06h
    mov CX,0027h
    mov DX,184fh
    mov BH,70h
    int 10h
    mov AX,4c00h
    int 21h
    main endp
    codsg ends

end main

اینطور کدهایی که در انتهایشان فرصتی برای فشار دادن کلیدی از سوی کاربر در نظر نگرفته اید را در DOS
یا پنجره Command Prompt اجرا کنید تا فرصتی برای مشاهده نتایج آن داشته باشید. وگرنه در ویندوز بلافاصله
بعد از اجرای برنامه از محیط خارج خواهد شد.
فایل کد asm به همراه فایل کامپایل شده exe (البته با کامپایلر ML مایکروسافت) ضمیمه این پست می باشد.
 

پیوست ها

  • A.zip
    677 بایت · بازدیدها: 9

hobab1987

Member
مرسي دوستم از توضيح كاملتون
خوب من الان از محيط cmd اجرا كردم ،
وقتي دستور c:\a>link a رو كه همون طور در پست 1 هم آقا سالك گفتند رو نوشتم برنامه اين پيغام رو داد!!!!!!!!!!

'link' is not recogenize as an in internal or external command
operable program or batch file

بعد تا حالا در محيط هاي ديگه هنوز برنامه رو اجرا نكردم اگر بخوام اين كار رو كنم كد اسمبلي دستور مثل getch(); رو نمي دونم!
 
آخرین ویرایش:

the_king

مدیرکل انجمن
مرسي دوستم از توضيح كاملتون
خوب من الان از محيط cmd اجرا كردم ،
وقتي دستور c:\a>link a رو كه همون طور در پست 1 هم آقا سالك گفتند رو نوشتم برنامه اين پيغام رو داد!!!!!!!!!!

'link' is not recogenize as an in internal or external command
operable program or batch file
پیغام خطا به این معنا است که سیستم عامل نتوانسته LINK.EXE را در مسیر فعلی و مسیر های %PATH% پیدا کند.
برای آنکه بتوانید از Link.exe یا هر فایل اجرایی دیگری استفاده کنید، بایستی چنین فایلی یا در مسیر فعلی باشد،
مثلا اگر در مسیر C:\PROG قرار دارید، فایل C:\PROG\LINK.EXE هم وجود داشته باشد، و یا مسیر پوشه ای
که LINK.EXE در آن قرار دارد را به مقدار %PATH% سیستم عامل اضافه کنید. مثلا اگر LINK.EXE را در مسیر
C:\MASM615\BIN کپی کرده اید، بایستی پیش از هر کاری این فرمان زیر را برای اضافه شدن آن مسیر به %PATH%
وارد کنید (بین هر کدام از مسیر ها از کاراکتر ; استفاده می شود) :
کد:
SET PATH=%PATH%;C:\MASM615\BIN

شما در هر زمان می توانید مسیر های موجود در %PATH% را با وارد کردن دستور زیر مشاهده کنید :
کد:
ECHO %PATH%

بعد تا حالا در محيط هاي ديگه هنوز برنامه رو اجرا نكردم اگر بخوام اين كار رو كنم كد اسمبلي دستور مثل getch(); رو نمي دونم!
شما برای دریافت یک کلید از صفحه کلید بایستی از سرویس های Interrupt (وقفه) استفاده کنید، آن چیزی که شما
در انتهای برنامه نیاز دارید سرویسی است که کلید فشار داده شده را نمایش ندهد، یعنی فقط دریافت کند و روی
صفحه نمایش نشان ندهد، سرویس 8 از وقفه 21h این عمل را انجام داده و کلید فشار داده شده را در AL بر می گرداند :
کد:
        MOV     AH, 8
        INT     21h
 

جدیدترین ارسال ها

بالا