zoukankan      html  css  js  c++  java
  • 王爽《汇编语言》(第三版)实验8解析(超详细)

    题目

    分析程序,在运行前思考:这个程序是否能够正确返回?
    运行之后再思考:为什么是这种结果?
    通过这个程序加深对相关内容的理解。

    贴入代码如下:

    assueme cs:codesg
    codesg segment
            mov ax,4c00h
            int 21h
    start:  mov ax,0
        s:  nop
            nop
    
            mov di,offset s
            mov si,offset s2
            mov ax,cs:[si]
            mov cs:[di],ax
    
        s0: jmp short s
    
        s1: mov ax,0
            int 21h
            mov ax,0
    
        s2: jmp short s1
            nop
    codesg ends
    end start
    

    分析

    由我们之前学到的知识,我们知道这个程序从start标号的字段开始执行。

    我们先来看一下程序的执行流程:

     1. start: mov ax,0
     2.   s:  nop  ; nop标号语句,在运行时在代码段中分配一个字节的空间,
     3.       nop  ; 这个字节(空间)的值为90h。
            
            ; 操作符 `offset` 的功能是取得标号的偏移地址。
     4.       mov di,offset s   ; 将 s 的偏移地址存到 di 寄存器中
     5.       mov si,offset s2  ; 将 s2 的偏移地址存到 si 寄存器中
     6.       mov ax,cs:[si]   ; 此行是将cs:[si]内存中的机器码存到ax寄存器中,
                               ; 这个机器码是由编译器将 s2 标号字段中的指令编译而成。
     7.       mov cs:[di],ax  ; 将 ax 中的 s2 标号字段的机器码存放到 s 标号字段中。
    
     8.   s0: jmp short s  ; 跳转到 s 标号字段处执行代码。
    
     9.   s:  jmp short s1 ; 根据我们之前的分析, 指令是用相对偏移来表示的
        ; 因此执行的操作并不是真的跳转到 s1 这个标号, 
        ; 而是跳转编译时确定的 该指令到 s1 标号的偏移量。
        ; 所以我们要分析接下来程序的流程的话 , 就必须先编译程序 , 
        ; 通过查看这条指令的机器代码,才知道偏移量是多少。
        ; 然后再根据这个偏移量确定程序下一步应该执行哪里的指令。
        ; 根据下图的编译结果 , 可以发现 , 
        ; jmp short s1 在编译后得到的指令是 : EB F6
        ; 由上可知,偏移量是 :F6 
        ; 偏移量是由 补码 来表示的,由书中 附注二 ,
        ; 我们可以算出 F6对应的有符号十进制数为 -10。
        ; 从这里,我们可以知道,这条指令是将 ip 的值加上 -10。
        ; 那么,我们再看看 ip - 10 指向的地址是哪里呢 ? 
        ; 由下图的编译结果,我们可以知道,
        ; 它指向的刚好就是 code segment 开始的位置.
    
     10.   mov ax,4c00h
     11.   int 21h      ;看到这两句,大家就知道,程序是可以正常返回了
    
    

    反编译

    注意这里使用 debug 的 u 命令进行反汇编的时候要指定代码段的偏移地址为 0 ,否则 debug 会自动从 start 标号的地方开始反汇编

    不完整的反编译代码

    有时候单纯从 u 0 命令无法查看到jmp short s1这条代码。因为有的命令行工具可能不能够显示过多的代码。 我们可以从上图中找一个参照点,再次运用 u 命令,就可以看到这行代码了。从下图中,我们可以看到,jmp short s1对应的机器代码,正是 EB F6

    完整的反编译代码

    • jmp short s1的跳转原理分析:
    1. codesg segment
            mov ax,4c00h     ; 3字节
            int 21h          ; 2字节
    2. start:  mov ax,0         ; 3字节
    3.    s:  jmp short s1     ; 2字节   
        ; 上述4条指令总共加起来是10字节,即 10 个单位的偏移量!
        ; 由于 nop 只占一个字节 , 因此
        ; 原来 s 中的两个 nop 被jmp short s1完全替代。
        ; CPU首先读取这条指令到指令缓存器里
        ; 此时的ip为8(由上图可以知道)
        ; 【文末的参考文章中的len(EB F6)解释错误,应为2,此处已更正】
        ; 接下来 , (ip) = (ip) + len(EB F6) = (ip) + 2 = 10 
        ; 然后执行这条指令 , 即为 (ip) = (ip) - 10 = 0
        ; 这样 ip 就回到了 code segment 的起始处
        ; 这样继续执行
    4. mov ax,4c00h
    5. int 21h
        ; 这样,程序就这样神奇的执行成功啦!!!
    

    总结

    运用王爽老师在P179页的话,CPU在执行jmp指令的时候并不需要转移的目的地址,而包含的是转移的位移。这个位移,是编译器根据汇编指令中的“标号”计算出来的。

    本博参考了他的文章:
    链接:https://www.jianshu.com/p/7e5dfea72b65

  • 相关阅读:
    Ansi,UTF8,Unicode,ASCII编码的区别
    Delphi 快捷键
    Sql Server2008恢复备份数据库问题
    js图片无缝滚动代码
    SQL Server 2008 清空删除日志文件 130G日志 10秒内变10M .
    JavaScript_循环26个英文字母的方法 .
    iframe跨子域
    sql数据库该名字
    大型网站架构的优化与架构演变(整理) .转自网络
    删除SQL日志语句,经测试8G日志文件都可以删除
  • 原文地址:https://www.cnblogs.com/nojacky/p/9497660.html
Copyright © 2011-2022 走看看