20145316 《信息安全系统设计基础》第五周学习总结
教材学习内容总结
3.1历史发展
X86 寻址方式经历三代:
- DOS时代的平坦模式,不区分用户空间和内核空间,很不安全
- 8086的分段模式
IA32的带保护模式的平坦模式
3.2程序编码
编译的优化
命令行示例:
gcc -O1 -o p p1.c p2.c
-O1
表示使用第一级优化。优化的级别与编译时间和最终产生代码的形式都有关系,一般认为第二级优化-O2 是较好的选择。-o
表示将p1.c和p2.c编译后的可执行文件以及实现库函数的代码合并,产生的可执行文件最终命名为p。
两种抽象:
指令集体系结构ISA
是机器级程序的格式和行为,定义了处理器状态、指令的格式,以及每条指令对状态的影响。学到这里的时候认为ISA这个概念过于抽象,所以到网上查阅了相关知识,明白ISA就是“CPU里的硬性指令集”,而Intel和ARM处理器的本质区别就是,Intel使用复杂指令集(CISC),而竞争对手ARM则使用 精简指令集(RISC),这也就是ARM低功耗的原因。
CPU架构解析:ARM和x86大比拼
参考资料如下:
机器级程序使用的存储器地址是虚拟地址
看上去是一个非常大的字节数组,实际上是将多个硬件存储器和操作系统软件组合起来。
3.3数据格式
3.4访问信息
三种操作数:
- 立即数:常数值。表示为$c标准表示的整数。
- 寄存器:表示某个寄存器的内容。
- 存储器:根据计算出来的地址访问某个存储器位置
数据传送指令
- 栈的特点
- 遵循“后进先出”的原则
- push压栈,pop出栈
- 栈顶:总是从这端插入和删除元素
- 栈顶元素的地址是最低的
- 栈指针%esp保存着栈顶元素的地址
- 数据传送指令
数据传送示例
- 局部变量通常保存在寄存器中;
- 寄存器访问比存储器访问要快的多。
3.5算术和逻辑操作
四组操作
- 加载有效地址:将有效地址写入目的操作数,目的操作数必须是寄存器。
- 一元操作:只有一个操作数,可以是寄存器也可是存储器位置。
- 二元操作:源操作数是第一个,可以是立即数、寄存器、存储器 ;目的操作数是第二个,可以是寄存器、存储器;两个不能同时为存储器。
- 移位:第一个是移位量,用单个字节编码(只允许0-31位的移位),可以是立即数或者放在单字节寄存器%cl中 ;算术右移SAR,填上符号位;逻辑右移SHR,填上0。目的操作数可以是一个寄存器或存储器。
特殊的算术操作
3.6控制
条件码
- CF:进位标志
- ZF:零标志
- SF:符号标志
- OF:溢出标志
访问条件码
条件码常用的使用方法
- 根据条件码的某个组合,将一个字节设置为0或1。SET指令根据t=a-b的结果设置条件码;
- 可以条件跳转到程序的某个其他部分;
- 可以有条件的传送数据。
跳转指令及其编码
jump指令
- 直接跳转:后面跟标号作为跳转目标
- 间接跳转:*后面跟一个操作数指示符
其他跳转指令
除了jump指令外,其他跳转指令都是有条件的。有条件跳转是指根据条件码的某个组合,或者跳转或者继续执行下一条指令。
翻译条件分支
将条件表达式和语句从c语言翻译成机器语言,最常用的方式就是结合有条件和无条件跳转。
循环
循环结构的三种形式
- do-while:先执行循环体语句,再执行判断,循环体至少执行一次。
- while: 把循环改成do-while的样子,然后用goto翻译
- for: 把循环改成do-while的样子,然后用goto翻译
汇编中用条件测试和跳转组合实现循环的效果。大多数汇编器根据do-while形式来产生循环代码,其他的循环会首先转换成do-while形式,然后再编译成机器代码。
条件传送指令
实现条件转移的方式
传统方式: 利用控制的条件转移。当条件满足时就,程序沿着一条执行路径进行,而当条件不满足时,就走另一路径。
数据的条件转移方式。注意:基于条件数据传送的代码比基于条件控制转移的代码性能好。
switch语句
跳转表是一种非常有效的实现多重分支的方法,是一个数组,表项i是一个代码段的地址,这个代码段实现当开关索引值等于i时程序应该采取的动作。
3.7过程(重点)
栈帧结构
- 机器用栈来传递过程参数、存储返回信息、保存寄存器用于以后恢复,以及本地存储。为单个过程分配的那部分栈称为栈帧。
- 最顶端的栈帧以两个指针界定,寄存器%ebp为帧指针,寄存器%esp为栈指针。
转移控制
call指令
- call指令有一个目标,即指明被调用过程起始的指令地址。
- call指令的效果是将返回地址入栈。并跳转到被调用过程的起始处。
ret指令
- ret指从栈中弹出地址,并跳转到这个位置。
- ret指令返回到call指令后的那条指令。
leave指令
leave指令可以使栈做好返回的准备 等价于:
movl %ebp,%esp
popl %ebp
寄存器使用惯例
程序寄存器组是唯一能被所有过程共享的资源。
惯例是为了防止一个过程P调用另一个过程Q时寄存器中的值被覆盖- 使用惯例:
- %eax,%edx,%ecx 调用者保存寄存器
- %ebx,%esi,%edi 被调用者保存寄存器
- %ebp,%esp 保持寄存器
- 保存某值的两种方式
- 由调用者保存。在调用之前就压进栈。
- 由被调用者保存,在刚被调用的时候就压进栈,并在返回之前恢复。
3.11GDB的应用
代码调试中的问题和解决过程
在为code.c进行优化编译的时候出现以下问题:
- 后来仔细看了课本,发现应该是
O1
而不是01
,这两个实在太容易看错了。而后,针对这样一个小小的马虎,我深入思考了一下O1
的含义,1
当然是优先级,那么O
想必就是output输出的意思了,这样一记就不容易混淆了。 下面是成功的截图:
反汇编
本周代码托管截图
截图
- 代码托管地址:https://git.oschina.net/xxy745214935/linux/tree/master/week05?dir=1&filepath=week05&oid=a2b6eaa8b67452123502807ccfe6b0f1e73825a1&sha=3c6f123ee4a616c321d956afdf0836c7a64654c2
课外学习C++语言的代码托管截图:
C++代码托管地址:https://git.oschina.net/xxy745214935/C-Plus-Plus
其他(感悟、思考等,可选)
- 这周的学习内容与大二下学期汇编语言的知识密切相关,实践比起第二章有所增加,但还是更侧重于理论,需要记忆的指令也很多。不同于背古诗,此类信息需要不断地在敲代码的实践中记忆,死记硬背可以应付每周的小测试,但于代码学习无益。同时,我们也要注重培养自己 速查的习惯,平时学习中遇到不会的指令和知识要赶快速查,要知道怎么查,在哪查,哪里找到的结果最可信,时间久了就发现每周开卷考试碰到不会的题,你做对的概率都会大很多。
- 这个周课余时间利用“计蒜客”这一学习平台学习了一部分C++语言的知识。虽然信安专业的培养计划里并没有C++语言的学习,在很多方面C++也广为人诟病(批判者包括linux的创始人),但我认为:一,C++语言继承了c语言的绝大部分用法,却比C更高效,在学习C++的时候因为有C的基础,所以难度不会太大,在学习的同时也对C语言知识进行了复习;二,C++是面向对象的程序语言,与Java也很相似,通过学习C++也可以帮助自己更深入理解“面向对象”的含义,(学习Java的时候因为浮躁这些基础都是没有打牢的)。C++学习的这一部分的代码也已上传到git上。
最近这两个周学习的最大收获是,不管学习什么科目的知识,快乐学习很重要,违背自己意愿的学习不可能收益太多。因为大一大二贪玩,基础比较差,很多时候看到课本那么多不认识的名词,永远调不通的代码,真的不想学了。之前的我总认为,学不进去就是懒惰,学不进去的时候就要给自己压力压制懒惰,道德捆绑自己学习。但通过不断地走弯路我摸索出了道理:学习效率低下学习热情不够高涨的时候,赶快收手,不要在自习室坐着浪费时间,敲几行代码就敲不下去了,赶快停下来,看电影,出去玩儿,做自己想做的事情。当自己内心对于玩乐的满足感已经过剩,未学习的罪恶感和ddl的压迫感扑面而来的时候,就会发现自己无比渴望学习,学习效率也会高很多。(当然,我不是鼓励大家拖延症,一天内的计划总是要在一天内做出来的)。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/2 | 15/30 | |
第二周 | 56 /56 | 2/3 | 15/45 | |
第三周 | 89/145 | 1/4 | 20/65 | |
第五周 | 260/405 | 1/5 | 35/100 |