汇编笔记_第十章

call和ret指令

ret和retf

  • ret指令用栈中的数据,修改IP的内容,从而是实现 近转移
    (IP)=((ss)*16+(sp))
    (sp)=(sp)+2;
  • retf指令用栈中的数据,修改 CS和IP 的内容,从而实现 远转移
    (IP)=((ss)16+(sp))
    (sp)=(sp)+2
    (cs)=((ss)
    16+(sp))
    (sp)=(sp)+2;
  • 前者相当于:
    pop IP
    后者相当于
    pop IP
    pop CS

call指令

CPU执行call指令,进行两步操作:

  • 将当前的IP或CS和IP压入栈中;
  • 转移

call指令 不能实现短转移,除此之外与jmp的原理相同;

依据位移进行转移

指令格式:
call 标号
将当前的IP压栈后,转到标号处执行;(入栈的是call指令后的第一个字节偏移地址入栈),段内转移;

  • (sp)=(sp)-2;((ss)*16+(sp))(ip)
  • (ip)=(ip)+16位位移

相当于:

push IP

jmp near ptr 标号

eg:

内存地址    机器码    汇编指令
1000:0     b8 00 00  mov ax,0
1000:3     e8 01 00  call s
1000:6     40        inc ax
1000:7     58        s:pop ax

最后ax的值为:6h,因为执行call s时,push ip (ip)=6h,之后pop ax,(ax)=6h

转移的目的地址在指令中

  • call far ptr 标号实现的是段间转移;

  • (sp)=(sp)-2

  • ((ss)*16+(sp))=(cs)

  • (sp)=(sp)-2

  • ((ss)*16+(sp))=(ip)

  • (cs)=标号所在的段地址;

  • (ip)=标号所在的偏移地址;

eg:

内存地址    机器码          汇编指令
1000:0     b8 00 00        mov ax,0
1000:3     9A 09 00 00 10  call far ptr s
1000:8     40              inc ax
1000:9     58              s:pop ax
                           add ax,ax
                           pop bx
                           add ax,bx

指令执行后,(ax)=1010h

执行call时,push cs , push ip,(cs)=1000h,(ip)=8h;

pop ax后,(ax)=8h,add ax,ax后(ax)=10h,pop bx后(bx)=1000h,最后add ax,bx,(ax)=1010h;

转移地址在寄存器中

格式:
call 16位寄存器

功能:

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

相当于进行:

push ip

jmp 16位reg

eg:

内存地址    机器码    汇编指令
1000:0     b8 06 00  mov ax,6
1000:3     ff d0     call ax
1000:5     40        inc ax
1000:6               mov bp,sp
                     add ax,[bp]

程序执行完后,(ax)=0bh;

转移地址在内存中

两种格式:

  • call word ptr 内存单元地址

相当于:

push ip
jmp word ptr 内存单元地址

  • call dword ptr 内存单元地址

相当于:


push cs

push ip

jmp dword ptr 内存单元地址

eg:

assume cs:code
stack segment
dw 8 dup (0)
stack ends
code segment
start:
mov ax,atack
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
call word ptr ds:[0EH]
inc cx      ;设这个地方的地址为0000:xx
inc cx
inc cx

mov ax,4c00h
int 21h

code ends
end start

程序执行到call前,堆栈段和数据段合并,执行call时(ip)=x,入栈,也是数据段ds:[0EH]处的数据为x,这是跳到x处的指令也就是inc ax,,三次inc后(ax)=3h;

call和ret的配合使用

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

code ends
end start

cpu执行的主要过程:

  • CPU执行到call s指令时,ip指向后一句mov bx,ax处,并将其压栈,之后修改ip到s处,实现程序的跳转;
  • 在s中,s实现的时求 \(2^{cx}\),cx的值由最开始的指令给出;
  • 执行完后,ret指令将栈中的值弹出赋给ip,程序跳转到call后的mov bx,ax处,最后结束;

子程序的框架

标号:
    指令
    ret

模块化程序的设计

伪指令proc

格式:

子程序名 PROC 属性
......
子程序名 ENDP

过程属性

  • 属性分为NEAR属性和FAR属性,默认为NEAR,主程序和子程序在 同一个代码短 使用 NEAR 属性,否则使用 FAR 属性;
  • call执行时,系统根据子程序名的属性决定保存断点的段地址和偏移地址;

近程调用NEAR

code segment
    main proc far
        ...
        call subr1
        ...


    subr1 proc near
        ...
        ret
    subr1 endp


    main endp

code ends

code segment
    main prco far
        ...
        call sunr1
        ...
    main endp

    subr1 proc near
        ...
        ret
    subr1 endr

code ends

远程调用NEAR

code1 segment
    main proc far
        ...
        call subrx
        ...
        mov ah,4ch
        int 21h
    main endp
code1 ends

code2 segment
    ...
    call subrx
    ...

    subrx proc far
        ...
        ret
    subrx endp

code2 ends

现场保护

主程序调用子程序时可能寄存器的值会被改变,需要保存此时的值后再进入子程序,一般的实现是利用栈来保存可能改变的寄存器的值,退出子程序时pop恢复现场;

mul指令

  • mul是无符号数乘法指令;
  • 格式:
    mul reg
    mul 内存单元

不同位的相乘:

  • 8位:al和9位寄存器或内存单元相乘,结果在al中;
  • 16位:ax和16位寄存器或内存单元相乘,结果高位在dx中,低位在ax中;


  • 相乘的两个数要么是8位要么是16位;

内存单元可用不同的寻址方式给出:

  • mul byte ptr ds:[0]
    含义:(ax)=(al)*((ds)*16+0)

  • mul word ptr [bx+si+8]
    含义:
    (ax)=(al)*((ds)*16+(bx)+(si)+8)
    (dx)=(al)*((ds)*16+(bx)+(si)+8)

  • 结果大于255就用16位的

xchg指令

  • 指令格式:xchg oprd1,oprd2
  • 功能:将一个字节或一个字的源操纵数和目的操作数相交换;
  • 交换的指令可以在寄存器之间,寄存器与储存器之间:
xchg reg,reg
xchg reg,mem
xchg mem,reg

xchg 指令不允许的情况:

  • 不能同时都为内存操作数
  • 任何一个操作数都不能为段寄存器
  • 任何一个操作数不能为立即数
  • 两个操作数的长度必须相等

https://www.cnblogs.com/31415926535x/p/10197667.html

(end)

posted @ 2018-12-29 19:33  31415926535x  阅读(248)  评论(0编辑  收藏  举报