十八、使用call和ret指令实现子程序的调用和返回

来源:互联网 发布:加工中心编程教学 编辑:程序博客网 时间:2024/03/28 18:29

1. 子程序实现的基础——跳转:

    1) 汇编中的子程序即等价于C语言的函数,即实现程序的模块化;

    2) 在汇编语言中,子程序其实就是以一个标号起始,最后有类似C函数的返回指令的一段代码块,主程序可以在中途调用该代码块(其实就是跳转到子程序执行),调用结束后再从子程序返回到调用处(其实就是从子程序处跳转回调用它的地方);

    3) 也就是说子程序实现的基础就是跳转,即需要转移指令的支持;


2. 利用call和ret指令来调用子程序和从子程序返回:

    1) call的使用方法是:call 子程序入口处地址,该地址可以是标号,也可以存放在寄存器和内存中;

    2) ret的使用方法就是直接在子程序中使用ret指令即可,可以没有参数,执行该指令会直接返回至调用子程序的位置处;

    3) 这两条指令是如何实现的?

        i. 由于调用和返回都是通过跳转实现的,因此两条指令的背后肯定都修改了cs:ip;

        ii. 考虑到最后要返回至调用处,则肯定需要在调转至子程序处之前先保存好返回时的位置(即call后面一条指令的地址),待子程序运行完后再恢复该位置并赋给cs:ip,而保存和恢复的工具必然是栈了;

        iii. 因此call、ret其实是一组复合动作,其执行流程是:

call proc_addr:push ++(cs:ip)jmp -> proc_addrret:pop (cs:ip)
    4) 由于call和ret背后也是转移,因此也是要分段内跳转和段间元跳转的:

        i. 段内跳转call:

           *1. call near ptr proc_tag:等价于jmp near ptr,因此也是一种位移转移,其中near ptr可以省略,但不建议这样做,将near ptr写上可以联想到jmp near ptr,这样不会导致记忆混乱,并且使程序清晰易读;

           *2. call 16-bit-register:子程序段内偏移地址存在16位寄存器中,等价于jmp 16-bit-register,因此是直接修改ip但不修改cs;

           *3. call word ptr 内存单元:子程序段内偏移地址存在内存单元中,等价于jmp word ptr 内存单元,也是只修改ip

           *注意:它们都会在跳转之前先push ip进行备份!没有段内你短转移!

        ii. 远跳转call:直接同时修改cs:ip

            *1. call far ptr proc_tag:等价于jmp far ptr

            *2. call dword ptr 内存单元:等价于jmp dword ptr,第16位是偏移地址,高16位是段地址;

            *注意:在跳转之前都会先保存cs:ip的值,顺序是先push cs再push ip;

        iii. 段内跳转ret:直接ret即可,其实就等价于pop ip

        iv. 远跳retf:注意,远跳是retf,即return far的缩写,f不要忘了,等价于pop (ip, cs),注意和远跳的call对应(栈是后进先出的!)

    5) call和ret要对应使用,即段内跳的call就和ret配合使用,远跳的call就和retf配合使用,千万不能交叉配合使用,虽然这样编译不会报错,但是一定会发生运行时错误或者是不可预料的错误,因为段内跳push和pop16位的地址,而远跳push和pop32位的地址,交叉使用就会相差16位,从而导致cs:ip指向异常!

一定要牢记这点!


4. 乘法指令mul:

    1) mul有两种类型,一种是两个8位相乘得到一个16位的结果,另一种是两个16位相乘得到一个32位的结果;

    2) 双8位相乘:一个乘数默认放在al中,另一个乘数可以放在任意一个8位寄存器或者内存中,结果默认放在ax中;

    3) 双16位相乘:一个乘数默认放在ax中,另一个乘数可以放在任意一个16位寄存器或者内存中,结果的高16位默认放在dx中,低16位默认放在ax中;

    4) 使用格式:

; 8-bit mul 8-bitmoval, XXXmov8-bit-register/memory, XXXmul8-bit-register/memory; -> ax; 16-bit mul 16-bitmovax, XXXmov16-bit-register/memory, XXXmul16-bit-register/memory; -> [dx:ax]
    5) 示例:100 × 10和100 × 10000:

assume cs:codecode segmentdd 0start:moval, 100movah, 10mulahmovax, 100movdx, 10000muldxmovword ptr cs:[0], axmovword ptr cs:[2], dxmovax, 4C00Hint21Hcode endsend start
运行结果:

*1. ax -> 03E8H

*2. 将结果保存在了代码段开头定义的数据区中,结果是000F4240H



原创粉丝点击