汇编语言-子程序设计

目录

题目1、将BUF开始的10个单元中的二进制数转换成两位十六进制数的ASCII码,在屏幕上显示出来。要求码型转换通过子程序HEXAC实现,在转换过程中,通过子程序DISP实现显示。

题目2、编写一个主程序,从键盘接收若干个字符,然后用远调用的方法,调用子程序统计字符串中小写字符’x’的个数.子程序的参数是字符串的首地址TABLE,字符串长度N及字符”x”.子程序返回字符"x”的个数.参数传送采用堆栈实现.主程序在子程序返回后,显示字符”x”及其个数(设为一位十六进制数)。

题目3、请编写一个程序来实现简单的程序菜单显示。(采用多模块程序设计方法)


题目1、将BUF开始的10个单元中的二进制数转换成两位十六进制数的ASCII码,在屏幕上显示出来。要求码型转换通过子程序HEXAC实现,在转换过程中,通过子程序DISP实现显示。

实现程序如下所示:

;将二进制数转换为两位十六进制数,则每个二进制数最多8位
;使用了子程序的近程调用
assume cs:code,ds: data
data segment
    ;二进制最高位FF,即255
    buf      db  00010001b,00100010b,00110011b,01000100b,01010101b
             db  10111011b,11001100b,11011101b,11101110b,11111111b
    buf_size equ $ - buf
    output   db  'Array: $'
data ends
code segment
    ;一般来说,主过程应当定义为far属性,这是由于八程序的主过程看作dos调用的一个子过程
    ;因而dos对main的调用以及main中的ret就是far属性的
main proc far
    start:     
               mov  ax,data
               mov  ds,ax
               mov  cx,buf_size
               mov  si,0
               lea  dx,output
               mov  ah,09h
               int  21h
    lop:       call hexac
               inc  si
               loop lop
               jmp  exit
hexac proc near
    ;将二进制数转化为十六进制对应的ASCII码,其每位十六进制必然为数字或A-F
               push cx
               mov  ax,0
               mov  al,[buf+si]
               mov  cl,4
               shl  ax,cl
               shr  al,cl          ;ah,al分别存储高四位和底四位的数字
               cmp  al,9h
               ja   low_char
               jbe  low_digit
    highTrans: 
               cmp  ah,9h
               ja   high_char
               jbe  high_digit
    low_digit: 
               add  al,30h
               jmp  highTrans
    low_char:  
               add  al,37h
               jmp  highTrans
    high_digit:
               add  ah,30h
               call disp
               jmp  return
    high_char: 
               add  ah,37h
               call disp
    return:    
               pop  cx
               ret
hexac endp
disp proc near
    ;输出两个字符
               mov  dl,ah
               call outputchar
               mov  dl,al
               call outputchar
               mov  dl,' '
               call outputchar
               ret
    outputchar:
               mov  ah,02h
               int  21h
               ret
             
    exit:      
               mov  ax,4c00h
               int  21h
disp endp
main endp
code ends
end start 

 该程序将10个二进制数据:

00010001b,00100010b,00110011b,01000100b,01010101b

10111011b,11001100b,11011101b,11101110b,11111111b

输出,运行结果如下所示:


题目2、编写一个主程序,从键盘接收若干个字符,然后用远调用的方法,调用子程序统计字符串中小写字符’x’的个数.子程序的参数是字符串的首地址TABLE,字符串长度N及字符”x”.子程序返回字符"x”的个数.参数传送采用堆栈实现.主程序在子程序返回后,显示字符”x”及其个数(设为一位十六进制数)。

 子程序的远调用,统计字符串中小写字符‘x’的个数

实现程序如下所示:

;从键盘接收若干个字符,使用远程调用,统计字符串中小写字符x的个数
assume cs:code,ds: data,es:data
data segment
       input  db 'Enter your string:$'
       table  db 50h,100 dup(?)
       count  db ?
       output db 0ah,'The num of x:$'
data ends
code segment
       start:
             mov  ax,data
             mov  ds,ax
             mov  es,ax
             lea  dx,input
             mov  ah,09h
             int  21h
             lea  dx,table
             mov  ah,0ah
             int  21h

             push dx                 ;传入字符串的首地址
             mov  dl,[table+1]
             push dx                 ;传入参数字符串长度
             mov  dx,'x'
             push dx                 ;传入要统计的字符'x'
             call far ptr getX       ;远程调用push cx,push ip
             pop  dx
             mov  count,dl
             lea  dx,output
             mov  ah,09h
             int  21h
             mov  dl,count
             add  dl,30h
             mov  ah,02h
             int  21h
             jmp  exit
          
       exit: 
             mov  ax,4c00h
             int  21h
