汇编学习笔记(三)

一.子程序设计
如果某个程序片段将反复在程序中出现,就把它设计成子程序
或某个程序片段具有通用性,可供许多程序共享,就把它设计成子程序
(一)过程调用和返回指令
 调用前必须先压入堆栈。
 过程调用指令有段内调用和段间调用之分。
 过程返回指令也有段内返回和段间返回之分。
 段内:近调用 近返回
 段间:远调用 远返回
 
 1.过程调用指令
 过程调用指令先把子程序的返回地址(即CALL指令的下一条指令的地址)压入堆栈。
 (1)段内直接调用
 段内直接调用指令用于当前段内的子程序
  CALL DST
 该指令进行的具体操作分解如下:SP<---SP-2
               [SP]<---IP
               IP<---IP+disp
 (2)段内间接调用
   CALL OPRD
   OPRD是16位通用寄存器或字存储器操作数
   具体操作分解如下:
   SP<---SP-2
   [SP]<---IP
   IP<---(OPRD)
例:
  CALL BX
  CALL WORD PTR [BX]
 (3)段间直接调用
  调用其他代码段中的子程序
  CALL 过程名
  具体操作的分解:
  SP<---SP-2
  [SP]<---CS
  SP<---SP-2
  [SP]<---IP
  IP<---过程入口地址的偏移
例如:CALL FAR PTR SUBRO
 (4)段间间接调用
   CALL OPRD
   OPRD是双字存储器操作数
    CALL 过程名
  具体操作的分解:
  SP<---SP-2
  [SP]<---CS
  SP<---SP-2
  [SP]<---IP
  IP<---OPRD的低字值
  CS<---OPRD的高字值
例如:CALL DWORD PTR [BX]

 2.过程返回指令
 过程返回指令把子程序的返回地址从堆栈弹出到IP或CS和IP
 不影响标志位
 (1)段内返回指令
  RET
  具体操作:
  IP<---[SP]
  SP<---SP+2
 (2)段间返回指令
  RET
  具体操作:
  IP<---[SP]
  SP<---SP+2
  CS<---[SP]
  SP<---SP+2
 (3)段内带立即数返回指令
   RET 表达式
   汇编程序把表达式的结果data取整
   IP<---[SP]
   SP<---SP+2
   SP<---SP+data
   该指令能同时修改堆栈指针。对堆栈的操作是以字为单位。data一般为偶数
 (4)段间带立即数返回指令
   RET 表达式
   具体操作:
   IP<---[SP]
   SP<---SP+2
   CS<---[SP]
   SP<---SP+2
   SP<---SP+data
   
(二)过程定义语句
  利用过程定义伪指令语句,可把程序片段说明为具有近类型或远类型的过程
  并能给过程起一个名字

  过程名 PROC [NEAR|FAR]  ;默认为NEAR
        ...
  过程名 ENDP
  
  过程名也有段值、偏移和类型三个属性
  
(三)子程序举例
已知程序如下
DATA SEGMENT
ORG 1000H
BLOCK DB 48H,8DH
RESULT DB ?
DATA ENDS
STACK SEGMENT PARA STACK 'STACK'
DB 64 DUP(?)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,SS:STACK,DS:DATA
START PROC
BEGIN:MOV AX,DATA
      MOV DS,AX
      MOV SP,4000H
      LEA BX,BLOCK
      MOV AL,[BX]
      SUB AL,[BX+1]
      PUSH AX
      PUSHF
      CALL SUB1
      POPF
      POP AX
      MOV [BX+2],AL
      HLT
START ENDP
   SUB1 PROC
   ADD AL,AL
   RET
SUB1 ENDP
CODE ENDS
END BEGIN
(四)子程序说明信息
  为了正确使用子程序,在给出子程序代码时还要给出子程序的说明信息
  子程序说明信息一般由如下部分组成:
  (1)子程序名
  (2)功能描述
  (3)入口和出口参数
  (4)所用的寄存器和存储单元
  (5)使用的算法和重要的性能指标
  (6)其他调用注意事项和说明信息
  (7)调用实例
例:写一个把16位二进制数转换为4位十六进制ASCII码的子程序
;入口参数:DX = 欲转换的二进制数
;DS:BX = 存放转换所得ASCII码串的缓冲区首地址
;出口参数:十六进制数ASCII码串按高位到低依次存放在指定的缓冲区

二.主程序与子程序间的参数传递
 1.寄存器传递法
 把参数放在约定的寄存器中,适合用于传递参数较少的情况。
例子:把大写字母改成小写字母的子程序
;子程序名 UPTOLOW
;功能:大写转换为小写
;入口参数:AL=字符ASCII码
;出口参数:AL=字符ASCII码
;说明:如果字符是大写字母,就转换为小写。否则不变
UPTOLOW PROC
 PUSHF  ;保护各标志位
 CMP AL,'A'  ;与A比较,小于A则不是大写字母
 JB UPTOLW1
 CMP AL,'Z'  ;与Z比较,大于A则不是大写字母
 JA UPTOLW1
 ADD AL,20H
