加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

汇编语言(王爽第三版)检测点10 第10章 答案及分析

(2017-04-11 10:44:05)
标签:

汇编

王爽

it

教育

分类: 汇编语言(王爽第三版)检测点

检测点10.1

补全程序,实现从内存1000:0000处开始执行指令

汇编源代码check10-1.asm

assume cs:code

stack segment

    db 16 dup (0)

stack ends

code segment

start:  ;建栈

        mov ax,stack

        mov ss,ax

        mov sp,16

        ;压栈

        mov ax,1000H

        push ax

        mov ax,0000H

        push ax

        retf

       

        mov ax,4c00H

        int 21H

code ends

end start

程序分析:

1. retf指令作用(CPU角度):从栈中弹出2个字单元,并修改CS(第二个字)和IP(第一个字);首先它弹出的是IP,其次是CS,故在压栈时,CS的值首先入栈,IP再入栈。

    在汇编编程角度,retf实现了远转移。

讲解:在汇编代码这个层次,retf指令作用是修改CSIP的值,进而使指令从修改后的地址处开始执行。由于它所依赖的是栈中存储的内容,故在压栈过程中要搞清楚入栈的顺序、入栈的值。

2.熟悉ret指令和RETF指令执行的操作。

我们编译链接后,debug跟踪check10-1.exe

-d ss:0

0B66:0000  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................

stack数据区中初始化了160,此时它未成为栈结构。直到初始化栈的结构。

执行代码t t(二次)

AX=0B66  BX=0000  CX=0026  DX=0000  SP=0010  BP=0000  SI=0000  DI=0000

DS=0B56  ES=0B56  SS=0B66  CS=0B67  IP=0008   NV UP EI PL NZ NA PO NC

0B67:0008 B80010        MOV     AX,1000

-d ss:00

0B66:0000  00 00 00 00 00 00 66 0B-00 00 08 00 67 0B 68 05   ......f.....g.h.

初始化一个栈sp=0010H16),栈地址:ss=0b66,这里我们发现一些不应该有的数据(不理会它,它是中断的信息)

继续执行代码:

-d ss:0

0B66:0000  00 00 00 00 00 00 10 00-67 0B 68 05 00 00 00 10   ........g.h.....

发现从高位开始存储10 00 00 00四个字节的数据,(体会栈是从高地址向低地址发展的,sp指针从10H减少到了0cH

此时的CS=0B67  IP=0010

执行retf代码:

我们发现:CS=1000  IP=0000CSIP的值改变了。

总结:retRETF依赖于栈的结构存储一个程序执行点(IPCSIP),当执行这个代码时,可以恢复到这个程序的执行点(将栈中的数据修改IPCSIP,使CPU指向新的CSIP

检测点10.2

       下面的程序执行后,ax中的数值为多少?

内存地址:         机器码                 汇编指令          

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

程序分析:

1.熟悉call指令的操作过程。call指令在执行时,首先push ip(此时ip应为6,CPU将要执行的地址),然后jmp 标号,执行标号处的代码,pop ax (弹栈写入ax,(ax)= 6),我们发现inc ax没有执行。

    此时使用的栈空间是系统自动创建的。

2.结论:(ax)= 6

 

检测点10.3

内存地址          机器码             汇编指令                 执行后情况

1000:0         b8 00 00             mov ax,0              ax=0,ip指向1000:3

1000:3         9a 09 00 00 10       call far ptr s        push cs,push ip,ip指向0000:9

1000:8         40                   inc ax

1000:9         58                 s:pop ax                ax=8h

                                    add ax,ax             ax=10h

                                    pop bx                bx=1000h

                                    add ax,bx             ax=1010h

程序分析:

1.关键还要明白是什么段地址和偏移地址压栈?遇到CALL指令,老样子,首先将当前的CS和IP值压栈,(cs)=1000H(由CALL的机器码得知),此时IP指向了0008H。它们统统压栈(cs先入栈,ip在栈顶)。(ax)=0

2.转移到标号S处继续执行代码,pop ax出栈写入到ax,(IP)先出栈(0008H),(ax)=0008H

3.add ax,ax   0008H+0008H=0010H

4.pop bx 将(cs)=1000H出栈,并写入bx中,(bx)=1000H

5.add ax,bx   0010H+1000H =1010H

6.(ax)=1010H;代码:inc ax没有执行

检测点 10.4

下面的程序执行后,ax中的数值为多少?

内存地址      机器码           汇编指令            执行后情况

1000:0       b8 06 00        mov ax,6               (ax)=6,ip指向1000:3

1000:3       ff d0           call ax                 push ip(此时IP值为5),ip转移指向1000:6

1000:5       40              inc ax

1000:6       58              mov bp,sp              (bp)=(sp)=fffeh

                             add ax,[bp]            (ax)=6+(ss:bp)=6+5=0bh

程序分析:

1. 遇到CALL指令,老样子,(ip)(此时是5),压栈;这里我们可以不管sp是多少(我的debug是0000H),目前我们确定的就是IP的值是5(压栈的数据)。此时栈中有一个字就是0005H。(sp)=(sp)-2 =>>0000H-2=fffeH

2.由于是CALL ax,(ax)=0006H,直接转移到1000:0006处执行,将sp的值赋值给bp。

3.由于bp默认隶属于ss段寄存器,故[bp]指向ss段的物理内存,也就是栈结构的空间,此时栈中就一个字0005H,那么(ss:[bp])=0005H(读取ss栈中的内容)。

4.add ax,[bp]    ,0006H+0005H=000BH

5.结果:ax的值是000BH。inc ax指令依然没有执行。

 

检测点10.5

1)下面的程序执行后,ax中的数值为多少?ax=3

assume cs:code

stack segment

     dw 8 dup (0)

stack ends

code segment

start:  mov ax,stack

        mov ss,ax

        mov sp,16

        mov ds,ax

        mov ax,0

        call word ptr ds:[0eh]

        inc ax

        inc ax

        inc ax

 

         mov ax,4c00h

        int 21h

code ends

end start

程序分析:

1. 在栈段初始化并定义了8个字,16个字节的空间。是dw指令。

2. 初始化栈,将栈段地址也赋值给了ds;(ss=ds),数据段和栈段是同一个内存空间段。

3. 遇到了call,老样子,将(cs)压栈(这个值肯定是call指令后面的那个指令的csip我们可以不关心它,依据你的debug程序)、将(ip)压栈,此时的ip值应该是第一个inc ax的偏移地址。然后jmpds[0eh]内存单元内容作为偏移地址的点执行代码。由于dsss都是同一个段,call的是一个字单元,故ds[0eh]内存单元是指向的一个字(ds[0eh]~ds[0fh]内存单元),此单元正好是栈空间栈顶的存储单元,存储着最后压入的ip的值,这个值就是代码inc ax的偏移地址,那么开始执行inc ax

4.执行3inc ax后, ax=3

5.总结:这个考察了我们对于CALL 内存空间这个指令的熟悉程度,也考察了栈段和数据段在同一段地址下,怎样读出栈空间单元内容。

       为什么不让使用debug来逐步调试?因为在执行到CALL指令时,显示ds:[0eh]065D(在我的环境中debug后)ds:[oeh]中的内容是中断的信息,并不是我们程序所希望的0011H,它一下就jmp065D的地址去了,而不是cs11地址执行。

       stack段初始的时候定义的全是0,怎么初始化栈段后有数据了?因为中断信息。

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有