20135213——信息安全系统设计基础第八周期中总结

第八周(10.26-11.01):

学习计时:共xxx小时

读书:

代码:

作业:

博客:参考:之前每周发布的课堂笔记部分:

《深入理解计算机系统》第一节课课堂笔记(20135213)

《深入理解计算机系统》第二节课课堂笔记(20135213)

《深入理解计算机系统》第三节课课堂笔记(20135213)

等等内容

+课本+闫佳歆博客内容

一、学习目标

复习前面Linux 命令,Linux 编程基础,教材前七章内容

二、学习资源

1. 教材

2.答案解析见http://group.cnblogs.com/topic/73060.html

   考试中错的最多的会再考,关注一下排名前十的同学做错的题目   

 

三、学习方法

1.  进度很重要:必须跟上每周的进度,阅读,练习,问答,项目。我会认真对待每一位同学,请你不要因为困难半途而废。

2. 问答很重要:遇到知识难点请多多提问,这是你的权利更是您对自己负责的义务。问答到博客园讨论小组:http://group.cnblogs.com/103791/
3. 实践很重要:解决书中习题,实践书中实例,完成每周项目,才算真的消化了这本好书。通过实验楼环境或自己安装的虚拟机在实践中进行学习
4. 实验报告很重要:详细记录你完成项目任务的思路,获得老师点评和帮助自己复习。学习完成后在博客园中(http://www.cnblogs.com/)把学习过程通过博客发表,博客标题“信息安全系统设计基础第八周期中总结”

 

四、学习任务

1. 复习Linux命令,特别是man -k, cheat, grep -nr xxx /usr/include

2. 复习vi, gcc, gdb,make的使用

3. 复习教材内容ch01 ch02 ch03 ch04 ch06 ch07

4. 复习前面的考题(答案解析见http://group.cnblogs.com/topic/73060.html) ,下次考试考每次考试错的最多的题目

5. 期中总结发一篇Blog:

    知识点总结

    自己的收获(不要假大空)

    自己的不足(要具体,有改进措施)

    课程建议和意见(要有理由)

 

、后续学习预告(可选):

第十章:系统级I/O

、学习过程

一、常用命令总结

clear清屏

man帮助

man man打开帮助命令行

总结9点

重点一二章

哪个命令不会用直接man+命令

例如:man ls

ls –l 显示所有文件信息

man -k:

常用来搜索,结合管道使用。

组合

man –k sort | grep 3

 

多关键字查找man –k k1 | grep k2 | grep k3

最后的数字意味着帮助手册中的区段,man手册共有8个区段,最常用的是123,含义如下:

1.Linux
2.系统调用
3.c语言

但是当单独用man语句的时候,想查看其中的单独某个区段内的解释时,用法是这样的:

man 3 printf

即查找c语言中printf的用法。

重点知识:man –k sort 找到任何和sort相关的东西,快速排序

网络协议

cheat(欺骗、作弊)

知道命令如何使用:cheat(列出这个命令的常用方法)

例如:cheat find

 

根目录cd/

pwd显示当前目录所在路径

find

locate

whereis

which

grep

grep -nr

grep  -nr XXX  /usr/include   (XXX为关键字)

这条语句可以用来查找关键字,全文搜索,并且可以直接查找文件内的内容。其中:

n:为显示行号
r:为递归查找

例如,如果想查找某个宏,我们已知宏保存在include文件夹中,所以可以使用下列语句:

grep -nr XXX /usr/include(XXX为所要找的宏)

二、常用工具

vim

Esc进入普通模式,在该模式下使用方向键或者h,j,k,l键可以移动游标。

按键说明
h
l 右(小写L)
j
k
w 移动到下一个单词
b 移动到上一个单词

命令说明
i 在当前光标处进行编辑
I 在行首插入
A 在行末插入
a 在光标后插入编辑
o 在当前行后插入一个新行
O 在当前行前插入一个新行
cw 替换从光标所在位置后到一个单词结尾的字符

请尝试不同的从普通模式进入插入模式的方法,在最后一行shiyanlou前面加上www.注意每次要先回到普通模式才能切换成以不同的方式进入插入模式

命令说明
:q! 强制退出,不保存
:q 退出
:wq! 强制保存并退出
:w <文件路径> 另存为
:saveas 文件路径 另存为
:x 保存并退出
:wq 保存并退出

进入普通模式,使用下列命令可以进行文本快速删除:

命令说明
x 删除游标所在的字符
X 删除游标所在前一个字符
Delete x
dd 删除整行
dw 删除一个单词(不适用中文)
d$D 删除至行尾
d^ 删除至行首
dG 删除到文档结尾处
d1G 删至文档首部

除此之外,你还可以在命令之前加上数字,表示一次删除多行,如:

2dd表示一次删除2行

交换上下行——ddp,快速交换光标所在行与它下面的行。

行间跳转

命令说明
nG(n Shift+g) 游标移动到第 n 行(如果默认没有显示行号,请先进入命令模式,输入:set nu以显示行号)
gg 游标移动到到第一行
G(Shift+g) 到最后一行

小技巧:你在完成依次跳转后,可以使用Ctrl+o快速回到上一次(跳转前)光标所在位置

vim的功能很强大,并且可以移植到很多种不同的程序中,但是我们现在使用的过程中真正用到的命令很少也很简单,更多的技巧参见:VIM相关命令单独记载

 

gcc

常用选项

-c		只编译不链接,生成目标文件.o
-S		只编译不汇编,生成汇编代码
-E		只进行预编译,不做其他处理
-g		在可执行程序中包含标准调试信息
-o file	将file文件指定为输出文件
-v		打印出编译器内部编译各过程的命令行信息和编译器的版本
-I dir	在头文件的搜索路径列表中添加dir目录

编译过程

预处理:gcc –E hello.c –o hello.i;	gcc –E调用cpp	生成中间文件
编 译:gcc –S hello.i –o hello.s;	gcc –S调用ccl	翻译成汇编文件
汇 编:gcc –c hello.s –o hello.o;	gcc -c 调用as	翻译成可重定位目标文件
链 接:gcc hello.o –o hello ;		gcc -o 调用ld**	创建可执行目标文件

-o后面是接的你给生成的文件指定的名字,如果不指定,则默认为a.out

在命令行上运行这个可执行目标文件需要输入它的名字:

 ./a.out 

其中./代表当前目录。

gdb

注意:使用GCC编译时要加“-g”参数,然后才能够用gdb调试

GDB最基本的命令有:

gdb programm(启动GDB)
l	查看所载入的文件
b	设断点
info b	查看断点情况
run 开始运行程序
bt	打印函数调用堆栈
p	查看变量值
c 	从当前断点继续运行到下一个断点
n 	单步运行(不进入)
s 	单步运行(进入)
quit 退出GDB

四种断点:

1.行断点
	b [行数或函数名] <条件表达式>
2.函数断点
	b [函数名] <条件表达式>
3.条件断点
	b [行数或函数名] <if表达式>
4.临时断点
	tbreak [行数或函数名] <条件表达式>

另外的调试工具:

cgdb,有单独的debug窗口,更方便查看

ddd,图形页面

Make和Makefile

这是实现自动化编译的好方法。

Makefile的一般写法:

一个Makefile文件主要含有一系列的规则,每条规则包含以下内容:

  • 需要由make工具创建的目标体,通常是可执行文件和目标文件,也可以是要执行的动作,如‘clean’;

  • 要创建的目标体所依赖的文件,通常是编译目标文件所需要的其他文件。

  • 创建每个目标体时需要运行的命令,这一行必须以制表符TAB开头

格式为:

test(目标文件): prog.o code.o(依赖文件列表)
tab(至少一个tab的位置) gcc prog.o code.o -o test(命令) 
.......
即:
target: dependency_files
	command

定义变量的两种方式:

1)递归展开方式	
		VAR=var
(2)简单方式		
		VAR:=var

使用变量的格式为:

$(VAR)

三、正则表达式

作用:

  • 验证是否匹配
  • 查找
  • 替换

规则:

  • 特殊符号,表示后面的字符本身
  • [ ] 匹配其中任意字符,但每次匹配只匹配一个
  • [^ ] 匹配除其中的任意字符,每次匹配只匹配一个
  • {n} 次数修饰,重复n次,具体如下:

    ?= {0,1}
    += {1, }	
    *= {0, }
    {m,n}:至少为m,至多为n

    匹配方法:

  • ^ 从字符串开始的地方匹配
  • $ 从字符串结束的地方匹配
  • | 可以匹配左或者右
  • () 1.次数修饰中,可以表示当做整体;2.结果中,可以表示单独表示

贪婪:尽可能多的匹配

加了?后——非贪婪,尽可能少的匹配

四、静态库与动态库

静态库:.a(linux)、.lib(windows)
动态库:.so(linux)、.dll(windows)

静态库(以linux为例)

创建该库:

gcc -c addvec.c multvec.c
ar rcs libvector.a addvec.o multvec.o

涉及到的参数所做动作:

gcc -c只编译,不连接成为可执行文件。
	即:把.c文件编译成.o文件
ar -r:在库中插入模块(替换)
   -c:创建一个库
   -s:写入一个目录文件索引到库中
	即:把两个.o文件归档成静态库存档文件.a并且写入目录文件索引到库中

创建它的可执行文件

gcc -02 -c main2.c
gcc -static -o p2 main2.o ./libvector.a

相关参数含义:

gcc -02 和-0都是代码优化指令,可以减少编译时间
	-c 只编译,不连接成为可执行文件
	-static 告诉编译器驱动程序,链接器应该构建一个完全链接的可执行目标文件
	-o 命名生成文件

动态库(linux)

构造创建共享库:

gcc -shared -fPIC -o libvector.so addvec.c multvec.c

参数解析:

-fPIC	指示编译器生成与位置无关的代码
-shared 指示链接器创建一个共享的目标文件
-o 		命名生成文件

把.c文件编译成为.o文件,放入新建的共享库中,并且命名。

链接程序

gcc -o p2 main2.c ./libvector.so

创建一个可执行目标文件p2,在运行时可以和动态库libverctor.so链接。

五、课本重要思想

第一章 计算机系统漫游

这一章介绍了一些基本的概念,是以后各章的总括,提到的内容都在之后的各章中拆开细讲,我认为这章最重要的就是一句话:

信息=位+上下文

计算机中的信息都是有二进制数字表达的,而因为这些二进制位所处的位置不同,是有符号数还是无符号数,是大端法还是小端法,由于具体的解释不同,造成的结果也不同。

之后的学习就是如何读写位,和上下文如何对应。

第二章 信息的表示和处理

这章里我觉得最容易混淆的是小端法和大端法。常用小端法,巧记方式是“高对高,低对低”,但是同时要注意字节在存放的时候的高低与我们惯常认知中的高低位的关系,以及一串数据中几位代表一个字节:

一个字节是8位,也就是两位十六进制数。

然后是整数中,有符号数和无符号数的表示,补码表示,位运算和逻辑运算,溢出、截断和扩展;

浮点数中,二进制小数,最重要的是IEEE小数:

IEEE浮点标准:

用V=(-1)^s X 2^E X M 来表示一个数:
符号:s决定这个数是正还是负。0的符号位特殊情况处理。
阶码:E对浮点数加权,权重是2的E次幂(可能为负数)
尾数:M是一个二进制小数,范围为1~2-ε或者0~1-ε(ε=1/2的n次幂)

编码规则:

单独符号位s编码符号s,占1位
k位的阶码字段exp编码阶码E
n位小数字段frac编码尾数M(同时需要依赖阶码字段的值是否为0)

两种精度

  • 单精度(float),k=8位,n=23位,一共32位;
  • 双精度(double),k=11位,n=52位,一共64位。

三种被编码情况

  • 规格化的
  • 非规格化的
  • 特殊值

还有舍入方式:

1.向偶舍入(默认方法)

即:将数字向上或向下舍入,是的结果的最低有效数字为偶数。
能用于二进制小数。

2.向零舍入

即:把整数向下舍入,负数向上舍入。

3.向下舍入

正数和负数都向下舍入。

4.向上舍入

正数和负数都向上舍入。

默认的(即向偶舍入)方法可以得到最接近的匹配,其余三种可用于计算上界和下界。

第三章 程序的机器级表示

这一章和之前学习过的汇编很像,需要注意的就是寻址方式和几个操作,mov,push,pop,leal,还有跳转指令、控制转移指令等等。

几个比较新的容易遗忘的知识点是:

翻译循环

汇编中可以用条件测试和跳转组合起来实现循环的效果,但是大多数汇编器中都要先将其他形式的循环转换成do-while格式。

1.do-while循环

通用形式:

do
	body-statement
	while(test-expr);

循环体body-statement至少执行一次。

可以翻译成:

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

即先执行循环体语句,再执行判断。

2.while循环

通用形式:

while (test-expr)
	body-statement

GCC的方法是,使用条件分支,表示省略循环体的第一次执行:

if(!test-expr)
	goto done;
do
		body-statement
		while(test-expr);
done:

接下来:

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

归根究底,还是要把循环改成do-while的样子,然后用goto翻译。

3.for循环

for循环可以轻易的改成while循环,所以再依照上面的方法改成do-while再翻译即可。

寄存器使用惯例

程序寄存器组是唯一能被所有过程共享的资源。

这个惯例是为了防止一个过程P调用另一个过程Q时寄存器中的值被覆盖。惯例如下:

%eax,%edx,%ecx  调用者保存寄存器(Q可覆盖,P的数据不会被破坏)
%ebx,%esi,%edi  被调用者保存寄存器(Q在覆盖这些值前必须压入栈并在返回前回复他们)
%ebp,%esp   惯例保持
%eax用来保存返回值

帧栈结构

这一部分最重要的参见函数调用帧栈的实践,可以参见孙小博同学的讲解中的调用部分,还有笔记本上的所写的帧栈调用过程。

其实这里最基本的是要知道,针对每一句汇编语句,它都干了些什么,寄存器里的值如何变化,栈帧如何变化,内存中的值如何变化,更要明白的是每一行的变化都代表着什么。

 文件在:http://pan.baidu.com/s/1kT4ILON

第四章 处理器体系结构

这章里学习的是一个相对简单的处理器Y86,指令集比起IA32省略了很多。学习中我觉得一个比较不容易掌握,做题时需要反复查阅的是:

指令的字节级编码

每条指令需要1-6个字节不等,每条指令的第一个字节表明指令的类型

1.第一个字节

这个字节分为两个部分,每个部分4位:

  • 高四位:代码部分,值域为0~0xB
  • 第四位:功能部分,功能值只有在一组相关指令共用一个代码时才有用。

比如:课本第233页,Y86指令集的功能码:

整数操作里代码部分均为6,功能部分区分addl,subl,andl,xorl

分支指令里代码部分均为7

传送指令里代码部分均为2

这里要注意rrmovl归到了传送指令里,前面说过它们有相同的指令代码

8个程序寄存器中每个都有相应的0~7的寄存器标识符,程序寄存器存在CPU中的一个寄存器文件中,这个寄存器文件就是一个小的、以寄存器id作为地址的随机访问存储器。

当需要指明不应访问任何寄存器时,用ID值0xF表示

2.有的需要额外的字节
(1)附加的寄存器指示符字节

指定一个或两个寄存器,例如rA或者rB。

  • 没有寄存器操作数的指令,例如分支指令和call指令,就没有寄存器指示符字节。
  • 只需要一个寄存器操作数的指令(irmovl,pushl,popl)将另一个寄存器指示符设为0xF
(2)附加的4字节常数字

这个字的用处:

1.irmovl的立即数数据
2.rmmol和mrmovl的地址指示符的偏移量
3.分支指令和调用指令的目的地址

注意事项

1.分支指令和调用指令的目的地址是一个绝对地址
2.所有整数采用小端法编码

指令编码这一部分可以帮助我们理解机器码与汇编代码的对应关系,并且涉及到下一个我认为的难点:

Y86的顺序实现

这里的六个阶段和每个阶段进行的动作,得出的数据和对应的结果看起来似乎眼花缭乱,但是课本上已经给出了部分常用命令的具体过程,课后的作业题中也有过类似的作业,这要求我们的举一反三的能力。

至于HDL语言,在EDA课程中已经有过基础,看起来倒是比较轻松。

第六章存储器层次结构

涉及到ROM,RAM,磁盘的几个计算,总线等等。概念理解起来比较简单,计算只需要套公式,注意不要漏算盘面或者柱面就好。

这一章我觉得最重要的是局部性。

局部性原理:

一个编写良好的计算机程序,常常倾向于引用临近于其他最近引用过的数据项的数据项,或者最近引用过的数据项本身。

分类:

  • 时间局部性
  • 空间局部性

量化评价一个程序中局部性的简单原则:

  • 重复引用同一个变量的程序有良好的时间局部性
  • 对于具有步长为k的引用模式的程序,步长越小,空间局部性越好
  • 对于取指令来说,循环有好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。

还有存储器层次结构,这里最重要的思想是这句话:每层存储设备都是下一层的“缓存”

这样就涉及到了缓存命中和不命中的情况,还有替换策略:

1.缓存命中

当程序需要第k+1层的某个数据对象d时,首先在当前存储在第k层的一个块中查找d,如果d刚好缓存在第k层中,就称为缓存命中。

该程序直接从第k层读取d,比从第k+1层中读取d更快。

2.缓存不命中

即第k层中没有缓存数据对象d。

这时第k层缓存会从第k+1层缓存中取出包含d的那个块。如果第k层缓存已满,就可能会覆盖现存的一个块

覆盖——替换/驱逐

替换策略:

  • 随机替换策略-随机牺牲一个块
  • 最近最少被使用替换策略LRU-牺牲最后被访问的时间距离现在最远的块。

3.缓存不命中的种类

(1)强制性不命中/冷不命中

即第k层的缓存是空的(称为冷缓存),对任何数据对象的访问都不会命中。

(2)冲突不命中

由于一个放置策略:将第k+1层的某个块限制放置在第k层块的一个小的子集中,这就会导致缓存没有满,但是那个对应的块满了,就会不命中。

(3)容量不命中

当工作集的大小超过缓存的大小时,缓存会经历容量不命中,就是说缓存太小了,不能处理这个工作集。

然后是高速缓存存储器

高速缓存是一个高速缓存组的数组,它的结构可以用元组(S,E,B,m)来描述:

S:这个数组中有S=2^s个高速缓存组
E:每个组包含E个高速缓存行
B:每个行是由一个B=2^b字节的数据块组成的
m:每个存储器地址有m位,形成M=2^m个不同的地址

除此之外还有标记位和有效位:

有效位:每个行有一个有效位,指明这个行是否包含有意义的信息
标记位:t=m-(b+s)个,唯一的标识存储在这个高速缓存行中的块
组索引位:s
块偏移位:b

高速缓存的结构将m个地址划分成了t个标记位,s个组索引位和b个块偏移位。

“存储器山”

作用主要是引入缓存的概念。

关于考试见:

答案摘取

七、遇到的问题及解决

不足:对于系统并没有认识完全,而且操作也并不熟练。知道用man来寻求具体帮助,但是实际使用的时候并没有很顺手,有事更多的求助方向是百度。

 

 

八、其他

收获:基本认识了Linux的命令以及vim还有存储器相关的知识,对于电脑方面不再像以前拘泥于图形图像的点击方式操作。了解了部分的快捷键和对文件用命令行方式的操作方法。

原文地址:https://www.cnblogs.com/20135213lhj/p/4928798.html