常见汇编代码

常见汇编代码

  1. 编写程序:比较AX,BX,CX中带符号数的大小,将最大的数放在AX中

    code segment
     assume cs:code 
    
     mov ax,32
     mov bx,74
     mov cx,23
    
    sort: cmp ax,bx 
          jge X          ;如果ax大于等于bx就跟cx比较
          xchg ax,bx 
        X:cmp ax,cx       ;如果ax大于cx
          jge Y
          xchg ax,cx  
        Y:int 21h 
          mov ax,4c00h
    code ends
         end sort
    

2.要求对键盘输入的小写字母用大写字母显示出来

    code segment 
     assume cs:code 

    start: mov ah,1
        int 21h 

        cmp al,'a'       
        jz error 
        cmp al,'z'
        ja error 
        sub al,20h       ;'A'~'Z':41~5AH     ‘a'~'z':61~7ah
        mov dl,al 
        mov ah,2 
        int 21h 
        jmp start
    error:ret
code ends 
     end start

3.编写程序:从键盘上接收一个四位数的十进制数,并在终端上显示出与它等值的二进制数。

    code segment 
      assume cs:code 
    begin:xor bx,bx       ;清空bx
          mov ch,4
          mov cl,4        ;设置内外层的循环次数
    input:shl bx,cl        ;bx中的内容逻辑左移
          mov ah,1
          int 21h          ;输入
          cmp al,30h        ;是否小于0
          jb  input         ;是就重新输入
          cmp al,39h        ;是否大于9
          ja  input      
          and al,0fh        ;转换为相应的二进制
          jmp combine

    combine:or bl,al         
            dec ch 
            jnz input 
    display:mov cx,16        ;输出的循环次数
       print:mov dl,0 
             rol bx,1 
             rcl dl,1 
             or dl,30h        ;清空dl
             mov ah,2 
             int 21h 
             loop print 
             ret
    code ends 
         end begin 

4.将内存ffff:0~ffff:d单元中的数据复制到0:200~0:20d单元中。

code segment
 assume cs:code 
        mov bx,0 
        mov cx,0fh 

 copy:mov ax,0ffffh    
      mov ds,ax 
      mov dl,[bx]
      mov ax,0020h
      mov ds,ax 
      mov [bx],dl
      inc bx 
      loop copy 


    mov ax,4c00h 
    int 21h 
code  ends 
      end copy 

5.将AX寄存器中的16位数分成四组,每组四位,然后把这四组数分别放在AL、BL、CL和DL中。

data segment
   s db 4 dup(?)   ;占位,并清空 
 mov ax,0ffffh
data ends 
;-----------------------------------    
 progrnam segment 
          assume cs:progrnam,ds:data
 begin:mov cl,4     ;ax逻辑右移四次
       mov ch,4     
       lea bx,s
  X: mov dx,ax
     and dx,0fh      ;逻辑与屏蔽高位
     mov [bx],dl   ;以字节形式将dl移入bx
     inc bx 
     shr ax,cl       ;逻辑右移
     dec ch 
     jnz X
  Y: mov dl,s        ;依次移入相应寄存器内
     mov cl,s+1
     mov bl,s+2 
     mov al,s+3
     ret     
progrnam ends 
    end begin

6.从键盘输入一系列字符,以字符‘$’为结束符,然后对其中的非数字字符计数,并显示出计数结果。

`stack segment
     dw  100h    dup(?)
     top  label   word
stack ends

data segment
        h1   db  'Please input a string: ','$'
        h2   db 'The number of the chars that is not digit:','$'
       crlf  db 0dh,0ah,24h
data   ends

code  segment
      assume  cs:code,ds:data,ss:stack

 main  proc    far
  begin:mov     ax,stack 
        mov     ss,ax
        lea     sp,top
        mov     ax,data 
        mov     ds,ax

        lea     dx,h1
    mov ah,9
    int 21h

        mov     cx,0

input:     mov     ah,1
        int     21h
        cmp     al,'$'
        jz      exit
        cmp     al,30h
        jb      count 
        cmp     al,39h
        jnb     count 
        jmp     input

count:  inc     cx
        jmp     input

exit:   lea     dx,crlf
        mov     ah,9
        int     21h
        lea     dx,h2
        int     21h

        mov     si,0
        mov     bl,10
        mov     ax,cx

mem:     div     bl
        mov     dl,ah
        mov     dh,0
        push    dx
        inc     si
        mov     ah,0
        cmp     al,0
        jnz     mem 

prin:     pop     dx
        add     dl,30h
        mov     ah,2
        int     21h
        dec     si
        cmp     si,0
        jnz     prin

        mov     ah,4ch
        int     21H

main    endp
code    ends
        end   begin 
`

