20135220谈愈敏--信息安全系统设计基础期中总结
期中总结
一、Linux命令
先研究学习,论专业课程背后的三种知识:
元知识:思考问题的能力
硬知识:可见的知识点
软知识:实践中的经验
1、man
查看帮助文档:man+关键词
这里可以在中间加上数字,表示:
1是普通的Linux命令
2是系统调用,操作系统的提供的服务接口
3是库函数, C语言中的函数
man -k 搜索引擎
结合grep和管道,实现多关键字查找:
man -k key1 | grep key2 | grep key3...
2、cheat
相当于小抄,man帮助还不会用,这个可以提供具体的例子。
3、grep
grep 可以对文件全文检索,支持正则表达式。
例:查找宏:
grep -nr XXX /usr/include
n:为显示行号
r:为递归查找
4、其他核心命令
find查找一个文件在系统中的什么位置
locate是神速版本的find
whereis,which告诉你使用的命令工具装在什么地方
二、Linux工具
1、vim
三种常用模式及其转换:
普通→插入: i/a
普通→命令行: “:”
插入/命令行→普通: Esc 或 Ctrl + [
常用操作:
vim 文件名:进入vim,还可新建文件
命令行模式下 :wq 表示保存并退出
2、gcc
gcc流程:
1、gcc会调用预处理程序cpp,由它负责展开在源程序中定义的宏
$ gcc -E hello.c -o hello.i
2、编译:翻译成汇编文件
$ gcc –S hello.i –o hello.s
3、将hello.i编译为目标代码(二进制代码)
$ gcc -c hello.s -o hello.o
4、gcc连接器将目标文件链接为一个可执行文件
$ gcc hello.o -o hello
3、gdb
首先在编译时,必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的 -g 参数即可。
如:$ gcc -g hello.c -o hello
基本命令:
gdb programm 启动GDB
l 查看所载入的文件
b 设断点
info b 查看断点情况
run 开始运行程序
bt 打印函数调用堆栈
p 查看变量值
c 从当前断点继续运行到下一个断点
n 单步运行(不进入)
s 单步运行(进入)
quit 退出GDB
四种断点:
1.行断点 b [行数或函数名] <条件表达式>
2.函数断点 b [函数名] <条件表达式>
3.条件断点 b [行数或函数名] <if表达式>
4.临时断点 tbreak [行数或函数名] <条件表达式>
4、makefile
make工具根据makefile文件中描述的源程序至今的相互关系来完成自动编译、维护多个源文件工程。
makefile按某种语法进行编写,需要说明如何编译各个源文件并链接生成可执行文件,要求定义源文件之间的依赖关系。
Makefile的一般写法:
test(目标文件): prog.o code.o(依赖文件列表)
tab(至少一个tab的位置) gcc prog.o code.o -o test(命令)
.......
技巧:编译命令反向写makefile
5、静态库与动态库
静态库:
静态链接库的生成: ar rcsv libxxx.a xxx.o
静态库的使用: gcc -o main main.c -L. -lxxx
动态库:
动态库的生成: gcc -fPIC -c xxx.c
gcc -shared -o libxxx.so xxx.o
动态库的使用: gcc -o main main.c -L. -lxxx
三、课本内容
第一章 计算机系统漫游
这章是全书的一个总括。
重点理解信息就是位+上下文
查看源文件可以用od 命令 : od -tc -tx1 hello.c
冯式结构:CPU执行指令的操作
加载
存储
操作
跳转
存储系统的核心思想:缓存
操作系统核心抽象:
文件
虚存
进程
虚拟机
第二章 信息的表示和处理
三种重要的数字表现形式:
1、无符号数:编码基于传统的二进制表示法表示大于或等于零的数字。
2、补码:编码是表示有符号整数的最常见方法,可以是正或者是负的数字。
3、浮点数:编码是表示实数的科学计数法的以二位基数的版本
整数和浮点数会有不同的数学属性是因为:处理数字表示有限性的方法不同。
整数:编码相对较小的数值范围,但精确度高
浮点数:编码较大范围的数,但这种表示是近似的
寻址和字节顺序:最高有效位前八位和最低有效位后八位。是网络编程基础。
小端法:某些机器选择在存储器中按最低有效字节到最高有效字节
大端法:某些机器选择在存储器中按最高有效字节到最低有效字节
小端法“高对高,低对低”大端与之相反。
布尔代数:二进制是计算机编码存储和操作信息的核心。
C语言中的位级运算:C语言支持按位的布尔运算。与、或、非、异或、同或
C语言中的逻辑运算:&&与 ||或 !非
C语言中的移位运算:x<<k:左移k位; X>>k:右移k位
扩展一个数字的位表示:在不同字长的整数之间转换又保持数值不变。
0扩展:简单的在表示的开头加0。
符号扩展:将补码数字转换成更大类型的数据。规则在表中添加最高有效位的值的副本。
IEEE浮点表示:标准 V=(-1)s*M*2E
符号:s 决定这个数是正数还是负数。
尾数:M 二进制小数。
阶码:E 对浮点数加权,权重是2 的E次幂。
将浮点数的位划分成三段分别进行编码:
一个单独的符号位直接编码符号。
K位的阶码字段exp=ek-1……e1e0编码阶段
N位小数字段
舍入:浮点运算只能近似的表示示数运算想要找到最接近x的值就是舍入,问题的关键在于在两个可能的值中间确定舍入方向。
向偶数舍入:也叫向最接近的值舍入。是默认方法。
将数字向上或向下舍入使的结果的最低有效数字是偶数。
其他三种方式产生实际值的确界。
第三章 程序的机器级表示
X86(Intel处理器系列) 寻址方式经历三代:
1 DOS时代的平坦模式,不区分用户空间和内核空间,很不安全
2 8086的分段模式
3 IA32的带保护模式的平坦模式
对于机器级编程的两种重要抽象
1 机器级程序的格式和行为,定义为指令集体系结构(ISA)
2 机器级程序使用的存储器地址是虚拟地址,存储器系统的实际实现是将多个硬件存储器和操作系统软件组合起来。
用objdump -d xxx.o 反汇编
函数前两条(push,mov)和后两条(pop,ret)汇编代码,所有函数都有,建立函数调用栈帧。
注意: 64位机器上想要得到32代码:gcc -m32 -S xxx.c
操作数的三种类型
立即数:常数值
寄存器:某个寄存器的内容
存储器:根据计算出来的地址访问某个存储器位置
栈
1 遵循“后进先出”的原则
2 push压栈,pop出栈
3 栈顶:总是从这端插入和删除元素
4 栈顶元素的地址是最低的
5 栈指针%esp保存着栈顶元素的地址
算术和逻辑操作
加载有效地址:实际是将有效地址写入目的操作数,目的操作数必须是寄存器。
一元操作:只有一个操作数,可以是寄存器也可是存储器位置。
二元操作:源操作数是第一个,可以是立即数、寄存器、存储器
目的操作数是第二个,可以是寄存器、存储器
两个不能同时为存储器。
移位:第一个是移位量,用单个字节编码(只允许0-31位的移位),可以是立即数或者放在单字节寄存器%cl中
算术右移SAR,填上符号位;逻辑右移SHR,填上0。
目的操作数可以是一个寄存器或存储器。
控制中最核心的是跳转语句:
有条件跳转(实现if,switch,while,for)
无条件跳转jmp(实现goto)
条件码寄存器
描述了最近的算术或逻辑操作的属性,可以检测这些寄存器来执行条件分支指令
常用条件码:CF ZF SF OF
注意leal不改变任何条件码
IA32通过程序栈来实现过程调用。栈用来:
传递过程参数
存储返回信息
保存寄存器
本地存储
最顶端的栈帧以两个指针界定,寄存器%ebp为帧指针,寄存器%esp为栈指针。程序执行时,栈指针可以移动,大多数信息的访问都是相对于帧指针的。
栈向低地址方向增长。
call指令
指明被调用过程起始的指令地址,效果是将返回地址入栈,并跳转到被调用过程的起始处。
ret指令
从栈中弹出地址,并跳转到这个位置,使用这个指令栈指针要指向call指令存储返回地址的位置。
函数返回值存在%eax中
第四章 处理器体系结构
处理器执行一系列指令,指令被编码为由一个或多个字节序列组成的二进制格式。一个处理器支持的指令和指令的字节级编码称为它的指令集体系结构,ISA。
Y86程序中的每条指令都会读取或修改处理器状态的某些部分,称为程序员可见状态。
8个程序寄存器:%eax,%ecx,%edx,%ebx,%esi,%edi,%esp,%ebp
寄存器%esp被入栈,出栈,调用和返回指令作为栈指针
三个一位的条件码:ZF/SF/OF
程序计数器PC存放当前正在执行指令的地址
存储器,是一个很大的字节数组,保存着程序和数据
Y86程序用虚拟地址来引用存储器位置。硬件和操作系统软件联合起来将虚拟地址翻译成实际或物理地址
状态码Stat 表明程序执行的总体状态:正常运行/某种异常
Y86指令集
IA32的movl指令分成了四个不同的指令:irmovl,rrmovl,mrmovl,rmmovl 显示的指明源和目的。
源可以是立即数i,寄存器r,存储器m 目的可以是寄存器r,存储器m
不允许从存储器到存储器,也不允许将立即数传到存储器。
4个整数操作指令:addl,subl,andl,xorl 只对寄存器数据进行操作,会设置3个条件码
7个跳转指令:jmp,jle,jl,je,jne,jge,jg
6个条件传送指令:cmovle,comvl,cmove,cmovne,cmovge,cmovg
call指令将返回地址入栈,然后跳到目的地址。ret从这样的过程调用中返回
pushl,popl实现入栈和出栈
halt停止指令的执行,会导致处理器停止,并将状态码设置为HLT
指令编码
1、第一个字节表明指令的类型,分两部分:高四位代码部分,低四位功能部分。
代码值为0~0xB,功能值只有在一组相关指令共用一个代码时才有用。
2、8个程序寄存器都有相应的寄存器标识符:
数字 寄存器名字
0 %eax
1 %ecx
2 %edx
3 %ebx
4 %esp
5 %ebp
6 %esi
7 %edi
F 无寄存器
指令需要操作数时,会有附加的**寄存器指示符字节**(如上数字)
只需要一个寄存器的将另一个寄存器指示符设为0xF。
3、有些指令需要附加4字节常数字
1 作为irmovl的立即数数据
2 rmmovl和mrmovl的地址指示符的偏移量
3 分支指令和调用指令的目的地址,这里是一个绝对地址,同时这里所有整数采用小端法编码
Y86异常
代码值 名字 含义
1 AOK 正常操作
2 HLT 处理器执行halt指令
3 ADR 遇到非法地址
4 INS 遇到非法指令
逻辑设计和硬件控制语言HCL
实现一个数字系统需要三个组成部分:
计算对位进行操作的函数的组合逻辑
存储位的存储器元素
控制存储器元素更新的时钟信号
逻辑门是数字电路的基本计算元素,输出为输入位值的某个布尔函数。
AND: &&
OR: ||
NOT: !
逻辑门只对单个位的数进行操作,而不是整个字。
逻辑门总是活动的,一旦输入变化了,输出会相应的变化。
HCL中情况表达式通用格式如下:
[
select_1 : expr_1
select_2 : expr_2
:
select_k : expr_k
]
布尔表达式和整数表达式,前者表明什么时候该选择,后者指明得到的值
同switch语句不同,这里不要求不同的选择表达式之间互斥,顺序求值,第一个求值为1的情况会被选中。
集合关系
判断集合关系的通用格式是:
iexpr in {iexpr1,iexpr2,...,iexprk}
被测试值 待匹配值 都是整数表达式
存储器和时钟
时钟寄存器:存储单个位或字,时钟信号控制寄存器加载输入值
随机访问存储器:存储多个字,用地址来选择该读或该写哪个字
将处理组织成阶段
取指:从存储器读取指令字节,地址为程序计数器PC的值。
指令指示符字节的两个4位为icode指令代码和ifun指令功能。还可能有寄存器指示符和四字节常数字。
按顺序方式计算下一条指令的地址valp=PC+已取出指令的长度。
译码:从寄存器文件读入最多两个操作数读入指令rA、rB指明的寄存器或%esp。
执行:算术逻辑单元ALU执行操作或计算存储器引用的有效地址,增加或减少栈指针,也可能设置条件码。
访存:将数据写入存储器或者从存储器读数据。
写回:最多可以写两个结果到寄存器文件。
更新PC:将PC设置成下一条指令的地址。
SEQ阶段的实现
1、取指阶段
以PC作为起始地址,从指令存储器中读出六个字节。
根据这些字节,产生出各个指令字段。PC增加模块计算信号valP。
2、译码和写回阶段
指令字段译码,产生寄存器文件使用的四个地址(两个读和两个写)的寄存器标识符。
从寄存器文件中读出的值成为信号valA和valB。两个写回值valE和valM作为写操作的数据。
3、执行阶段
ALU要么为整数运算指令执行操作,要么作为加法器。
根据ALU的值,设置条件码寄存器。检测条件码的值,判断是否该选择分支。
4、访存阶段
数据存储器既可以写,也可以读存储器的值。从存储器读出的值就形成了信号valM。
5、更新PC阶段
根据指令代码和分支标志,从信号valC、valM和valP中选出下一个PC的值。
第六章 存储器层次结构
存储器系统 是一个具有不同容量、成本和访问时间的存储设备的层次结构。
CPU寄存器:容量小,成本高,访问快
高速缓存存储器:CPU和主存之间的缓存区域
主存:磁盘上大容量,成本低,慢速
随机访问存储器 RAM
静态的RAM:SRAM更快也更贵,用来作为高速缓存存储器,既可以在CPU芯片上,也可在片下。
动态的RAM:DRAM,用来作为主存以及图形系统的帧缓冲区。容量更大。
非易失性存储器ROM
PROM:可编程ROM,只能被编程一次。
EPROM:可擦写可编程ROM,能够被擦写和重编程的次数的数量级达到1000次。
EEPROM:电子可擦除PROM,不需要物理上独立的编程设备,可直接在印刷电路卡上编程。数量级达到10^5。
FLASH:闪存,基于EEPROM,为大量的电子设备提供快速而持久的非易失性存储
计算机系统的配置:
CPU芯片
I/O桥芯片组
组成主存的DRAM存储器模块
系统总线:连接CPU和I/O桥
存储器总线:连接I/O桥和主存
I/O桥将系统总线的电子信号翻译成存储器总线的电子信号
磁盘构造:盘片、磁道、扇区、间隙、柱面;磁盘驱动器
磁盘容量
记录密度:磁道一英寸的段中可以放入的位数
磁道密度:从盘片中心出发半径上一英寸的段内可以有的磁道数
面密度:记录密度与磁道密度的乘积
计算磁盘容量的公式:
磁盘容量 = 字节数/扇区 X 平均磁盘数/磁道 X 磁道数/表面 X 表面数/盘片 X 盘片数/磁盘
对扇区的访问时间:
寻道时间:定位到包含目标扇区的磁道上,移动传动臂所需时间。依赖于读写头以前的位置和传动臂移动速度。
旋转时间:目标扇区的第一个位旋转到读写头下,时间依赖于读写头到目标磁道的位置和磁盘的旋转速度。
传送时间:读写该扇区的内容,时间依赖于旋转速度和每条磁道的扇区数目(扇区大小)。
局部性
时间局部性:被引用过一次的存储器位置很可能在不远的将来再被多次引用。
空间局部性:如果一个存储器位置被引用了一次,那么很可能在不远的将来引用附近的一个存储器位置。
对程序数据引用的局部性
取指令的局部性
量化评价一个程序中局部性的简单原则:
重复引用同一个变量的程序有良好的时间局部性。
对于具有步长为k的引用模式的程序,步长越小,空间局部性越好。
对于取指令来说,循环有很好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。
存储器层次结构
从高层往底层走,存储设备变得更慢、更便宜和更大。
存储器层次结构的中心思想是:每一层都缓存来自较低一层的数据对象。
缓存命中
需要k+1层的数据对象d,在第k层的一个块中查找到d,可直接读取,更快。
缓存不命中
第k层没有缓存数据对象d,这时会从第k+1层取出包含d的块缓存到第k层。如果k层已满会覆盖现存的一个块。
决定该替换哪个块又缓存的替换策略控制,如随机替换策略,最近最少被使用LRU替换策略。
缓存不命中的种类
强制性不命中/冷不命中:第k层的缓存为空(称为冷缓存),任何访问都会不命中。
这种通常是短暂的事件。
冲突不命中:放置策略为将第k+1层的块限制放置在第k层块的一个小的子集中。
如:假设第k层有4个块,第k+1层的块i必须放置在第k层的块(i mod 4)中。
这时会出现有些对象映射到同一个缓存块,缓存会一直不命中。
容量不命中:每个阶段访问缓存块的某个相对稳定不变的集合,称为这个阶段的工作集。
当工作集的大小超过缓存的大小,会经历容量不命中。就是缓存太小。
通用的高速缓存存储器结构
S=2^s个高速缓存组
每组E个高速缓存行
每行B=2^b字节的数据块
每行一个有效位
每行 t=m-(b+s)个标记位
高速缓存大小C=S*E*B,不包括标记位和有效位
物理地址m被分为三个字段:
t位标记 行匹配
s位组索引 组选择
b位块偏移 字抽取
三个特殊的高速缓存
直接映射高速缓存:每个组只有一行的高速缓存
组相联高速缓存:每个组都保存有多于一个的高速缓存行,即1<E<C/B
全相联高速缓存:由一个包含所有高速缓存行的组组成的,即E=C/B。
第七章 链接
链接器的两个任务
符号解析
重定位
目标文件的三种形式
可重定位目标文件
可执行目标文件
共享目标文件
目标文件格式
a.out
COFF
PE
ELF
处理目标文件的工具:GNU binutils包
AR
STRINGS
STRIP
NM
SIZE
READELF
OBJDUMP
LDD
四、每周检测错题与重点题目摘录总结
关于man指令的:
Linux中显示文件(file )属性(status)的命令是( stat )
数据结构中有线性查找算法,C标准库中没有这个功能的函数,但Linux中有,这个函数是(lfind或lsearch)
关于grep指令的:
Linux Bash中,使用grep查找当前目录下*.c中main函数在那个文件中的命令是( grep main *.c )
~/test 文件夹下有很多c源文件,查找main函数在哪个文件中的命令( grep main *.c )
查找宏 STDIN_FILENO 的值的命令是(grep -nr XXX /usr/include)
关于find指令的:
查找当前目录下2天前被更改过的文件 (find . -mtime +2 -type f -print)
Linux Bash中,查找home目录中前天创建的文件的命令是(find ~ -ctime 2)。
查找当前目录下所有目录的find命令是(find . -type d)
关于cheat指令的:
使用du命令对当前目录下的目录或文件按大小排序 的命令是( du -sk *| sort -rn )
To list the content of /path/to/foo.tgz archive using tar ( tar -jtvf /path/to/foo.tgz )
关于vim/gcc/gdb/makefile/静态库/动态库
针对如下代码:
1、在vi中,查看scanf和printf man pages(帮助文档)的命令分别是?
K 3K
2、编译和运行以上代码的命令
gcc *.c -o main
./main
3、使用GDB调试以上代码:编译代码的命令是?main.c中如何给main函数设置断点?如何在第六行设置断点?
gcc -g *.c -o main
b main
b 6
4、除了main.c外,其他4个模块(add.c sub.c mul.c div.c)的源代码不想给别人,如何制作一个mymath.a静态库?main.c如何使用mymath.a?
gcc -c add.c sub.c mul.c div.c
ar rcvs libmymath.a add.o sub.o mul.o div.o
gcc main.c -o main -L. -lmymath (or gcc main.c ./libmymath.a -o main)
5、除了main.c外,其他4个模块(add.c sub.c mul.c div.c)的源代码不想给别人,如何制作一个mymath.so共享库?main.c如何使用mymath.so?
gcc -fPIC -c add.c sub.c mul.c div.c
gcc -shared -o libmymath.so add.o sub.o mul.o div.o
gcc -o main main.c -L. -lmymath
libmymath.so 要拷贝到/lib or /usr/lib
6、写出编译上面代码的makefile,编译出来的目标文件为testmymath, 只用显式规则就可以.
testmymath: main.o add.o sub.o mul.o div.o
gcc main.o add.o sub.o mul.o div.o -o testmymath
main.o: main.c head.h
gcc -c main.c
add.o: add.c head.h
gcc -c add.c
sub.o: sub.c head.h
gcc -c sub.c
mul.o: mul.c head.h
gcc -c mul.c
div.o: div.c head.h
gcc -c div.c
五、学习总结
还未来得及感叹时间飞逝之快,这门课已经过半,遥想当初,一开始学习的时候,的确压力很大,适应不了任务量,也害怕自己因此浑沦吞枣,我也知道这样既会浪费时间也学不到东西,幸好后来及时与老师沟通解决了问题,随着每周的学习深入,我不再有一开始的恐惧心理,甚至会认为这本书看似那么厚,那么难,只要循序渐进,一章一章的学习,我们还是能够学习到很多知识。到现在我们已经学习了大半的课本,这次的总结让我认识到,我对知识记忆的不够牢固,很多重要的知识点由于表面,我们还需要对更多的知识进行多次重复记忆,最好是通过实践巩固,这样掌握的会更牢。希望老师上课也可以多次强调重点,多带领着我们实践,然后再让我们自己动手实践。
六、参考资料
课本
之前的Blog
2015-2016-1 每周检测解析