《山东大学汇编语言程序设计课件第6章解读》由会员分享,可在线阅读,更多相关《山东大学汇编语言程序设计课件第6章解读(42页珍藏版)》请在金锄头文库上搜索。
1、第六章 子程序结构 6.1 子程序的设计方法 6.2 子程序的嵌套 6.3 子程序举例 主程序 子程序: 子程序:在一个实际程序中,有些操作要执行多次, 把要重 复执行(subroutine)操作编为子程序。 也常把一些常用的操作标准化、通用化的子程序 。 主程序(Main program)往往要调用子程序 或处理中断, 暂停主程序,执行子程序或中断服务程序。 模块化程序设计方法 模块化程序设计方法按照各部分程序所实现的 不同功能把程序划分成多个模块,各个模块在明确各自 的功能和相互间的连接约定后,就可以分别编制和调试 程序,最后再把他们连接起来,形成一个大程序。 子程序结构是模块化程序设计的
2、基础 调用子程序时需调用子程序时需保留内容保留内容: : 调用子程序:将调用子程序:将CALLCALL下条指令地址即下条指令地址即IPIP值保留下来值保留下来 (8086中段寄存器CS和指令指针IP), 才能保证子程序执行完后准确返回主程序继续执行。保证子程序执行完后准确返回主程序继续执行。 执行子程序时执行子程序时, 通常用到内部寄存器,执行结果会影响标志位, 必须在调用子程序之前将现状保护起来现状保护起来。 子程序嵌套或子程序递归(自调自) 保留许多信息,而且保证正确返回(且后进先出)。 后保留先取出原则(即LIFO-LAST In First out)。 6.1 子程序的设计方法 6.1
3、.1 过程(子程序)定义伪操作 过程名 PROC 属性 过程名 ENDP NEAR (FAR) 与标号类似, 是子程序入口的符号地址 CALL和RET指令的属性 (1)都有NEAR和FAR两种属性 (2)在80x86汇编程序中用PROC的类型属性来确定 过程属性的确定原则: NEAR属性:调用程序和子程序在同一代码段中 (段内调用) FAR 属性:调用程序和子程序不在同一代码段中 (段间调用) code segment main proc far call subr1 ret main endp subr1 proc near ret subr1 endp code ends code seg
4、ment main proc far call subr1 ret subr1 proc near ret subr1 endp main endp code ends 例6.1 调用程序和子程序在同一代码段中 把过 程写 成嵌 套的 形式 NEAR 例6.2 调用程序和子程序不在同一代码段中 segx segment subt proc far ret subt endp call subt segx ends ends segy segment segment call subt segy ends ends FAR FAR 子程序调用(中断调用):隐含使用堆栈保存返回地址 call ne
5、ar ptr subp (1) 保存返回地址 (2) 转子程序 (IP) subp的偏移地址 call far ptr subp (1) 保存返回地址 (2) 转子程序 (CS) subp的段地址 (IP) subp的偏移地址 (IP)(SP) (IP)(SP) (CS) 6.1.2 子程序的调用和返回 (IP)(SP) (CS) (PSW) int n (n : 中断类型号) (1) 保存现场和返回地址 (2) 转中断处理程序 (IP) (n*4) (CS) (n*4+2) 子程序返回(中断返回): (1)ret (2)iret int 21H 注意: 1、PROC的属性 2、堆栈状态 CA
6、LL调用指令(仅以16位为例) 段内直接近调用:CALL DST 执行操作: PUSH (IP) (IP)(IP)+16位位移量 段内间接近调用:CALL DST 执行操作: PUSH (IP) (IP)(EA) CALL与RET指令的复习 段间直接远调用:CALL DST 执行操作: PUSH (CS) PUSH (IP) (IP)DST偏移地址 (CS)DST段地址 段间间接远调用:CALL DST 执行操作: PUSH (CS) PUSH (IP) (IP)(EA) (CS)(EA+2) CALL与RET指令的复习 RET返回指令 段内近返回:RET 执行操作: (IP) POP ( )
7、 段内近带立即数近返回:RET EXP 执行操作: (IP) POP ( ) (SP)(SP)+D16(由EXP计算得到) 带立即数 用于调用程序调用子程序时的参数传递 CALL与RET指令的复习 段间远返回:RET 执行操作: (IP)POP ( ) (CS)POP ( ) 段间带立即数远返回:RET EXP 执行操作: (IP)POP ( ) (CS)POP ( ) (SP)(SP)+D16(由EXP计算得到) CALL与RET指令的复习 6.1.3 保存与恢复寄存器 1、为什么要有保存与恢复寄存器的操作? 调用程序和子程序所使用的堆栈会发 生冲突 ,为了避免运行发生错误 2、如何保存和恢
8、复寄存器? 1、通常使用PUSH保存和POP恢复 2、286+可以使用PUSHA/POPA,386+可以使 用PUSHAD/POPAD 3、增强功能中的USES字段 3、要对哪些寄存器保存和恢复? (1)子程序子程序中用到的寄存器应该保存 (2)负责传送参数的寄存器则不一定需要保存,特 别是用来向主程序回送结果的寄存器 subt proc far push ax push bx push cx push dx pop dx pop cx pop bx pop ax ret subt endp 保存 恢复 例: 参数传送的方式 (1)通过寄存器传送参数 (2)通过存储器传送参数 *子程序和调用程
9、序在同一程序模块中,则 子程序可直接访问模块中的变量。 (3)通过地址表传送参数地址 (4)通过堆栈传送参数或参数地址 6.1.4 子程序的参数传送 计算机处理信息时,其对象都是二进制数。 外设(显示器、打印机、键盘等) 用ASCII码与CPU 进行信息传送。 例如: (1) 在键盘上按下某一字符键 (如9),键盘接口 向键盘缓冲区送去的是该字符的ASCII码(如 39H),而不是送数字09H。 ( 2) 在文本方式下,要在显示器上显示某一字符 (如A),须将该字符的ASCII码(如41H)送显示缓 冲区,不是送数字0AH。 基础知识复习 例6.3 十进制到十六进制的转换程序 (通过寄存器传送
10、变量) decihex segment ; 1016 assume cs: decihex main proc far push ds sub ax, ax push ax repeat: call decibin ; 102 call crlf call binihex ; 216 call crlf jmp repeat ret main endp decibin proc near ; 102 mov bx, 0 newchar: mov ah, 1 int 21h sub al, 30h jl exit ; 9退出 cbw xchg ax, bx mov cx, 10d mul cx
11、xchg ax, bx add bx, ax jmp newchar exit: ret decibin endp 键盘输入 binihex proc near ; 216 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 a
12、h, 2 int 21h mov dl, 0ah mov ah, 2 int 21h ret crlf endp decihex ends end main 例6.4 累加数组中的元素(直接访问变量) data segment ary dw 1,2,3,4,5,6,7,8,9,10 count dw 10 sum dw ? data ends code segment main proc far assume cs:code, ds:data start: push ds sub ax, ax push ax mov ax, data mov ds, ax call near ptr proa
13、dd ret main endp proadd proc near push ax push cx push si lea si, ary mov cx, count xor ax, ax next: add ax, si add si, 2 loop next mov sum, ax pop si pop cx pop ax ret proadd endp code ends end start data segment ary dw 1,2,3,4,5,6,7,8,9,10 count dw 10 sum dw ? ary1 dw 10,20,30,40,50,60,70,80,90,10
14、0 count1 dw 10 sum1 dw ? data ends 如果数据段定义如下: *如果直接访问内存变量,那么累加数组ary和数组ary1中 的元素不能用同一个子程序proadd 例6.4 累加数组中的元素(通过地址表传送变量地址) data segment ary dw 10,20,30,40,50,60,70,80,90,100 count dw 10 sum dw ? table dw 3 dup (?) ; 地址表 data ends code segment main proc far assume cs:code, ds:data start: push ds sub a
15、x, ax push ax mov ax, data mov ds, ax mov table, offset ary mov table+2, offset count mov table+4, offset sum mov bx, offset table call proadd ret main endp proadd proc near push ax push cx push si push di mov si, bx mov di, bx+2 mov cx, di mov di, bx+4 xor ax, ax next: add ax, si add si, 2 loop next mov di, ax pop di pop si pop cx pop ax ret proadd endp code ends end start ary 10 0000 20 0002 30 40 50 60 70 80 90 100 count 10 0014 sum ? 0016 table 0000 0018 (bx) 0014 00