第六章 子程序结构

合集下载

第六章 子程序结构

第六章  子程序结构

第六章 子程序结构一、主程序与子程序的概念子程序又称为过程,它相当于高级语言中的过程和函数。

通常,凡是具有相对独立功能的程序段或需要多次应用的程序段都可以编制成子程序。

程序中当需要这段程序时,用调用指令CALL 转到这段程序中去,执行完毕,通过RET 指令返回原来的程序。

如下图(1)所示。

子程序返回后,从CALL 的下一条指令X 1继续执行主程序。

使用子程序优点:节省编程时间和存储空间,有利于设计一个大而复杂的程序。

即可以把一个大而复杂的程序设计成由一个主程序和若干个子程序组成,使用模块化程序设计,减少程序设计复杂性。

使用子程序不足之处:在调用和返回时要进行堆栈操作,增加CPU 开销,使程序速度减慢。

继续SURENDP X 1: (1)主程序与子程序的关系(2)子程序嵌套调用主程序与子程序的概念是相对的。

图(2)是一个子程序嵌套调用的例子。

图中,程序1在A、B两处调用程序2,在C处调用程序3,则称程序2和3是程序1的子程序,程序1是主程序;而程序2和3又分别调用程序4,则称程序4是程序2和3的子程序,程序2和3是主程序。

这就是子程序中嵌套子程序。

子程序还可以直接或间接调用自己,称为递归子程序和递归调用。

二、调用指令CALL 和返回指令RET(参见指令系统p.98)CALL 调用指令RET 返回指令由于子程序和调用程序可以在同一个段中,也可以不在同一段中,因此这两条指令的格式如下:1、调用指令CALL DSTCALL指令语句实现子程序(即过程)的调用。

调用结束后,要由所调用的子程序RET指令返回到CALL指令的下一条指令(即返回调用断点),因此执行CALL指令时要进行进栈操作。

具体分为直接调用和间接调用。

直接调用:目标地址直接出现在CALL指令语句中,DST就是过程名(即子程序名)。

间接调用:由16位通用寄存器或者存储单元提供调用地址。

(1)段内直接调用格式:CALL DST执行的操作:Push(IP) ;当前IP值进栈(IP)←(IP)+D16;目标地址装入IP,程序转移指令操作分二步:第一步,是把子程序的返回地址(即调用程序中CALL指令的下一条指令的地址)存入堆栈中,以供子程序返回主程序时使用。

汇编语言:第6章子程序结构

汇编语言:第6章子程序结构

3、通过地址表传达变量地址
问题提出
如果数据段中有两个数组如下: data segment ary dw 100 dup(?) count dw 100 sum dw ? num dw 100 dup(?) n dw 100 total dw ? data ends 要求分别累加ARY和NUM数组的内容,如何进行?
主程序
main proc far assume cs:code, ds:data start: push ds ;{修改 xor ax,ax push ax mov ax, data mov ds,ax ;修改} call near ptr proadd ret ;修改 main endp
子程序Proadd
• 模块1 Extrn var2:word,lab2:far Public var1,lab1,var4 Data1 segment var1 db ? var3 dw ? var4 dw ? Data1 ends Code1 segment
Main proc far Start:
next: add ax, [si] ;compute sum add si, 2 loop next mov [di],ax ;store result pop di ;restore registers pop si pop cx pop ax pop bp ret 6 ;adjust stack and return proadd endp code2 ends end start
调用与返回
call far ptr proadd lab: Ret main endp code1 ends
code2 segment assume cs: code2 proadd proc far Push bp ;保存 BP mov bp, sp ; 用BP 作为基准参数 push ax ;save other registers push cx push si push di mov si, [bp+0ah] ;取 ary地址 mov di, [bp+8] ; 取 count地址 mov cx, [di] ; 取长度CX <- - (count) mov di, [BP+6] ;取 sum地址 xor ax, ax ;clear AX

第六章 子程序结构

第六章  子程序结构