code ends

code2 segment
getX proc far
              pop   bx              ;call指令自动调用push cs和ip堆栈中保留了返回地址的段地址和偏移地址
              pop   si              ;先得到cs和ip的值,其中si保存cs的值,bx保存ip的值
              pop   ax              ;获取参数'x'
              pop   cx              ;获取参数字符串长度
              pop   di              ;获取参数字符串的首地址
              add   di,2
       ;将偏移地址压入堆栈中
              mov   dx,0
              cld
scan proc far
              repne scasb           ;每次di和al相等时退出,使用dx计数
              inc   dx
              cmp   cx,0            ;xxaxxb
              je    check
              ja    scan

check proc far
              cmp   al,[di-1]
              je    return          ;判断最后一个字符是否为x,如果不是则dx-1
              dec   dx
check endp
return proc far
              push  dx
              push  si              ;push cs
              push  bx              ;push ip
return endp
              ret                   ;ret指令自动调用pop ip pop cs
scan endp
getX endp
code2 ends
end start

使用debug指令查看远程调用时堆栈段的变化情况,如下所示:

可以观察到远程调用时,将下一条要执行的指令CS = 0775,IP = 0026压入堆栈中

Push(CS),Push(IP)

查看堆栈段的数据可以观察到调用子程序的下一条指令的CS和IP值

运行程序的结果如下所示,与预期结果一致。


题目三、请编写一个程序来实现简单的程序菜单显示。(采用多模块程序设计方法)

显示一个菜单要求用户从下表中选择:

(1)      HEXAC GAME                 (对应-->程序1)

(2)      CHAR  STATISTICS PROGRAM    (对应-->程序2)

(3)      PRESS  “ESC”  TO  QUIT

用户作出选择1~3时,显示输出要执行操作的名字,如“Your selection is 1,the program will execute HEXAC NUMBER GAME!”然后转向相应的程序去执行,执行结束前进行退出的判断,显示一个提示信息“will you continue program really?(Y:N)”要求用户从键盘键入字符,若是“Y”键,则继续程序的执行,若是“N”键,则返回到菜单。若用户选择3,要求程序显示提示信息“Please press ESC key to exit!”,并能按要求正确退出。

文件1(主程序)程序如下所示:、

;从键盘接收若干个字符,使用远程调用,统计字符串中小写字符x的个数
; source module1
;引入far 模块
extrn game1:far,game2:far
assume cs:code,ds: data,es:data
data segment
    continue db 0dh,0ah,'will you continue progrqam really?(Y:N):$'
    option1  db 0dh,0ah,'Your selection is 1,the program will execute HEXAC NUMBER GAME!',0dh,0ah,'$'
    option2  db 0dh,0ah,'Your selection is 2,the program will execute CHAR STATISTICS PROGRAM!',0dh,0ah,'$'
    option3  db 0dh,0ah,'Please press ESC key to exit:$'

    menu     db 0dh,0ah,'1: HEXAC NUMBER GAME',0dh,0ah
             db '2: CHAR STATISTICS PROGRAM',0dh,0ah
             db '3: PRESS "ESC" TO QUIT',0dh,0ah
             db 'Please input your option:',0dh,0ah,'$'

    bye      db 0dh,0ah,'GoodBye!',0dh,0ah,'$'
data ends
code segment
main proc far
    start:        
                  mov  ax,data
                  mov  ds,ax
                  mov  es,ax
    showmenu:     
                  lea  dx,menu
                  mov  ah,09h
                  int  21h
                  mov  ah,01h
                  int  21h
                  cmp  al,'1'
                  je   routine_1
                  jb   exit
                  cmp  al,'2'
                  je   routine_2
                  cmp  al,'3'
                  je   routine_3
                  ja   exit

    routine_1:    
                  lea  dx,option1
                  call output_string
                  push ds
                  call far ptr game1    ;远程调用前往其它模块
                  pop  ds               ;需要恢复数据段
                  call _continue
                  jmp  routine_1
                  
    routine_2:    
                  lea  dx,option2
                  call output_string
                  push ds               ;由于后续程序需要使用到es,保存es的值
                  call far ptr game2
                  pop  ds               ;恢复数据段
                  call _continue
                  jmp  routine_2
    routine_3:    
                  lea  dx,option3
                  call output_string
                  mov  ah,01h
                  int  21h
                  cmp  al,1Bh           ;1Bh即esc的ascii码值
                  je   exit
                
                  jne  routine_3

