2017-2018-1 20155219 《信息安全系统设计基础》第5周学习总结

教材学习内容总结

X86 寻址方式:

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

指令集体系结构(ISA)定义了处理器状态、指令的格式、以及每条指令对状态的影响。大多数ISA包括IA32和x84-64,将程序的行为描述成好像每条指令是按顺序执行的。
汇编命令与反汇编命令

用gcc -S xxx.c -o xxx.s 获得汇编代码,用gcc -c code.c产生目标文件code.o(二进制文件,无法直接查看),用objdump -d xxx.o反汇编可以查看目标代码文件内容。

  • 不同数据的汇编代码后缀
    image

  • 寻址方式
    image

不同数据汇编代码后缀

movb(传送字节)
movw(传送字)
movl(传送双字)注意:汇编代码中后缀l可以表示4自己整数和8字节双精度浮点数。

数据传送指令

MOVS和MOVZ指令比较:MOVS符号位扩展,MOVZ零扩展(高位0填充)

pushl数据压栈,popl数据出栈。采用先进后出的原则。栈顶地址小,栈底地址大。IA32栈向低地址方向增长。所以push指令减小栈指针。

4个整数操作指令
addl、subl、andl、xorl

7个跳转指令(jXX)jmp、jle、jl、je、jne、jge、jg

有6个条件传送指令(cmovXX)
只有当条件码满足所需要的约束时,才会更新目的寄存器的值。
cmovle、cmovl、cmove、cmovne、cmovge、cmovg

翻译条件分支

将条件和表达式从C语言翻译成机器代码,最常用的方式是结合有条件和无条件跳转。
C语言中if-else语句的通用形式:

if(test-expr)
    then-statement
else
    else-statement

汇编结构:

 t=test-expr;
    if!(t)
        goto false;
    then-statement
    goto done;
false:
    else-statement
done:

do-while循环

C语言中do-while语句的通用形式:

do
    body-statement
    while(test-expr);

汇编结构:

loop:
    body-statement
    t=test-expr;
    if(t)
        goto loop;

while循环

C语言中while语句的通用形式:

while(test-expr)
    body-statement

汇编结构:

  t=test-expr;
    if(!t)
        goto done;
loop:
    body-statement
    t=test-expr;    
    if(t)
        goto loop;
done:

for循环

C语言中for语句的通用形式:

for(init-expr;test-expr;update-expr)
    body-statement

汇编结构

init-expr
    t=test-expr;
    if(!t)
        goto done;
loop:
    body-statement
    update-expr;
    t=test-expr;
    if(t)
        goto loop;
    done:
  • 关于栈帧的gdb命令

backtrace/bt:打印当前的函数调用栈的所有信息。后面加n或-n表示打印栈顶上n层(或者下n层)的栈信息。
frame n:n为栈中的层编号,从0开始,类似C语言中数组的下标。移动到n指定的栈帧中去,并打印选中的栈的信息。如果没有n,则打印当前帧的信息。
up n:表示向栈的顶移动n层。
down n:表示向栈底移动n层。

教材学习中的问题和解决过程

  • 1.已知下列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的测试。

代码调试中的问题和解决过程

  • 编译代码
int add(int x)
{
    return x+3;
}
int raturn(int x)
{
return add(x);
}
int main(void)
{
return raturn(4)+1;
}
  • 使用gcc -s xxx.c得到汇编结果如下图:

  • 将C语言文件编译成可执行文件并查看可执行文件的二进制内容

  • 删去汇编多出的辅助信息得到以下代码:
add:
      pushl    %ebp            //保存,将父函数的栈底寄存器存入当前程序栈中
      movl    %esp, %ebp      //构造当前函数堆栈
      movl    8(%ebp), %eax   //从父函数堆栈中取得参数,存入ax寄存器
      addl    $3, %eax        //完成+3操作
      popl    %ebp            //恢复原父函数堆栈

  r_turn:
      pushl    %ebp            //保存,将父函数的栈底寄存器存入当前程序栈中
     movl    %esp, %ebp      //构造当前函数堆栈
     pushl    8(%ebp)        //
     movl    8(%ebp), %eax   
     call    add               //调用add
     addl    $4,%esp
 main:
     pushl    %ebp
     movl    %esp, %ebp
     push    $4        
     call    r_turn      
     addl    $4,%esp              
     addl    $1, %eax        //完成+1操作
  • objdump -d xxx.o得到反汇编结果如下图:

通过gdb的调试可执行文件查看eip, ebp, esp 等寄存器内容如何变化。
一开始调试时总是出问题,查资料后了解,在linux中gdb调试汇编文件需要先用gcc -g3 -o * *.c的命令来将c语言文件编译成可调试汇编的可执行文件。
在64位中rip就是eip,rbp就是ebp,rsp就是esp。
但仍出现如下问题:

还没有解决.

代码托管

其他(感悟、思考等,可选)

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 200/200 2/2 20/20
第二周 300/500 2/4 18/38
第三周 500/1000 3/7 22/60
第四周 300/1300 2/9 10/70
第五周 169/1469 2/9 14/84

尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。

参考:软件工程软件的估计为什么这么难软件工程 估计方法

  • 计划学习时间:10小时

  • 实际学习时间:14小时

  • 改进情况:

(有空多看看现代软件工程 课件
软件工程师能力自我评价表
)

参考资料