美文网首页
《系统级程序设计》——重点&汇编上手

《系统级程序设计》——重点&汇编上手

作者: CSDN_georgeChen | 来源:发表于2019-01-05 12:15 被阅读589次

    1.这是我根据我的印象抽取的重点,希望不要奶死了。
    2.里面有看汇编代码的迅速上手,如果要熟练,请一定要完成几个书上的汇编逆向出代码的题目。

    • 当表达式既有signed又有unsigned的时候,自动转换为unsigned

    • 数的补码表示:最高位为符号位,代表的值不再是2^k 而是 -2^k,但是其余位不变。
      eg.
      [1001] = -8 + 0 + 0 + 1 = -7;

    • 负数补码算数右移,加偏置量2^n-1(n为右移位数)
      eg.
      [1001] >> 2 = [1110] = -8 + 4 + 2 + 0 = -2;
      而 -7 / 4 = -1;❌
      所以要加偏置量2^2 - 1 = 3 = [0011];
      则[1001] + [0011] = [1100];
      [1100] >> 2 = [1111] = -8 + 4 + 2 + 1 = -1;✔️

    • 二进制小数:只能表示x/(2^k)
      eg.
      [0.101] = (4 + 1) / (2 ^ 3) = 5 / 8;

    • 浮点数:非规格化的作用
      1、提供了一种表示0的方法,因为规格化数小数位>=0。
      eg.-0.0 & 0.0,除了符号位为1 & 0 其余全为0
      2.提供一种叫逐渐溢出的属性,即0.0周围的小数都分布均匀地接近于0

    • 浮点数:偏置量bias = 2^(k - 1)-1 ;(k为浮点数指数位位数)

    • 浮点数:非规格化数的偏置为什么为1-bias,而不是bias
      因为规格化数小数位隐含第一位为1,而非规格化数没有。
      为了实现最大非规格化数与最小规格化数之间的平滑过度,所以为1-bias

    • 浮点数:特殊值
      if(指数位全为1)
      {
      if(若小数位全为0)
      表示∞
      else
      否则表示NaN
      }

    • 寄存器
      要看懂汇编,先要清楚寄存器。
      常用的寄存器有:ax,bx,cx,dx,si,di,bp,sp(具体作用,请结合我另一文章看)
      这些都是16位的寄存器。
      (括号内英文仅为方便记忆)
      如果加上l(low),说明为低8位,为8位寄存器。如al,bl,sil,spl
      如果加上h(high),说明为高8位,仍然为8位寄存器。如ah,bh
      如果加上e(enough足够),说明为32位寄存器,如eax,esi,edi
      如果加上r(redundant超多),说明为64位寄存器,如rax,rsi,rdi
      //是不是与c语言的union类型比较像


      1
    • 指令:
      一般的指令有mov,jmp,push之类的,后面一般有表示操作数后缀。


      2

      比如movl表示要移动4*8=32位的数据到寄存器内,所以指令与你操作的数据以及寄存器要匹配得上。
      eg. movl %esi,%al
      这就不匹配,l说明移动32位,但%al寄存器为8位寄存器,无法容纳。

    • 取指针的值
      有指针 p,p存在寄存器esi中,但esi存的只是p的值,是地址。
      如果要获取
      p的值,要通过括号(%esi)来获取。

    • 复杂取地址
      记住,a(b,c,d)在外面的,以及非第二个逗号两边的树外,都是直接相加。
      比如 movl 12(%ebp),%eax ->%eax = %ebp + 12;
      而第二个逗号左右两边的数,为乘。
      比如 movl 12(%esi,%ebp,6),%eax -> %eax = %ebp * 6 + %esi + 12;

    • 控制指令
      要条件跳转,先要判断。
      判断指令有cmp,test
      test一般用法是 test a,a ->看a是否为0

    cmp是最常用的
    比如 cmp a,b
    就做b - a的运算,并且将结果暂存。

    接着就需要条件跳转语句jmp

    j代表跳转
    后面可以接以下字母以及他们的组合
    g(great): >
    a (above) : >
    e (equal) : =
    l (less) : <
    b (below) : <

    eg组合:jle .L1(如果less equal <= 则跳转到L1)

    • while的三种翻译方法
      1、do-while
      2、跳到中间的翻译方法
      3、gaurded-do翻译方法(做了优化)

    • 条件传送指令
      cmov
      后缀与jmp一样,此外还多了
      s(signed) 负数
      ns(not signed)非负数

    用法
    test x,x
    comvns a,b
    如果x不为负数,(则取前面的)即为a = a
    若x为负数,则 a = b
    //类似于C语言 a>=0?a:b;

    • 复杂数据类型的表示
      数组:在内存中连续存储
      //此时就可以联系到前面说过的取址指令了
      比如数组int a[3];
      a为数组首地址,每个数组元素占4Bytes
      若a存在寄存器%edi中,索引i存在%esi中
      那么取a的元素,放到%eax(用于存返回值的寄存器)
      a[i] : movl (%edi,%esi,4), %eax;
      //若为double数组,改4为8即可

    struct结构类型
    同理可按照数据大小进行连续排列
    eg
    strcut test
    {
    char c;
    int I;
    double d;
    }
    那么 那么d就在test偏移为5(sizeof int 和 char)的地方。

    但是,在有一些操作系统中,会有数据对齐的要求。
    要求:一个数据的首地址应该为该数据大小的整数倍,结尾也是。
    因此上述例子就不正确了,因为char占1B
    i就不能紧接着c存储,而必须空出3位,到从地址为4的地方开始到8结束(地址从0开始计算),而8正好为double的倍数,所以可以直接开始存储d。
    此时d相对于test偏移量就不再是5了,而是8。


    3
    • 缓冲区溢出攻击
      利用数据读取漏洞,通过注入溢出的数据代码,使得程序运行一些黑客所需要的代码。

    现代操作系统对缓冲区溢出攻击的防范机制:


    4
    • 代码优化方法
      1、消除循环低效率
      2、减少过程调用
      3、消除不必要的内存引用

    • 评估程序性能
      标准:CPE(每元素周期数)

    表示处理器性能的参数
    延迟:完成运算所需的时间
    发射时间:两个连续通类型的运算之间所需要的最小周期数
    容量:能够执行该运算的功能单元数量
    /*
    大概可以理解为,一辆赛车有氮气加速,延迟代表一罐氮气喷完所需时间,发射时间代表,一罐氮气的充气时间,容量代表你有几个气罐子。
    */
    eg
    一款处理器
    加法:延迟:3周期,发射时间:1周期,容量:2
    需要做两个加法运算
    如果两个加法相互独立,正好有容量为2,那么他们可以同时运算,则CPE = 3
    如果,两个加法之间有数据依赖:比如 a = b + a; a = a + a;那么必须先等第一个做完(花费3周期),再另外一个做(花费3周期)总共是6周期。
    //注意这里加法单元容量为2

    如果容量改为1:
    先等第一个做完(花费3周期),准备(花费发射1周期),再另外一个做(花费3周期)总共是7周期。

    相关文章

      网友评论

          本文标题:《系统级程序设计》——重点&汇编上手

          本文链接:https://www.haomeiwen.com/subject/zscrrqtx.html