• • • • • • • • • • •
CODE SEGMENT ASSUME DS : DATA , CS : CODE , SS : STACK START: MOV AX,DATA MOV DS,AX MOV DX,0 MOV DL,NUM8 ;转换二进制数送DX MOV CX,8 ;置位数8 LEA DI,ASCBUF ;字符串首址→DI CALL BTASC ;调用子程序BTASC MOV [DI],BYTE PTR 0DH MOV [DI+1],BYTE PTR 0AH
• • • • • • • • • STACK SEGMENT STACK DB 200 DUP(0) STACK ENDS DATA SEGMENT N DW 5 RESULT DW ? DATA ENDS CODE SEGMENT ASSUME CS:CODE, SS:STACK,DS: DATA
• 【例】试编制计算N! (N≥0)的程序。N!=N* (N-1)*(N-2)*……*1 • 其递归定义如下: • 0!=1 • N!=N*(N-1)! (N>1) • 计算N!的子程序FACT的流程图如图4.10所示。
【例】计算5!的程序示例, RESULT是保存阶乘的存 储单元。 程序如下:
子程序设计方法
• 信息的保护与恢复 • 主程序与子程序参数传递方式
信息的保护与恢复

• • • • • •
例如:若子程序PROG中改变了寄存 器AX,BX,CX,DX的值,则可采用 如下方法保护和恢复现场。 PROG PROC PUSH AX PUSH BX PUSH CX ;保护现场 PUSH DX ┆
• • • •
• • • • • •
入口参数:DX存放待转换的二进制数 CX存放待转换数的位数(8位或16位) DI存放ASCII码首地址 出口参数:转换后的字符串存放在以DI作指针的字 节存贮区中 程序如下: DATA SEGMENT NUM8 DB 93H NUM16 DW 0ABCDH ASCBUF DB 20 DUP(0) DATA ENDS

第六章 子程序结构

第六章  子程序结构

PUBLIC伪指令 (1) PUBLIC伪指令 格式: 符号] 格式:PUBLIC 符号 [,符号] 功能:说明其后的符号是全局符号。 功能:说明其后的符号是全局符号。 全局符号能被其他模 块引用。 局部符号) 块引用。(局部符号) EXTRN伪指令 (2) EXTRN伪指令 格式: 符号: 符号:类型] 格式:EXTRN 符号:类型 [,符号:类型] 功能:说明在本模块中需要引用的、 功能:说明在本模块中需要引用的、 由其他模块定义的符 号,即外部符号。
pop ax pop bp ret 6 Proadd endp Code2 ends end start
Sp
sp
(Sp→)bp
di si cx ax bp
IP CS
Sp Sp Sp
[bp+06h] [bp+08h] [bp+0ah]
Sum地址 地址 Count地址 地址 Ary地址 地址
Sp
5
多个模块之间的参数传送问题
Crlf
Crlf
proc near mov ah, 2 mov dl, odh int 21h mov dl, oah int 21h ret endp
Decihex ends
end repeat
2 如果过程和调用过程在同一源文件(同一模块)中, 如果过程和调用过程在同一源文件(同一模块) 则过程可直接访问模块中的变量。 则过程可直接访问模块中的变量。
; source module 1 extrn var2:word,lab2:far public var1,lab1 Data1 segment var1 db ? var3 dw ? var4 dw ? Data1 ends code1 segment assume cs:code1,ds:data1 Main proc far start: mov ax , data1 mov ds,ax … lab1: lab1: … mov ah,4ch int 21h Main endp Code1 ends End start

第六章子程序结构

第六章子程序结构
ROM-BIOS也以中断服务程序的形式,向程序 员提供系统的基本输入输出程序
汇编语言程序设计需要采用系统的各种功能程 序
充分利用操作系统提供的资源是程序设计的一 个重要方面,需要掌握
功能调用的格式
通常按照如下4个步骤进行:
在AH寄存器中设置系统功能调用号 在指定寄存器中设置入口参数 执行指令INT 21H实现中断服务程序的功
xchg ax,bx mov cx,10d mul cx xchg ax,bx add bx,ax jmp newchar Exit: ret Decibin endp
四、子程序参数的传递
Binhex proc near
mov ch,4
rotate:
mov cl,4 rol bx,cl mov al,bl and al,0fh add al,30h
cmp al,3ah jl printit add al,7h
printit: mov dl,al mov ah,2 int 21h dec ch jnz rotate ret
binihex endp
四、子程序参数的传递
Crlf proc near mov dl,0dh mov ah,2 int 21h mov dl,0ah mov ah,2 int 21h ret
Main proc far Repeat :call decibin
call crlf call binihex call crlf jmp repeat Main endp
… …
Decihex ends end main
四、子程序参数的传递
Decibin proc near mov bx,0
newchar: mov ah,1 int 21h sub al,30h jl exit cmp al,9d jg exit cbw