_continue proc near
                  lea  dx,continue
                  call output_string
                  mov  ah,01h
                  int  21h
                  cmp  al,'Y'           ;59H
                  je   con_return
                  cmp  al,'N'           ;5AH
                  je   showmenu
                  jne  _continue        ;输入不符合Y/N,则重新输入
    con_return:   
                  
                  ret
_continue endp

                  
               
output_string proc near
                  mov  ah,09h
                  int  21h
                  ret
output_string endp
    exit:         
                  lea  dx,bye
                  call output_string
                  mov  ax,4c00h
                  int  21h
main endp
code ends
end start 

文件二(子程序):

;source module2
assume cs:code,ds:data
    public game1,game2
data segment
    ;----------------------------game1-----------------------------
    buf      db  00010001b,00100010b,00110011b,01000100b,01010101b
             db  10111011b,11001100b,11011101b,11101110b,11111111b
    buf_size equ $ - buf
    output_1 db  'Array: $'
    ;----------------------------game2-----------------------------
    input    db  'Enter your string:$'
    table    db  50h,100 dup(?)
    count    db  ?
    output_2 db  0ah,'The num of x:$'
data ends
code segment
                
game1 proc far
               mov   ax,data
               mov   ds,ax
               mov   cx,buf_size
               mov   si,0
               lea   dx,output_1
               mov   ah,09h
               int   21h
    lop:       call  hexac
               inc   si
               loop  lop
               ret                   ;回到原过程
hexac proc near
    ;多模块调用,data和code
    ;需要将cs和ip保存起来
               push  cx
               mov   ax,0
               mov   al,[buf+si]
               mov   cl,4
               shl   ax,cl
               shr   al,cl           ;ah,al分别存储高四位和底四位的数字
               cmp   al,9h
               ja    low_char
               jbe   low_digit
    highTrans: 
               cmp   ah,9h
               ja    high_char
               jbe   high_digit
    low_digit: 
               add   al,30h
               jmp   highTrans
    low_char:  
               add   al,37h
               jmp   highTrans
    high_digit:
               add   ah,30h
               call  disp
               jmp   return1
    high_char: 
               add   ah,37h
               call  disp
    return1:   
               pop   cx
               ret
hexac endp
disp proc near
    ;输出两个字符
               mov   dl,ah
               call  outputchar
               mov   dl,al
               call  outputchar
               mov   dl,' '
               call  outputchar
               ret
    outputchar:
               mov   ah,02h
               int   21h
               ret
disp endp
               mov   ax,4c00h
               int   21h
game1 endp
game2 proc far
               mov   ax,data
               mov   ds,ax
               mov   es,ax
               lea   dx,input
               mov   ah,09h
               int   21h
               lea   dx,table
               mov   ah,0ah
               int   21h

               push  dx              ;传入字符串的首地址
               mov   dl,[table+1]
               push  dx              ;传入参数字符串长度
               mov   dx,'x'
               push  dx              ;传入要统计的字符'x'
               call  getX            ;远程调用push cx,push ip
               pop   dx
               mov   count,dl
               lea   dx,output_2
               mov   ah,09h
               int   21h
               mov   dl,count
               add   dl,30h
               mov   ah,02h
               int   21h
               ret
          
getX proc near
               pop   bx              ;段内近调用,保存ip值
               pop   ax              ;获取参数'x'
               pop   cx              ;获取参数字符串长度
               pop   di              ;获取参数字符串的首地址
               add   di,2
    ;将偏移地址压入堆栈中
               mov   dx,0
               cld
    scan:      
               repne scasb           ;每次di和al相等时退出,使用dx计数
               inc   dx
               cmp   cx,0
               je    check
               ja    scan

    check:     
               cmp   al,[di-1]
               je    return2         ;判断最后一个字符是否为x,如果不是则dx-1
               dec   dx
    return2:   
               push  dx
               push  bx              ;push ip,恢复ip值

               ret                   ;ret指令自动调用pop ip pop cs
getX endp
game2 endp
code ends
end

注意:

在链接时,需要将两个模块的目标文件链接在一起:

运行结果如下所示:

功能1如下图所示:输入Y,程序继续运行,输入N,停止程序,返回菜单,输入其它字符,则提示继续输入。

功能2实现如下所示,统计x的字符个数

功能3实现如下所示,点击esc键退出程序,否则提示继续输入

使用debug调试不同模块之间的子程序调用,如下所示:

进行多模块调用之前,CS:IP的值为077F:002B,并且使用U指令可以观察到下一条执行的指令IP的值为30,执行调用之后观察到CS:IP的值为0792:002B,使用D指令查看堆栈段的数据可以观察到主程序的CS和IP的值

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值