7.已知两个整数变量A和B,试编写完成下述操作的程序:
(1)若两个数中有一个数是奇数,则将奇数存入A中,偶数存入B中
(2)若两个数均为奇数,则两数分别加1,并存回原变量。
(3)若两个数均为偶数,则两变量不变。

code segment
     assume cs:code 
begin: mov ax,13
       mov bx,12
       mov cx,ax 
       mov dx,bx 
       xor ax,bx 
       test ax,0001h    ;A和B是否同时为奇数或偶数
       jz next           ;是
       test bx,0001h    
       jz return        ;B为偶数,A为奇数,加1
exchange:mov ax,dx        ;A为偶数,B为奇数,交换
       mov bx,cx 
       jmp return 
  next:test bx,0001h    ;是否同为奇数
       jz return        ;同为偶数,不变
       inc dx  
       inc cx
       jmp exchange
  return:ret 
code ends 
      end begin

8.比较两个字符串string1和string2所含的字符是否相同。若相同则显示‘true’,否则显示‘false’。

 data segment 
     string1 db 'i am a student'
     string2 db 'i am a student'
     string3 db 'true',0dh,0ah,'$'
     string4 db 'false',0dh,0ah,'$'
data ends 
;--------------------------  
progrnam  segment 
      assume cs:progrnam,ds:data
start:push ds 
      sub ax,ax
      push ax 
      mov ax,data
      mov ds,ax
      mov es,ax 
begin:lea si,string1
      lea di,string2
      cld    
      mov cx,string2-string1
      repe cmpsb
      jne Y
      lea dx,string3
      jmp print    
     Y:lea dx,string4
    print: mov ah,9
       int 21h 
    mov ax,4c00h
    int 21h

progrnam ends 
     end start

9.编写无溢出除法的汇编子程序 。

这里所说的除法溢出并不是指分母为0而发生溢出的情况。我们以除数为8位的情况来说明,假设我们的被除数为65535(16位的最大值)存储在AX 中,除数为1,存储在CL中,然后执行除法指令: div CL。根据上面的说法,结果都是放在AX中的,余数为0,当然这没有问题,然而商为65535要放在AL中却是放不下的,因为AL能存放的最大值只为 255,所以此时就会发生溢出。我们可以看到65535/1 = 255,这显然与我位正常的除法结果不符。
如何解决这个溢出问题
既然我们知道了问题的根源,要解 决它就不困难了。为了统一而且不发生溢出,我们可以把所有的除法的商都用32位来保存,即所有的被除数都用32位,所有的除数都用16位,所有的商都用 32位,所有的余数都用16位来保存,就可以解决这个问题,因为一个数除以一个整数后,不可能大于其之前的值。而对于8位的除法,除数和被除数的高位全用 0补全即可。为了达到这个目的,我们就不能使用默认的除法指令div了,而需要我们写代码来实现我们自定义的除法。

自定义除法: X为除数,N为被除数,H代表X的高16位,L代表X的低16位,
int(H/N)和rem(H/N)代表着H除以N的商和余数
X/N = int(H/N)* 2^16 + [rem(H/N)* 2^16+L]/N

 progrnam segment
          assume cs:progrnam 
          mov ax,0ffffh
          mov cx,1           ;初始化进行测试
 begin: cmp cx,0
        je return   ;除数不能为0
        push bx  
        push ax
        mov ax,dx 
        mov dx,0 
        div cx  ;执行H/N,商保存在ax中,余数在DX中
        mov bx,ax ;把商保存 
        pop ax    ;取出低位,执行rem(H/N)*2^16+L
        div cx    ;执行[rem(H/N)*2^16+L]/N ,商保存在ax中 ,余数在dx中
        mov cx,dx ;cx保存余数
        mov dx,bx ;dx中保存高位除法的商
        pop bx 
return:ret 
    mov ax,4c00h
    int 21h 
progrnam ends 
       end begin

10.编写一个程序,接受从键盘输入的10个十进制数字,输入回车符则停止输入,然后将这些数字加密后(用XLAT指令变换)存入内存缓冲区BUFFER。加密表为:

输入数字:0,1,2,3,4,5,6,7,8,9

密码数字:7,5,9,1,3,6,8,0,2,4

data segment
     number db 7,5,9,1,3,6,8,0,2,4
     buffer db 10 dup(?)
data ends 
;-------------------------------------
code segment 
     assume cs:code,ds:data 
     mov si,0
     mov cx,10 
     lea bx,number 
input:mov ah,1 
      int 21h
      cmp al,0dh    ;是否为回车符
      jz return
      cmp al,30h    ;比较是否是0~9,不是就重新输入
      jb input 
      cmp al,39h
      ja input 
      xlat           ;变换进行存储
      mov buffer[si],al 
      inc si 
      loop input 