第6章_子程序结构(书)

第6章_子程序结构(书)




CODE SEGMENT ASSUME DS : DATA , CS : CODE , SS : STACK START: MOV AX,DATA MOV DS,AX MOV DX,0 MOV DL,NUM8 ;转换二进制数送DX MOV CX,8 ;置位数8 LEA DI,ASCBUF ;字符串首址→DI CALL BTASC ;调用子程序BTASC MOV [DI],BYTE PTR 0DH MOV [DI+1],BYTE PTR 0AH
del_ul proc far Cld ;DF=0时,向前查找。 Push di ;右起始地址; Mov cx, es:[di] ; 取元素数; Add di , 2 ; 改变指针。 Repne scasw Jz delete ; 结果为0,ZF=1.转 ,此时CX值减少1 Pop di Jmp short exit Delete: jcxz deccnt ;为最后元素?cx剩下未比较个数 Next: mov bx, es:[di] ;元素向低地址移动一个字. Mov es:[di-2],bx add di ,2 ;指向另一个元素 loop Next ;重复,直到所有全移动 deccnt : pop di dec word ptr es:[di] ; 总元素数-1 exit: ret del_ul endp

【例6.12】将一个给定的二进制数按位转换 成相应的ASCII码字符串,送到指定的存储单 元并显示。如二进制数10010011转换成字符 串为‘10010011‟。要求将转换过程写成子程 序,且子程序应具有较好的通用性,而必须 能实现对8倍和16倍二进制数的转换。
入口参数:DX存放待转换的二进制数 CX存放待转换数的位数(8位或16位) DI存放ASCII码首地址 出口参数:转换后的字符串存放在以DI作指针的字 节存贮区中 程序如下: DATA SEGMENT NUM8 DB 93H NUM16 DW 0ABCDH ASCBUF DB 20 DUP(0) DATA ENDS

第6章 子程序结构

第6章  子程序结构

6.1 子程序的设计方法
子程序设计
把功能相对独立的程序段单独编写和调试,作为一个相对独立的 模块供程序使用,就形成子程序。
子程序可以实现源程序的模块化,可简化源程序结构,可以提高 编程效率。
3/37
子程序设计要利用过程定义伪指令 参数传递是子程序设计的重点和难点
子程序可以嵌套; 一定条件下,还可以递归和重入
12/37
6.1 子程序的设计方法
(3)用堆栈传递参数
.startup mov ax, offset array push ax mov ax, count push ax call checksumc add sp, 4 mov result, al .exit 0
13/37
要注意堆栈的分配情况,保证参数存取正确、子程序正 确返回,并保持堆栈平衡
6.1 子程序的设计方法
6.1.1 过程定义伪操作
过程名 过程名 proc [near|far] ... endp
4/37
过程名(子程序名)为符合语法的标识符,子程序入口的符号地址; NEAR/FAR属性 NEAR(段内近调用):调用程序和过程在同一代码段中 FAR(段间远调用):调用程序和过程不在同一代码段中 用户可以在过程定义时用near或far改变缺省属性
23/37
; 显示单个字符的功能号是2 ; 键盘输入单个字符的功能号是1 ; DOS中断号
1h 21h
main assume start: push sub push call call call call …… ret main
proc far cs:hexidec
ds
ax,ax ax hexibin crlf binidec crlf

汇编语言程序设计第六章 子程序结构

汇编语言程序设计第六章   子程序结构

20016H
20018H
SP
BX AX
IP CS
2001AH

DX CX BX AX ENDP
2001CH 2001EH
20020H
11
6.1.3 保存与恢复寄存器
先看一个例子(如图): SUBT PROC FAR PUSH AX PUSH BX PUSH CX PUSH DX
POP POP POP POP RET SUBT
DX CX
20016H
20018H 2001AH
BX AX
IP CS

