• 20145236《信息安全系统设计基础》第5周学习总结


    20145236《信息安全系统设计基础》第5周学习总结

    第三章 程序的机器级表示

    3.1 X86 寻址方式的变化:

    1. DOS时代的平坦模式,不区分用户空间和内核空间,很不安全;

    2. 8086的分段模式;

    3. IA32的带保护模式的平坦模式

    3.2 程序编码

    gcc -01 -o p p1.c

    • -01 表示使用第一级优化。优化的级别与编译时间和最终产生代码的形式都有关系,一般认为第二级优化-02 是较好的选择。

    • -o 表示将p1.c编译后的可执行文件命名为p

    • 计算机系统使用了多种不同形式的抽象,对于机器级编程来说,两种抽象尤为重要。第一种是机器级程序的格式和行为,定义为指令集体系结构(ISA),他定义了处理器状态、指令的格式,以及每条指令对状态的影响。

      • 程序计数器(CS:IP)

      • 整数寄存器(AX,BX,CX,DX)

      • 条件码寄存器(OF,SF,ZF,AF,PF,CF)

      • 浮点寄存器

    3.2.1 一些处理器状态

    1. PC,即程序计数器,用来指示将要执行的下一条指令在存储器中的地址;

    2. 整数寄存器,存储数据;条件码寄存器,保存逻辑指令状态信息。

    3. gcc -S xxx.c 可以得到C语言编译器产生的汇编代码,但不会做其他工作;使用“-c”命令,GCC就会编译并汇编该代码,得到二进制文件XXX.o。由此可见,机器执行的实际上是对一系列指令进行编码的字节序列。

    3.2.2 函数中通用的汇编语句:

    • pushl %ebp //将该寄存器内容全部压入程序栈

    • movl %esp,%ebp

    • addl %eax,accum

    • popl %ebp

    • 64位机器上想要得到32代码:gcc -m32 -S xxx.c

    3.3 数据格式

    1. 数据传送指令的三个变种:
    • movb 传送字节

    • movw 传送字

    • movl 传送双字

    1. 反汇编器:
      根据目标代码产生一种类似于汇编代码的格式。在linux中,objdump -d xxx.o 可以实现

    2. 二进制文件可以用od 命令查看,也可以用gdb的x命令查看。有些输出内容过多,我们可以使用 more或less命令结合管道查看,也可以使用输出重定向来查看:

      • od code.o | more

      • od code.o > code.txt

    3. Linux的汇编格式为ATT格式,而Windows的为Intel格式。二者在语法上有区别——后者省略了指示大小的后缀、寄存器前的%等。

    4. 寻址方式的通用公式:
      有效地址可以表示为Imm+R[Eb]+R[Ei]*s。Imm为立即数偏移;Eb为基址寄存器;Ei为变址寄存器;s为比例因子。如:

      • Ea——操作数值:R[Ea]

      • (Ea)——操作数值:M(R[Ea])

      • Imm(Ea)——操作数值:M(Imm+R[Ea])

    3.5 逻辑操作表示:

    • leal——加载有效地址;将数据从存储器读到寄存器

    • NEG——取负

    • SUB S,D——将D-S的结果送至D

    • 移位操作 SAL,SHL,SAR,SHR的移位量可以是立即数或%cl中的数

    跳转指令:

    • 无条件跳转——jmp.<标号> 跳转到标号所指示的语句处;jmp *<操作数指示符> 【注意:如果形如%eax,即以%eax中的值作为跳转目标;而形如(%eax)则是以其中的值作为地址,读出跳转目标】

    • 有条件跳转——类似于SET类指令,是根据条件码或者其组合来跳转

    3.6 循环

    • do-while语句等价的goto语句——
    loop:
      body-statement
      t = test-sxpr;
      if(t)
          goto loop;
    
    • while语句等价的goto语句——
    t = test-sxpr;
    if(!t)
        goto done;  
    loop:
      body-statement
      t = test-sxpr;
      if(t)
          goto loop;
    done:
    

    3.7 过程

    转移控制——

    • call指令:后接被调用过程的起始的指令地址。效果是将返回地址入栈,并跳转到被调用过程的起始处。

    • ret指令:从栈中弹出地址,并跳转到这个位置。

    【二者配合,实现函数调用时的衔接:即,call类似于先行的探险者,将迷宫入口处的地址存到某个安全的地方,然后探索迷宫(函数);ret类似于保障人员,在探险完成之后将该地址取出来,带领程序回到最初的入口处,接着走大路(主程序)】

    教材习题解答

    3.3

    • 找出下列代码的错误之处?

    movb $0xf,(%bl) ---目的操作数只能是一个寄存器或者一个存储器地址。(%bl)表示一个值

    movw (%eax),4(%esp)---目的操作数与源操作数不能都是存储器

    movb %si, 8(%ebp)---指令后缀与寄存器地址不匹配

    3.5

    • xp,yp,zp分别存储在相对于寄存器%edp中地址值偏移8、12、16的地方。试写出与以下代码等价的C语言代码

    movl 8(%ebp),%edi
    movl 12(%ebp),%edx
    movl 16(%ebp),%ecx
    movl (%edx),%ebx
    movl (%ecx),%esi
    movl (%edi),%eax
    movl %eax,(%edx)//将x存储到yp
    movl %ebx,(%ecx)//将y存储到zp
    movl %esi,(%edi)//将z存储到xp

    • 代码如下:
    void decode1(int *xp,int *yp,int *zp)
    {
        int x=*xp;
        int y =*yp;
        int z = *zp;
        *yp = x;
        *zp = y;
        *xp = z;
    }
    

    3.6

    • 假设寄存器%eax的值为x,%ecx的值为y。填写下表,指明下面每条汇编代码指令存储在寄存器%edx中的值。

    leal 6(%eax),%edx——6+x

    leal (%eax,%ecx),%edx——x+y

    leal (%eax,%ecx,4),%edx——x+4y

    leal 7(%eax,%eax,8),%edx——7+9x

    leal 0xA(,%ecx,4),%edx——10+4y

    leal 9(%eax,%ecx,2),%edx——9+x+2y

    3.9

    • 基于给出的汇编代码,补充C语言中缺失的代码:

    movl 12(%ebp),%eax
    xorl 8(%ebp),%eax
    sarl $3,%eax
    notl %eax
    subl 16(%ebp),%eax

    • C语言代码:
    int arith(int x,int y,int z)
    {
        int t1 = x^y;
        int t2 = 3*t1;
        int t3 = ~t2;
        int t4 = t3-z;
        return t4;
    }
    

    3.14

    • 根据以下C语言代码:
    int test(data_t a)
    {
        return a TEST 0;
    }
    

    根据以下每条指令序列,确定哪种数据类型和比较TEST会使编译器产生这样的代码?

    A. testl %eax,%eax setne %al

    后缀是‘l’,表明是32位操作数,且data_t可以是int,unsigned和指针;而ne表示比较类型是 !=,对有无符号的数字都成立;对于unsigned,比较还可以是>

    B. testw %ax,%ax sete %al

    后缀是‘w’,表明是16位操作数,且比较是 ==,则data_t一定是short或者unsigned short
    C. testb %al,%al setg %al

    后缀是‘b’,表明是8位操作数,且比较是对补码的‘>’ ,则data_t一定是char

    D. testw %ax,%ax seta %al

    后缀‘w’和寄存器指示符表明是16位操作数,且比较是对无符号的‘>’,则data_t一定是unsigned short。对于short或者unsigned short类型,比较也可以是!=。

    3.16

    • 已知下列C语言代码:
    void cond(int a,int *p)
    {
        if(p&&a>0)
            *p +=a;
    }
    

    按照与汇编代码等价的C语言goto版本,写一个与之等价的C语言代码。 答:

    void goto_cond(int a,int *p)
    {
        if(p == 0)
            goto done;
        if(a<=0)
            goto done;
        *p +=a;
        done:
            return;
    }
    
    • 请说明为什么C语言代码中只有一个if语句,而汇编代码包含两个条件分支?
      答:第一个条件分支是&&表达式实现的一部分。如果对p为非空的测试失败,代码会跳过对a>0的测试。

    3.22

    • 根据汇编代码,补充对应的C语言代码空缺部分

    movl 8(%edp),%edx //x at %edp+8
    movl $0,%eax
    testl %edx,%edx
    je .L7
    .L10:
    xorl %edx,%eax
    shrl %edx //shift right by 1
    jne .L10
    .L7:
    andl $1,%eax

    对应的C语言代码是:

    int fun_a(unsigned x)
    {
        int val = 0;
        while(x!=0)
        {
            val = val ^ x;
            x>> = 1;
        }
        return val & 0x1;
    }
    
    • 这段代码的功能? 【如果x有奇数个1,就返回1;如果有偶数个1,就返回0】

    3.23

    • 函数fun_b经GCC编译之后产生如下汇编代码:

    movl 8(%ebp),%ebx //x at %ebp+8
    movl $0,%eax
    movl $0,%ecx
    .L13:
    leal (%eax,%eax),%edx
    movl %ebx,%eax
    andl $1,%eax
    orl %edx,%eax
    shrl %edx
    addl $1,%ecx
    cmpl $32,%ecx
    jne .L13

    对应的C语言代码:

    int fun_b(unsigned x)
    {
        int val = 0;
        int i;
        for(i =0;i<32;i++)
        {
            val = (val<<1) | (x & 0x1);
            x>> =1;
        }
    return val;
    }
    
    • 这段代码的功能? 【把x的位(十六进制)翻转过来填入val】

    3.29

    • 根据给出的的汇编代码,填写补充C源代码
    int switcher(int a,int b,int c)
    {
        int answer;
        switch(a)
        {
            case 5 :
                c = b ^ 15;
            case 0 :
                answer = c+112;
            case 2 :
            case 7 :
                answer = c+6;
                break;
            case 4 :
                answer = a;
                break;
            default :
                answer = b;
        }
        return answer;
    }
    

    3.30

    • 下面的代码片段常常出现在库函数的编译版本中:

    call next
    next:
    popl %eax

    A.寄存器%eax被设置成了什么值?
    %eax被设置成popl的地址。

    B.解释为什么这个调用没有与之匹配的ret指令
    这不是一个真正的过程调用,因为根本是按照与指令相同的顺序进行的,而返回值是从栈中弹出的。

    C.这段代码完成了什么功能?
    这是IA32中将程序计数器中的值放到整数计数器中的唯一办法。

    代码托管链接

    代码托管

  • 相关阅读:
    使用Mxnet基于skip-gram模型实现word2vect
    【快学springboot】SpringBoot整合Mybatis Plus
    面试官:说说Spring中的事务传播行为
    「快学SpringBoot」配置文件的加载顺序和配置项默认值设置
    「快学springboot」SpringBoot整合freeMark模板引擎
    「快学springboot」SpringBoot多环境配置文件
    为什么阿里规约手册要求谨慎使用Arrays.asList方法
    「快学Docker」Docker简介、安装和Hello World实现
    Java中的transient关键字
    IDEA设置窗口标签换行显示
  • 原文地址:https://www.cnblogs.com/feng886779/p/5965236.html
Copyright © 2020-2023  润新知