UPTOLW1:POPF
UPTOLW ENDP
  
 2.约定内存单元传递法
 在传递参数较多的情况下,可利用约定的内存变量来传递参数
例子:
;子程序名:MADD
;功能:32位数相加
;入口参数:DATA1和DATA2缓冲区中分别存放要相加的32数
;出口参数:DATA3缓冲区中存放结果
;说明:(1)32位数据存放次序采用高高低低的原则
;   (2)可能产生的进位存放在DATA3开始的第5字节中
MADD PROC
PUSH AX
PUSH CX
PUSH SI
MOV CX,2 ;循环
XOR SI,SI ;清零
MADD1:MOV AX,WORD PTR DATA1[SI]
    ADC AX,WORD PTR DATA2[SI]
    MOV WORD PTR DATA3[SI],AX
    INC SI
    INC SI
LOOP MADD1
MOV AL,0
ADC AL,0
MOV BYTE PTR DATA3+3,AL
POP SI
POP CX
POP AX
RET
MADD ENDP

 3.利用堆栈传递参数
 在调用子程序之前,把需要传递的参数依次压入堆栈,子程序从堆栈取入口参数。
 如果使用堆栈传递出口参数,那么子程序在返回前,把需要返回的参数存入堆栈,
 主程序在堆栈中取出口参数。
例:写一个测量字符串长度的子程序,设字符串以0为结束标志
;子程序名:STRLEN
;功能:测量字符串的长度
;入口参数:字符串起始地址的段值和偏移值在堆栈中
;出口参数:AX=字符串长度
STRLEN PROC
  PUSH BP
  MOV BP,SP
  PUSH DS
  PUSH SI
MOV DS,[BP+6]
MOV SL,[BP+4]
MOV AL,9
STRLEN1: CMP AL,[SI]
JZ STRLEN2
INC SI
JMP STRLEN1
STRLEN2:MOV AX,SI
SUB AX,[BP+4]
POP SI
POP DS
POP BP
RET
STRLEN ENDP
(不理解,第29集)
 
 
三.DOS功能调用及应用
1.DOS功能概述
MS-DOS内包含许多设计设备驱动和文件管理方面的子程序
DOS各种命令就是通过适当的调用这些子程序实现的。
为了方便程序使用,把这些子程序编写成相对独立的程序模块并编上号
这些编了号可由程序员调用的子程序就称为DOS的功能调用或系统调用

DOS功能调用主要包括三方面的子程序:
设备驱动(基本I/O)、文件管理和其他
2.调用方法
(1)根据需调用的功能调用准备入口参数,有部分功能不需要入口参数
(2)把功能调用号送AH寄存器
(3)发软中断指令INT 21H

3.基本I/O功能调用
(1)带回显键盘输入(1号功能调用)
 (8号功能调用不带回显键盘输入)
 功能:从标准输入设备上读一字符,并将该字符回显在标准输出设备上
 如果键盘无字符可读,则一直等待有字符可读
 AL=读到字符的代码(ASCII码)
 
(2)显示输出(2号功能)
 功能:向标准输出设备写一字符。
 Ctrl+C或Ctrl+Break结束程序
 DL=要输出的字符
 补充:
 9号功能显示字符串
 DS:DX=要输出字符串的首地址
 以$结束
例子:利用2号系统功能调用完成输出线性一串字符信息
DATA SEGMENT
MSG DB 'THIS MESSAGE'
MSGLEN EQU $-MSG  ;当前地址减去字符串的首地址就是字符串的长度
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
BEGIN:MOV AX,DATA
   MOV DS,AX
   MOV CX,MSGLEN
   MOV SI,0
   MOV AH,02 ;把功能号2送到AH
NEXT:MOV DL,MSG[SI]  ;输出的字符放在DL中
   INT 21H  ;输出一个字符
   INC SI
   LOOP NEXT
   MOV AH,4CH
   INT 21H  ;返回DOS状态
CODE ENDS
 END BEGIN
如果是9号功能
必须把MSG放入DS:DX首地址
定义字符串必须以$结束
输出不需要放入DL中
 
 4.递归子程序
 必须用寄存器或堆栈传递参数,递归深度受堆栈空间的限制
例子:递归实现求阶乘
;子程序名:FACT
;功能:计算N!
;入口参数(AX)=n
;出口参数(AX)=n!
;说明(1)采用递归算法实现求阶乘
;(2)n不能超过8
FACT PROC
 PUSH DX
 MOV DX,AX
 CMP AX,0 ;N为0?
 JZ DONE ;是,转
 DEC AX ;否,n-1
CALL FACT ;求(n-1)!
  MUL DX ;n*(n-1)
  POP DX
RET
  DONE:MOV AX,1 ;0!=1
  POP DX
RET
FACT ENDP

你可能感兴趣的:(算法,汇编,dos,存储,byte,DST)