DX CX BX AX ENDP
2001CH 2001EH
20020H
8
下一页
6.1.3 保存与恢复寄存器
先看一个例子(如图): SUBT PROC FAR PUSH AX PUSH BX PUSH CX PUSH DX
POP POP POP POP RET SUBT
18
newchar: mov int sub jl cmp jg cbw ;(digit is now in ;multiply number xchg mov mul xchg add jmp exit: ret DEC2BIN endp ah,1 21h al,30h exit al,9d exit ;keybroad input ;call DOS ; ASCⅡ to binary ;jump if<0 ;is it >9d? ;yes,not dec digit ;byte in AL to word in AX
stack_seg
tos stack_seg ; dw label
segment 100 dup(?) Word;教材P132 ends

第6章 子程序结构

第6章 子程序结构

Lea dx,string地址 地址(IP) 地址 Num string地址 地址
2010-12-28 ch6
从键盘取得十进制 保存到BX BX中 数,保存到BX中 显示回车和换行 用十六进制形式 显示BX BX中的数 显示BX中的数
7
计算机科学与技术系
《汇编语言》 汇编语言》
Decihex
segment
assume cs:Decihex Main proc far Repeat: push ds xor ax, ax push ax call decibin call crlf call binihex call crlf ret Main endp
通过堆栈传递地址或参数
计算机科学与技术系
《汇编语言》 汇编语言》
Binhex proc near push bp mov bp,sp push ax push di push bx push cx pushf mov ax, [bp+4] mov di, [bp+6] mov ch, 4 mov cl, 4 roat: rol ax ,cl mov bl, al and bl, 0fh add bl, 30h cmp bl, 39h jle next add bl, 7h 2010-12-28
;每次乘的 每次乘的
;结果在 中 结果在BX中 结果在
8
计算机科学与技术系
《汇编语言》 汇编语言》
Binihex proc near mov ch, 4 Rotate: mov cl, 4 rol bx, cl mov dl, bl and dl, 0fh add dl, 30h cmp dl, 3ah jl print add dl, 7h Print: mov ah, 2 int 21h dec ch jnz rotate ret 2010-12-28 Binihex endp

第6章 子程序结构2013.ppt.Convertor

第6章 子程序结构2013.ppt.Convertor

1第六章子程序结构三、子程序参数传递参数:入口参数: 在子程序中被处理的数据出口参数: 表示子程序处理结果的数据(1) 通过寄存器传送参数(2) 通过存储器传送参数(3) 通过堆栈传送参数或参数地址(4)*多个模块之间的参数传送软延时:指利用CPU 执行指令需要耗费一定时间的特点实施的延时,常用减1循环来实现。

例:8088CPU ,主频4.77M ,每个时钟周期为:1/4.77M = 0.21μs 。

循环指令LOOP ,当CX 不为零时,执行循环转移分支,占用17个时钟周期;当CX 为零时,退出循环,占用5个时钟周期。

如果CX 初值是2801时,执行指令W AIT1:LOOP W AIT1,所需时间为:(0.21×2801)×17 + 0.21 ×5 ≈ 10ms子程序调用,实现100ms、550延时CSEG SEGMENTASSUME CS:CSEG,……MAIN PROC FARPUSH DSSUB AX,AXPUSH AX……MOV BX,10 ;延时100ms,参数赋值CALL DELAY ;调用延时子程序MOV BX,55 ;延时550ms,参数赋值CALL DELAY ;调用延时子程序……RETMAIN ENDP例:十六进制到十进制的转换(通过寄存器传送参数)assume cs: hexidecmain proc farstart: push dssub ax, axpush axrepeat:call crlfcall crlfjmp repeat retmain endp ………………hexidec ends end start如果数据段定义如下:data segmentary dw 1,2,3,4,5,6,7,8,9,10count dw 10sum dw ?ary1 dw 10,20,30,40,50,60,70,80,90,100count1 dw 10sum1 dw ?data ends如果直接访问内存变量,那么累加数组ary和数组ary1中的元素不能用同一个子程序proadd。

第六章子程序结构

第六章子程序结构

6.4.3、堆栈传递参数 子程序可以利用堆栈传递参数。例如C语言中,函数的参数传递就是利用堆栈。 首先要了解堆栈的构造和工作原理: 堆栈段使用段寄存器SS。在CALL指令、RET指令、PUSH指令、POP指令中, 按照“后进先出”的原则工作,并使用SP寄存器内容为堆栈顶偏移量指令。 使用BP为指针存取数据,默认的段寄存器也是SS,因此,BP也常常用来作存 取堆栈中数据的偏移量指针。 堆栈顶是变化的,随着压栈操作,堆栈顶向低地址方向生长。 压栈操作,堆栈顶向低地址方向生长 压栈操作 对堆栈的压栈操作和弹出堆栈操作必须平衡。
例:在数据串STR1中有20个字数据,数据串STR2中有5个字数据,编程。在 STR1中查找子串STR2,找到则把BL置为1,否则把BL置为0。 先编一个比较字数据串的子程序CMPSTR。 子程序名:CMPSTR 功能:把STR2与SI指到的字数据串比较(只比较前5个元素),相同则返回ZF= 1,否则返回ZF=0。 入口参数:SI指到一个数据串。 出口参数:两个串相同则返回ZF=1,否则返回ZF=0 程序: CMPSTR: LEA DI,STR2 MOV CX ,5 CLD REPZ CMPSW RET
SP
×× ×× ## ## %% SP %% ◎◎ ◎◎
ARY 地址 COUNT 地址 SUM 地址
×× ×× ## ## %% %% ◎◎ ◎◎
低地址
问题:取堆栈中的数据能否使用BX、SI、DI作指针? 答:可以,但是必须用段超越。如: PROADD PROC NEAR
MOV SI,SP MOV MOV SUB LP: ADD INC INC LOOP MOV MOV RET PROADD ENDP BX,SS:[SI +6] ;取ARY首地址 C X,SS:[SI+4] ;取数据个数 AX ,AX AX,[BX ] BX BX LP BX,SS:[SI+2] ;取SUM地址 [BX] ,AX 6 ;存和数 ;返回,并且使SP=SP+6

汇编第06章子程序结构

汇编第06章子程序结构
20122012-5-21 7
2、子程序结构 、 (1)同一代码段 ) Code segment Main proc far …… Ret Main Endp Sub1 Proc Near …… Ret Sub1 Endp Code Ends
20122012-5-21
(2)不同代码段 ) Code segment Sub proc far …… Ret Sub Endp …… Call Sub …… Code Ends Code1 Segment …… Call Sub Sub1 Endp
20122012-5-21
• 过程名在整个程序中必须是唯一的。 过程名在整个程序中必须是唯一的。 • 过程名本质上与标号一样,也具有3种属性:段地 过程名本质上与标号一样,也具有 种属性: 种属性 偏移地址和类型( 址、偏移地址和类型(NEAR或FAR)。 或 )。 • PROC后用关键字 后用关键字NEAR、FAR或空,以表示过程 或空, 后用关键字 、 或空 的类型(缺省为NEAR)。 的类型(缺省为 )。 • 原则:同一代码段用 原则:同一代码段用Near • 不同代码段用 不同代码段用Far 11
SUB1
PROC MOV AX,1 AGAIN:MUL CX LOOP AGAIN RET SUB1 ENDP
20122012-5-21
16
DATA SEGMENT M EQU 8 N EQU 3 RES DW ? DATA ENDS CODE SEGMENT ASSUME CS:CODE,DS:DATA : , : START:MOV AX,DATA : , MOV DS,AX , MOV CX,N , CALL SUB1 MOV BX,AX , MOV CX,M , CALL SUB1 DIV BX ;M!/N! ! ! MOV BX,AX , MOV CX,M , SUB CX,N , CALL SUB1 ;(M-N)! ;( )! XCHG BX,AX , DIV BX MOV RES,AX , MOV AH,4CH , 2012-INT 2012-5-21 21H