return:ret 
code ends 
end input

data segment
     number db 7,5,9,1,3,6,8,0,2,4
     buffer db 10 dup(?)
data ends 
;-------------------------------------
code segment 
     assume cs:code,ds:data 
     mov si,0
     mov cx,10 
     lea bx,number 
input:mov ah,1 
      int 21h
      cmp al,0dh    ;是否为回车符
      jz return
      cmp al,30h    ;比较是否是0~9,不是就重新输入
      jb input 
      cmp al,39h
      ja input 
      xlat           ;变换进行存储
      mov buffer[si],al 
      inc si 
      loop input 
return:ret 
code ends 
     end input

11.编写一个子程序嵌套结构的程序模块,分别从键盘输入姓名及8个字符的电话号码,并以一定的格式显示出来。

主程序TELIST:
A.  显示提示符“INPUT  NAME:”;
B.  调用子程序INPUT_NAME输入姓名;
C.  显示提示符“INPUT  A  TELEPHONE  NUMBER:”;
D.  调用子程序INPHONE输入电话号码;
E.  调用子程序PRINTLINE显示姓名及电话号码。
子程序INPUT_NAME:
A.  调用键盘输入子程序GETCHAR,把输入的姓名存放在INBUF缓冲区中;
B.  把INBUF中的姓名移入输出行OUTNAME。
子程序INPHONE:
A.  调用键盘输入子程序GETCHAR,把输入的8位电话号码存放在INBUF缓冲区中;
B.  把INBUF中的号码移入输出行OUTPHONE。
子程序PRINTLINE:
显示姓名及电话号码,格式为:
  NAME  TEL.
  X X X     XXXXXXXX

代码如下:

data segment
     tipname db 'input name:','$'
     tipnumber db 'input a telephone number:','$'
     inbuf db 12 dup(' ')
     crlf db 0dh,0ah,'$'
     outname db 16 dup(' ')
     outphone db 12 dup(' '),0dh,0ah,'$'
     info db 'name',12 dup(' '),'tel',0dh,0ah,'$'
data ends
;------------------------------------
stack segment 
       dw 100 dup(?)      ;伪定义使得同一个变量具有不同的属性
    string label word    
stack ends 
;----------------------------------------
progrnam segment 
 main proc far
       assume cs:progrnam,ds:data,es:data,ss:stack 
  start:mov ax,stack
        mov ss,ax 
        mov sp,offset string 
        push ds 
        xor ax,ax 
        push ax 
        mov ax,data 
        mov ds,ax 
        mov es,ax 

  begin:                
         mov ah,09          ;输出提示字符串
         mov dx,seg tipname
         mov ds,dx 
         mov dx,offset tipname
         int 21h
         call input_name    ;输入姓名
         mov ah,09           ;输出提示字符串
         mov dx,seg tipnumber
         mov ds,dx 
         mov dx,offset tipnumber
         int 21h 
         call input_number 
         call printline      
         ret
 main endp 
 ;------------------------------------------
 input_name proc near
            call getchar 
            lea si,inbuf
            lea di,outname
            mov cx,12      ;设置计数器
            cld             ;设置方向为自增
;movsb 与rep结合是传送字节,相当于 movs es:byte ptr[di],ds:[si]
            rep movsb       
            ret 
input_name endp 
;-----------------------------------------------
input_number proc near 
         call getchar 
         lea si,inbuf 
         lea di,outphone
         mov cx,12 
         cld 
         rep movsb 
         ret 
input_number endp 
;------------------------------------------------
getchar proc near
        mov al,20h 
        mov cx,12  
        lea di,inbuf
        cld 
;stosb这里是为了每一次输入一个字节存入相应的缓冲区
        rep stosb 
        mov cx,12 
        mov di,0 
   input:mov ah,1 
         int 21h 
         cmp al,0dh
         jz return
         mov inbuf[di],al 
         inc di 
         loop input
    return: call disp_crlf           ;输出回车符
            ret 
getchar endp 
;--------------------------------------
printline proc near             ;这里均是将所得的字符串进行输出
          mov ah,09
          mov dx,seg info
          mov ds,dx 
          mov dx,offset info
          int 21h 
          mov ah,09
          mov dx,seg outname
          mov ds,dx 
          mov dx,offset outname
          int 21h 
          ret 
printline endp 
;---------------------------------------
disp_crlf proc near
          mov ah,09
          mov dx,seg crlf
          mov ds,dx 
          mov dx,offset crlf
          int 21h 
          ret 
disp_crlf endp 
;-----------------------------------------
progrnam ends 
         end start

