• 20145211《信息安全系统设计基础》第五周学习总结——暗暗不曾闻


    教材学习内容总结

    寻址方式历史

    • DOS时代的平坦模式:不区分用户空间和内核空间,很不安全。
    • 8086的分段模式
    • IA32的带保护模式的平坦模式

    数据格式

    • 由于是从16位体系结构扩展成32位,intel用术语字(word)表示16位数据类型,因此32位为双字(double words),64位数为4字(quad words)。
      以下是比较容易模糊的数据类型大小:
      32位机上:float 4 long int 4 double 8 longlong 8 char* 4 unsigned long 4
      64位机上:float 4 long int 8 double 8 longlong 8 char* 8 unsigned long 8
      另外,GCC 用long double表示扩展精度(10字节),出于存储器性能考虑,会被存储为12字节

    访问信息

    • 一个IA32 CPU包含一组8个存储32位值的寄存器,用以存整数数据和指针:eax,ecx,edx,ebx,esi,edi esp,ebp。大多数情况下前六个都用作通用寄存器,eax,ecx,edx的存储和恢复惯例不同于ebx,edi,esi(前三者为被调用者保存,后三者为调用者保存,详见3.7.3);最后两个用于存储指针,由于在过处理中非常重要,分别指向栈帧的顶部和底部,必须保持。

    操作数指示符

    • 大多数指令有一到多个操作数,操作数有三种:
      立即数:即常数值
      寄存器:表示某个寄存器内容
      存储器引用:根据计算出来的地址(通常称有效地址)访问某个存储器位置
      因此寻址方式也有多种,如:立即数寻址、寄存器寻址、绝对寻址、间接寻址、变址寻址、伸缩化 的变址寻址……

    数据传送指令

    • 几个重要数据传送指令:mov族(之所以称这为族是因为mov指令还有很多兄弟指令如movb、movw、movsb、movzb,这是我个人对它们的称呼,便于记忆mov其他几个比较低调的兄弟)、pop、push。同时,对于mov族,movb、movw自不必做过多解释,movsb、movzb分别为符号扩展、零扩展,它们只拷贝一个字节,源操作数均为单字节,并设置目的操作数中其余的位,效果如下:
      初始假设:%dh=8D %eax=98765432
      1 movb %dh,%al ;%eax=9876548D
      2 movsbl %dh,%eax ;%eax=FFFFFF8D(目的操作数高24位设为源字节最高位,在这里为很显然为1,所以前24位为全F)
      3 movzbl %dh,%eax ;%eax=0000008D(目的操作数高24位被设为0)

    • 对于pushl指令等价于:
      subl $4,%esp
      movl %ebp,(%esp) //注意这里的括号引起的差别

      popl指令等价于:
      movl (%esp),%eax
      addl $4,%esp

    问题解决

    数据传输实例

    int exchange(int *xp, int y){                                 
        int x =  *xp;  
        *xp = y;  
        return x;  
    }  
      
    //*********汇编代码******/  
    //1 movl 8(%ebp),%eax   Get xp  
    //2 movl 12(%ebp),%edx  Get y  
    //3 movl (%eax),%ecx    Get x at *xp  
    //4 movl %edx,(%eax)    Store y at *xp  
    //5 movl %ecx,%eax      Set x as return value   
    
    • 通过汇编代码可以得到两点收获:
      1. 指针其实是地址,间接引用指针就是将该指针放在一个寄存器中 ,然后在间接存储器引
        用中引用这个寄存器
      2. 局部变量通常保存在寄存器中,而不是存储器(个人猜测应该是局部变量属于动态
        分配,局部变量因此被动态置入寄存器,而非存储器)

    课后习题解答(家庭作业)

    3.54

    int decode2(int x ,int y, int z)  
    {  
        int a = z - y;  
        int b = (a << 15) >> 15;  
        return (x ^ a) * b;  
    }  
    

    3.55

    typedef long long ll_t;
    
    
    void store_prod(ll_t *dest, ll_t x, int y){
    *dest = x*y;
    }
    
    // dest at %ebp+8, x at %ebp + 12, y at %ebp + 20  
    movl   12(%ebp), %esi        //将x的低位存到%esi  
    movl   20(%ebp), %eax       //将y存到%eax  
    movl   %eax, %edx     
    sarl   $31, %edx                  //将(y >> 31)存到%edx  
    movl   %edx, %ecx  
    imull   %esi, %ecx             //计算x_low * (y >> 31)存到%ecx  
    movl   16(%ebp), %ebx    //将x的高位存到%ebp  
    imull   %eax, %ebx           //计算x_high * y  
    addl   %ebx, %ecx           //计算 x_high * y + x_low * (y >> 31) 存到%ecx  
    mull   %esi                       //计算y * x_low 的无符号64位乘积  
    leal   (%ecx, %edx), %edx    //将64位乘积的高位与x_high * y + x_low * (y >> 31)得到最终结果的高位  
    movl   8(%ebp), %ecx  
    movl   %eax, (%ecx)  
    movl   %edx, 4(%ecx)          //将结果写入目的内存地址  
    
    说明:
    该汇编代码其实是y扩展至64位再进行两个64位数的乘积然后进行截断得到的。
    
    事实上有:
    
    y *{signed} x =
    (y_high * 2^32 + y_low) *{signed} (x_high * 2^32 + x_low) =
    y_high *{signed} x_high * 2^64 +
    y_high *{signed} x_low * 2^32 +
    y_low *{signed} x_high * 2^32 +
    y_low *{signed} x_low(有符号的x_low与无符号的x_low相等,故可用mull指令)
    
    而y_high *{signed} x_high由于乘以2^64,所以对结果不会产生影响。
    

    3.56写出loop函数原型

    int loop(int x, int n)  
    {  
        int result = 0x55555555;  
        int mask;  
        for(mask = 0x80000000;mask !=0; mask = (unsigned)mask >> (n & 0xFF))  
        {  
            result ^= x & mask;  
        }  
        return result;  
    }  
    

    3.57用条件传送指令写函数cread_alt

    movl    20(%esp), %eax  
    movl    $0, 12(%esp)  
    leal    12(%esp), %edx  
    testl   %eax, %eax  
    cmove   %edx, %eax  
    movl    (%eax), %eax  
    addl    $16, %esp  
    .cfi_def_cfa_offset 4  
     ret  
    

    3.58

    int switch3(int *p1,int *p2,mode_t action)  
    {  
        int result = 0;  
        switch(action){  
            case MODE_A:  
                result = *p1;  
                *p1 = *p2;  
                break;  
            case MODE_B:  
                result = *p1 + *p2;  
                *p2 = result;  
                break;  
            case MODE_C:  
                *p2 = 15;  
                result = *p1;  
                break;  
            case MODE_D:  
                *p2 = *p1;  
                result = 17;  
                break;  
            case MODE_E:  
                result = 17;  
                break;  
            default:  
                result = -1;  
                break;    
        }  
        return result;  
    }  
    
    
    

    本周代码托管

    补附第四周博客链接

    学习进度条

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 5000行 30篇 400小时
    第一周 120/200 1/2 16/16 学习Linux核心命令
    第二周 100/200 1/3 30/46 学习vim,gcc以及gdb的基本操作
    第三周 30/230 1/4 15/61 对信息的表示和处理有更深入的理解
    第四周 30/260 1/5 22/83 双系统的探索
    第五周 130/390 1/6 25/108 汇编的深入学习

    参考资料

  • 相关阅读:
    作业01
    C语言I博客作业08
    C语言I博客作业07
    C语言I博客作业06
    C语言I博客作业05
    C语言I博客作业04
    C语言II博客作业04
    C语言II—作业03
    C语言II博客作业02
    C语言II博客作业01
  • 原文地址:https://www.cnblogs.com/nostalgia-/p/5967376.html
Copyright © 2020-2023  润新知