子程序结构

子程序结构

第六章子程序结构§6.1 子程序的设计方法一、过程定义伪指令格式:〈过程名〉PROC NEAR、FAR……RET〈过程名〉ENDP指令组中至少有一个返回指令,通常用RET过程名是子程序的地址符号名,与段名、变量名等定义和作用类似。

子程序的调用使用CALL指令,返回使用RET指令。

过程名是CALL指令的操作数,有三个属性:段地址、偏移地址和类型,类型有两种:NEAR , FAR。

其中NEAR为缺省。

其类型决定了CALL和RET指令的目标码是段内或段间调用或返回。

CALL的寻址方式和JMP相似,它们都是对地址的修改。

书P80,吴秀清书P104。

调子程序的格式:段内调用及返回(修改IP单字操作)CALL PROG_N(过程名);CALL BX;CALL WORD PTR [BX+SI+D]RETRET n段间调用(修改IP CS 双字操作)CALL FAR PTR PROG_F(过程名)CALL DWORD PTR [BX+SI+D]RETRET n子程序在程序中的应用:举例L600.doc二、子程序的调用与返回1、调用:CALL2、返回:RETRET n三、编程原则1、类型定义:主程序为FAR型,子程序调用与定义在同一代码段的用NEAR;调用与定义在不同代码段的用FAR2、程序结构✓主程序与子程序顺序排列:一般主程序在前,子程序在后。

