汇编语言入门:CALL和RET指令(二)

本文首先对之前的知识进行一个简要的回顾和补充,接着继续讲解CALL、RET指令,包括由此产生的子程序设计概念


前提回顾

call、ret指令的作用

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

2)它们经常被共同实现子程序的设计

3)这一章讲解call、ret指令的原理

ret、retf指令的区别

ret:利用栈中的数据修改IP以实现近转移,先让IP等于栈顶接着SP加二(相当于pop IP

ret

这里写图片描述

retf:利用栈中的数据修改CS和IP以实现远转移,先让IP等于栈顶接着SP加二,然后CS等于新的栈顶,最后SP再次加二(相当于pop IPpop CS;注意这里是先IP后CS可见要逆向这一过程应该先push CS,再push IP

retf

这里写图片描述

call指令(call 标号)

call指令经常和ret指令配合使用,因为CPU执行call指令进行两部操作

1)将当前IP或CS和IP压入栈中

2)转移(相当于jmp指令)

call指令不能实现短转移(短转移8位位移,近转移16位位移),除此之外call指令实现转移的方法和jmp指令的原理相同(只是多了一个将CS、IP入栈)

call 标号

原理上:先让SP减二,接着把IP赋给新的栈顶,最后IP加上16位位移

这里写图片描述

16位位移 = 标号处的地址 - call指令后的第一个字节的地址(有负数用补码表示,由编译器在编译时算出)

push IP
jmp near ptr 标号

再次声明,call的转移地址不管是相对地址还是绝对地址,都只有near(16位模式下为16位,32位模式下为32位)和far(16位模式下为32位,32位模式下为48位)偏移


call指令的各种变式

call far ptr 标号:实现远转移

call指令结合far ptr实现远转移

call far ptr

相当于

push CS
push IP
jmp far ptr 标号

call 16位寄存器:同样实现近转移

16位寄存器存储16位数据

call 16位reg

这等价于

(sp) = (sp) - 2
((ss)*16 + (sp)) = (ip)
(ip) = (16位寄存器)

call word ptr 内存单元地址、call dword ptr 内存单元地址

call word ptr 内存单元地址
push ip
jmp word ptr 内存单元地址

栗子

mov sp,10h
mov ax,0123h
mov ds:[0],ax
call word ptr ds:[0]

这段代码执行后(IP) = 0123H,(IP) = 0E(因为push后IP向下移动两个字节)

再看下面这段

mov sp,10h
mov ax,0123h
mov ds:[0],ax
mov word ptr ds:[2],0
call dword ptr ds:[0]

执行后(CS) = 0,(IP) = 0123H,(SP) = 0CH


call和ret(retf)的配合使用

assume cs:code
code segment
start:mov ax,1
      mov cx,3
      call s
      mov bx,ax
      mov ax,4c00h
      int 21h
    s:add ax,ax
       loop s
       ret    ; 继续从mov bx,ax这句开始执行
code ends
end start

上面这段程序执行后bx = 8


子程序设计:参数传递

mov ds,ax
mov si,0
mov di,16

mov cx,s
s:mov bx,[si]
  call cube
  mov [di],ax
  mov [di].2,dx
  add si,2
  add di,4
  loop s

  mov ax,2c00h
  int 21h

cube:mov ax,bx
     mul bx
     mul bx
     ret

code ends
end start

上面实现了一个计算给定参数(这里是bx)的3次方的函数(子程序)


批量数据的传递:传递多个参数

对于字符串,我们可以传递它的首地址和其长度实现对整个字符串的操作

assume cs:code
data segment
    db 'conversation'
data ends

code segment
start:mov ax,data
      mov ds,ax
      mov si,0  ; ds:si存放指向字符串所在空间的首地址
      mov cx,12  ; cx存放字符串的长度
      call capital
      mov ax, 4cooh
      int 21h

capital:and byte ptr [si],11011111b
        inc si
        loop capital
code ends
end start

P.S. 除了用寄存器传递参数,还有一种通用的方法是通过栈来传递参数


jcxz结合cx进行条件判断

规定字符串都以0字符结尾,将以下四个字符串转换为大写

(data段和前面相同,此处略,详见前)

code segement

start:mov ax,data
      mov ds,ax
      mov bx,0

    mov cx,4
  s:mov si,bx
    call capital
    add bx,5
    loop s

    mov ax,4c00h
    int 21h

capital:mov cl,[si]
        mov ch,0
        jcxz ok
        and byte ptr [si],11011111b
        inc si
        jmp short capital
     ok:ret

code ends

end start

顺便一提,jcxz这个命名可以记忆为jump if cx is zero

猜你喜欢

转载自blog.csdn.net/abc_12366/article/details/80300991