12.试编写一个汇编语言子程序,要求将包含任意字符、以0结尾的字符串中的小写字母转换成大写字母。

data segment
      string db 'i am A stuDEnt',0h
data ends
;------------------------------

progrnam segment
     assume ds:data,cs:progrnam
start:push ds
     xor ax,ax   
     mov ax,data  
     mov ds,ax
     lea si,string
     push si     
begin: mov al,[si]      ;判断是否为小写字母并进行转换
      cmp al,0
      je return   
      cmp  al,'a'
      jb print
      cmp  al,'z'
      ja print           ;如果不是小写字母直接进行输出
      sub al,20h
      mov [si],al
print:push ds           ;将字母进行输出
      ;mov al,[si]
      mov dl,al
      mov ah,2
      int 21h
      pop ds      
    n:inc si
      jmp begin      
return:
      pop si
      pop ds
    mov ax,4c00h
    int 21h

progrnam ends
    end start  

13.编写程序,将一个包含有20个数据的数组M分成两个数组:正数数组P和负数数组N,并分别把这两个数组中数据的个数显示出来。

data segment
    string1 db 0dh,0ah, 'positive number:','$'
    string2 db 0dh,0ah,'negative number:','$'
    array dw  1,2,3,4,5,6,7,8,-4,-8,-9,-6,-2,-8,8,12,18,-12,5,64
    array1 dw 20 dup(?)     ;存储正数数组
    array2 dw 20 dup(?)      ;存储负数数组
    count1 db 0
    count2 db 0               ;计数
    CRLF DB 0dh,0ah,'$'
data ends
;----------------------------------
progrnam segment 
main proc far 
    assume ds:data,cs:progrnam
    s:   push ds 
        xor ax,ax
        push ax 
        mov ax,data 
        mov ds,ax    
    begin:mov cx,20         ;循环次数
          lea bx,array      ;bx相当于数组的首地址
          lea si,array1
          lea di,array2  
    start:mov ax,[bx]
            cmp ax,0         ;是否为负数
            js Y             ;是负数
            mov [si],ax       ;存入正数数组
            inc count1 
            add si,2 
            jmp short next  
        Y:  mov [di],ax 
            inc count2
            add di,2 
        next:add bx,2 
             loop start 
        lea dx,string1 
        mov al,count1 
        call print 
        lea dx,string2
        mov al,count2       
        call print
        ret
main endp        
;--------------------------------------
print  proc near
        push ax      ;al中存储计数值,要进行保存
        mov ah,9 
        int 21h
        pop ax        ;出栈,进行ASCII码调整
        aam            ;调整方式AH<-AL/10(商),AL<-AL%10 
        push ax  
        add ah,30h  ;变为0~9的ASCII码
        mov dl,ah 
        mov ah,2
        int 21h
        pop ax 
        add al,30h 
        mov dl,al 
        mov ah,2
        int 21h
        lea dx,CRLF
        mov ah,9 
        int 21h 
        ret 
print endp 
progrnam ends 
        end s

14.设有10个学生的成绩分别是76,69,84,90,73,88,99,63,100和80分。试编制一个子程序统计60~69分,70~79分,80~89分,90~99分和100分的人数,分别存放到S6,S7,S8,S9和S10单元中。

data segment
     grade dw 76,69,84,90,73,88,99,63,100,80
     count1 dw 0
     count2 dw 0
     count3 dw 0
     count4 dw 0
     count5 dw 0
data ends
;-----------------------------------------
progrnam segment 
         assume ds:data,cs:progrnam 
          push ds
          xor ax,ax 
          push ax 
          mov ax,data 
          mov ds,ax 
    begin:mov cx,10
    mov si,0
    next:mov ax,grade[si]
         mov bx,10 
         div bl 
         mov bl,al 
         sub bx,6 
         sal bx,1    ;将(grade/10-6)×2就是
         inc count1[bx]  ;count1是首地址
         add si,2
    loop next
progrnam ends 
     end begin

15.输出空行

progrnam segment
         assume cs:progrnam
    begin:push cx
          push dx
          mov ax,3    ;这里对ax进行赋值,观察输出的结果
          mov cx,ax
    print:mov dl,0dh
          mov ah,2    ;这是对与输出一个字符的bios的调用
          int 21h  ;print的功能就是输出空行,0dh为回车
        mov dl,0ah ;0ah为换行
        mov ah,2
        int 21h 
        loop print
        pop dx
        pop cx
    ;这一段程序是为了测试输出后的结果,主要母的是输出一个黄色的'*'
        mov ah,9
        mov al,'*'
        mov bh,0 
        mov bl,0eh
        mov cx,1
        int 10h
        ret
progrnam ends
         end begin
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值