10.1 ~ 10.7

2020-11-05
2020-11-05
3 min read
Hits

  《汇编语言(第3版)》10.1 ~ 10.7、《零基础入门学习汇编语言》P47 ~ 49

第十章 Call 和 Ret 指令

  call 和 ret 指令都是转移指令,它们都修改 IP,或同时修改 CS 和 IP。

  它们经常被共同用来实现程序的设计。

10.1 ret 和 retf

  ret 指令用栈中的数据,修改 IP 的内容,从而实现近转移。

  CPU 执行 ret 指令时,进行下面的两步操作

  1. (IP)=((ss)*16+(sp))
  2. (sp)=(sp)+2

  retf 指令用栈中的数据,修改 CS 和 IP 的内容,从而实现远转移;

  CPU 执行 retf 指令时,进行下面几步操作

  1. (IP)=((ss)*16+(sp))
  2. (sp)=(sp)+2
  3. (cs)=((ss)*16+(sp))
  4. (sp)=(sp)+2

  可以看出,如果我们用汇编语法来解释 ret 和 retf 指令,则

  1. CPU 执行 ret 指令时,相当于进行

    pop IP
    
  2. CPU 执行 retf 指令时,相当于进行

    pop IP
    pop CS
    

10.2 call 指令

  call 指令经常跟 ret 指令配合使用,因此 CPU 执行 call 指令,进行两步操作

  1. 将当前的 IP 或 CS 和 IP 压入栈中;
  2. 转移(jmp)。

call 指令不能实现短转移,除此之外,call 指令实现转移的方法和 jmp 指令的原理相同。

10.3 依据位移进行转移的 call 指令

  call 标号(将当前的 IP 压栈后,转到标号处执行指令)

  CPU 执行此种格式的 call 指令时,进行如下的操作

  1. (sp)=(sp)-2
  2. ((ss)*16+(sp))=(IP)
  3. (IP)=(IP)+16 位位移

  16 位位移 =“标号”处的地址 -call 指令后的第一个字节的地址;

  16 位位移的范围为 -32768~32767,用补码表示;

  16 位位移由编译程序在编译时算出。

  从上面的描述中,可以看出,如果用汇编语法来解释此种格式的 call 指令。则

  CPU 执行指令“call 标号”时,相当于进行

push IP
jmp near ptr 标号

10.4 转移的目的地址在指令中的 call 指令

  call 指令,其对应的机器指令中并没有转移的目的地址,而是相对于当前 IP 的转移位移。

  指令“call far ptr 标号”实现的是段间转移。

  CPU 执行“call far ptr 标号”这种格式的 call 指令时的操作

  1. (sp)=(sp)-2
  2. ((ss)×16+(sp))=(CS)
  3. (sp)=(sp)-2
  4. ((ss)×16+(sp))=(IP)
  5. (CS)= 标号所在的段地址
  6. (IP)= 标号所在的偏移地址

  从上面的描述中可以看出,如果我们用汇编语法来解释此种格式的 call 指令,则

  CPU 执行指令“call far ptr 标号”时,相当于进行

push CS
push IP
jmp far ptr 标号

10.5 转移地址在寄存器中的 call 指令

  指令格式:call 16 位寄存器

  功能

  1. (sp)=(sp)-2
  2. ((ss)×16+(sp))=(IP)
  3. (IP)=(16 位寄存器)

  汇编语法解释此种格式的 call 指令,CPU 执行 call 16 位 reg 时,相当于进行

push IP
jmp 16 位寄存器

10.6 转移地址在内存中的 call 指令

  转移地址在内存中的 call 指令有两种格式

  1. call word ptr 内存单元地址

    1. 汇编语法解释

      push IP
      jmp word ptr 内存单元地址
      
    2. 示例

      mov sp,10h
      mov ax,0123h
      mov ds:[0],ax
      call word ptr ds:[0]     # 执行后,(IP)=0123H,(sp)=0EH
      
  2. call dword ptr 内存单元地址

    1. 汇编语法解释

      push CS
      push IP
      jmp dword ptr 内存单元地址
      
    2. 示例

      mov sp,10h
      mov ax,0123h
      mov ds:[0],ax
      call word ptr ds:[2],0
      call dword ptr ds:[0]     # 执行后,(CS)=0,(IP)=0123H,(sp)=0CH
      

10.7 call 和 ret 的配合使用

  前面,我们已经分别学习了 ret 和 call 指令的原理。现在我们看一下,如何将它们配合使用来实现子程序的机制。

问题 10.1

  下面程序返回前,bx 中的值是多少?

assume cs:code
code segment
start:
	mov ax,1
	mov ax,3
	call s
	mov bx,ax
	mov ax,4c00h
	int 21h
	s:
		add ax,ax
		loop s
	ret
code ends
end start

  我们来看一下 CPU 执行这个程序的主要过程

  1. CPU 将 call s 指令的机器码读入,IP 指向了 call s 后的指令 mov bx,ax,然后 CPU 执行 call s 指令,将当前的 IP 值(指令 mov bx,ax 的偏移地址)压栈,并将 IP 的值改变为标号 s 处的偏移地址;
  2. CPU 从标号 s 处开始执行指令,loop 循环完毕,(ax)=8;
  3. CPU 将 ret 指令的机器码读入,IP 指向了 ret 指令后的内存单元,然后 CPU 执行 ret 指令,从栈中弹出一个值(即 call 先前压入的 mov bx,ax 指令的偏移地址)送入 IP 中。则 CS:IP 指向指令 mov bx,ax;
  4. CPU 从 mov bx,ax 开始执行指令,直至完成。

  因此,程序返回前,(bx)=8。我们可以看出,从标号 s 到 ret 的程序段的作用是计算 2 的 N 次方,计算前,N 的值由 CX 提供。

Avatar

Hui.Ke

❤ Cyber Security | Safety is a priority.
Previous 10.8 ~ 10.12