✓子程序中的堆栈操作一定要匹配PUSH指令,及对象和POP指令对应。

3、入口/出口参数及现场保护入口参数:调用者提供给子程序的信息出口参数:子程序运行后,返给调用者的信息。

参数传递:调用者与子程序之间信息传递的方法。

由于寄存器数量有限,为了避免冲突,提高子程序的通用性,所以编写子程序时应保护除入口/出口参数之外所用到的所有寄存器。

4、子程序说明子程序名、功能、入口参数、出口参数、执行时间等四、参数传递方法:✧寄存器传送✧变量传送✧参数表传送✧堆栈传送1、用寄存器传送:适用于参数较少的情况,即入口参数例如书200,例6.3题,子程序DECIBIN从键盘输入的数放在BX中,主程序在调用子程序BINIHEX前,是让它将BX的内容转换为十六进制显示。

第六章 子程序结构

第六章  子程序结构
IBM-PC汇编语言程序设计 汇编语言程序设计
第六章: 第六章: 子程序结构
子程序(过程)也是程序设计中常用的方法.子程序结构是模块化程序设计的 重要工具.设计子程序主要考虑参数传递的方法,因为参数传递是主程序和子程 序之间的接口.通常进行主程序和子程序间参数传递的方法有三种,即利用寄存 器传递参数、利用堆栈传递参数和利用存储单元传递参数。在设计子程序时 应根据实际情况选择合适的参数传递方法。本章还介绍了最常用的DOS系统 功能调用。
本章重点: 本章重点:
1)子程序的概念、基本结构形式、子程序的现场保护和恢复及子程 序的调用和返回。 2)子程序设计的步骤和方法。掌握主程序与子程序之间调用和返回 的程序流程。 3)主程序和子程序间传递参数的三种方法,能够利用参数传递的不 同方法编制合适的子程序。 4)常用DOS系统功能调用的方法,利用系统功能调用编制简单的输 入输出程序。 具体课件内容请看:第六章 子程序结构.doc
ቤተ መጻሕፍቲ ባይዱ

第6章 子程序结构

第6章  子程序结构

