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反汇编可以查看目标代码文件内容。
-
不同数据的汇编代码后缀
-
寻址方式
不同数据汇编代码后缀
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小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)