第6章 子程序结构
(2) 通用性。只能完成特定功能的子程序用处不大, 例如,只能实现5个字节加法运算的多字节加法子程序 和只能在定长字符串上查找某一固定字符的子程序都 没有通用性,因而用处也就不大。要能够得到广泛应 用的通用的多字节加法子程序,字节数应该是任意的, 字符查找子程序、字符串的长度和查找的字符都应是 任意的。
第6章 子程序结构
6.1 子程序的概念
6.1.1 子程序概念 把可以多次调用、能够完成特定操作功能的程序
段编写成独立的程序模块,该程序模块称为子程序, 又称为过程。调用这些子程序的程序称为主程序。在 主程序中,如果调用到子程序,就需要把控制转移到 子程序,这个过程称为转子。子程序执行完了,要把 控制再返回到主程序,这个过程称为返主。主程序与 子程序之间的关系如图6.1所示。
从 80286 CPU 开 始 可 用 的 PUSHA/POPA 指 令 和 从 80386 CPU开始的高档微机可用的PUSHAD/POPAD指令 为子程序中保存和恢复寄存器内容提供了有力的支持。
第6章 子程序结构
6.3 子程序的参数传送
主程序在调用子程序时,经常需要传送一些参数 给子程序,子程序运行完后也经常要回送一些信息给 主程序。这种调用程序和被调用程序之间的信息传送 称为主—子程序参数传送(或称变量传送和过程通信)。 以下介绍参数传送的常用方式。
第6章 子程序结构
【例6-3】 保护现场与恢复现场示例。
SUBT PROC
PUSH AX
;现场保护
PUSH BX
PUSH CX
PUSH DX
<子程序体>
第6章 子程序结构
POPDX POPCX POPBX POPAX RET SUBT ENDP
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
段间间接远调用:CALL DST 执行操作: (SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (CS) (SP) ← (SP) - 2 ( (SP)+1,(SP) ) ← (IP) (IP) ← (EA) (CS) ← (EA+2)
2.子程序返回指令RET 返回指令为子程序最后执行的指令,作用为断点出
LENTH DW
?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: MOV AX,DATA
MOV DS,AX
LEA SI,STRG
;SI为字符串首地址,作入口参数
CALL SCONT
;调用子程序
MOV LENTH,BX
;保存结果
MOV AH,4CH
INT 21H
第六章 子程序结构
§6.1 子程序的设计方法 §6.2 嵌套与递归子程序 §6.3 子程序举例 §6.4 DOS系统功能调用
§6.1 子程序的设计方法
➢把功能相对独立的程序段单独编写和调试, 作为一个相对独立的模块供程序使用,就形 成子程序 ➢子程序可以实现源程序的模块化,可简化 源程序结构,可以提高编程效率
SCONT NEXT:
OVER: SCONT CODE
PROC XOR CMP JZ INC INC JMP
RET ENDP ENDS END
NEAR BX,BX BYTE PTR [SI],-1 OVER BX SI NEXT
START
;BX寄存器用于统计结果 ;是否结束标志 ;是则转OVER ;统计 ;修改地址指针
分析:本题子程序的功能是统计字符串长度,只需要将被 统计字符串的首地址作为入口参数传递给子程序即可。统计的 结果放在某个寄存器如BX返回即可。程序如下:
地址 …… STRG →
元素序号 ←(si) [0号元素] 1号元素 2号元素
…… -1
…… n号元素
……
字符偏移量:SI 字符个数:BX
1、初始化: (1)、让si指向首字符 2、统计字符个数: (1)、初始化BX: (BX) ←0 ;用BX存储字符个数 (2)、判断字符是否已经统计完,判断:[SI]=-1?
三、子程序的调用与返回
如果过程的属 性是far属性, 则对它的调用 和返回也是far 属性的;如果
过程的属性是 near属性,则 对它的调用和 返回也是near 属性的。
主程序
CALL 子程序名
子程序
RET
回到CALL指令后的 指令处——返回地址
code segment assume cs:code
例:带立即数返回
code main
main
segment proc far …… push ax push bx push cx call sub …… ret endp
sub
sub code
proc near
…… ret 6 endp ends
(SP) (SP)
(IP) (cx) (bx) (ax)
一、子程序指令 二、子程序的调用与返回 三、现场的保护与恢复 四、子程序参数的传递
一、过程定义伪操作
使用格式: 过程名 PROC
属性
可以是:near或far
过程代码
过程名 ENDP
属性的确定:
NEAR属性(段内近调用)的过程只 能被相同代码段的其他程序调用FAR 属性(段间远调用)的过程可以被相
同或不同代码段的程序调用
assume cs:procedure input proc far
mov ah,1 int 21h ret input endp output proc far mov dl,al mov ah,2 int 21h ret output endp procedure ends end a
三、子程序的调用与返回
A、判断:输入字符<‘A’? a.是:转2(3); b.否: 判断:输入字符>‘Z’? 是:转2(3); 否:输入字符ASCLL码+20H;
(3) 、把字符存储到si所指向的单元中:[si] ←字符; (4)、修改si,让si指向下一个存储单元:(si) ← (si) +1; (5)、转2(1); 4、结束 。
code ends end a
过程定义也可以嵌套,一个过程定义中可以包括多个过程定义。
Main proc far ;调用程序 …… call subr1 …… ret subr1 proc near ;过程subr1
…… ret subr1 endp main endp
调用程序和过程不在同一个代码段中
从子程序返回主程序,(SP+i16)用以释放参数所占的堆栈单元。 段内带立即数近返回:RET EXP段间远返回:RET 执行操作: (IP) ← ( (SP)+1,(SP) )
(SP) ← (SP) + 2 (CS) ← ( (SP)+1,(SP) ) (SP) ← (SP) + 2
段间带立即数远返回:RET EXP
堆栈段
调用程序和过程在同一个代码段中
Main proc far
…… call subr1
…… ret main endp
…… subr1 proc near
…… ret subr1 endp
;过程subr1
由于调用程序MAIN和子程序SUBR1是在 同一代码段中的,所以SUBR1定义为NEAR属 性。这样,MAIN中对SUBR1的调用和SUBR1 中的RET就都是NEAR属性的。但是一般说来, 主过程MAIN应定义为FAR属性,这是由于我们 把程序的主过程看作DOS调用的一个子过程, 因而DOS对MAIN的调用以及MAIN中的RET就 是FAR属性的
子程序的正确调用和正确返回可以保证过程的正确执行,当主程序(调用程 序)需要执行这个功能时,采用CALL调用指令转移到该子程序的 起始处执行;当运行完子程序功能后,采用RET返回指令回到主程 序继续执行
为保证其正确性,除PROC的属性要正确选择外,应该注意子程序运行期间的堆 栈状态。
由于CALL时已使返回地址入栈,所以RET时应该使返回地址出栈。如果子程 序中不能正确使用堆栈而造成执行RET前SP并未指向进入子程序时的返回地址, 则必然会导致运行出错。
①、是:结束循环,转3; ② 、否:
a、 字符个数加1 :(BX) ← (BX) +1;
b 、修改si以便让其指向下一个字符: (SI) ←(SI)+1 ;
c、转2(2); 3、把字符个数存入LENTH中: LENTH ← (BX) 。
DATA SEGMENT
STRG DB ‘HFEUWINFD4632*%587fdjljowjo#$4’,-1
code ends end a
三、子程序的调用与返回
—书写形式(同一代码段)
三、子程序的调 用与返回
—书写形式 (不同代码段)
段内调用
供段内调用的子程序必须被定义为NEAR类型,并与主程序位于 同一个代码段中。子程序的位置通常在主程序的所有可执行指令 之前或之后,不能放在主程序的可执行指令序列内部,否则会破 坏主程序结构。 【例5.1 】在以STRG为首地址的缓冲区中存放着一个字符串, 以-1作为结束标志,编程统计字符串长度,并将结果存入 LENTH单元。要求统计字符串用子程序完成。
段内间接近调用:CALL DST 执行操作: (SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (IP) (IP) ← (EA)
段间直接远调用:CALL DST 执行操作: (SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (CS) (SP) ← (SP) - 2 ( (SP)+1,(SP) ) ← (IP) (IP) ← 偏移地址 (CS) ← 段地址
段间调用
供段间调用的子程序必须被定义为FAR类型,并与主程序位 于不同的代码段中,也可分属于不同的模块。
【例5.2 】从键盘上输入一个长度小于100的字符串,存入以 BUFF为首地址的缓冲区,其中如有大写字母,要求用子程序转 换为小写字母,字符串以回车键作为结束。
分析:本例中子程序以远程子程序的方式书写,它单独占 用一个代码段。子程序的功能是将大写字母转换为小写字母, 方法是大写字母的ASCII码加上20H。程序如下:
地址 BU[第0个字符]
第1个元素 第2个元素
……
…… 第99个元素
……
字符偏移量:SI
1、初始化: (1)、让si指向首字符 2、大写字符转小写字符: (1)、输入一个字符; (2)、判断刚才的输入是否为回车:输入字符=0DH?
①、是:结束,转4; ② 、否:
转换:判断所输入字符是否为大写字符:
Segx segment ……
subt proc far …… ret
subt endp ……
SUBT为一过程,它在两处被调用,一处 是与它在同一段的SEGX段内,另一处是 在另一段SEGY段内。为此,SUBT必须具 有FAR属性以适应SEGY段调用的需要。 SUBT既然有FAR属性,则不论在SEGX段 或SEGY段,对SUBT的调用就都具有FAR 属性。
call subt ;调用程序和过程在同一个代码段中
……
Segx ends
Segy segment
……
call far ptr subt ;调用程序和过程不在同一个代码段中
……
Segy ends
code segment assume cs:code
a: call far ptr input call far ptr output mov ax,4c00h int 21h code ends procedure segment
相关文档
最新文档