Linux 常用命令
- groups命令知道自己属于哪些用户组。
- chmod命令修改文件的权限。
- 查找home目录中前天创建的文件的命令是find ~ -ctime 2
- zip命令使用-e参数可以创建加密压缩包。
- ls . | sort 命令的功能是:显示当前目录内容并排序。
- 使用grep查找当前目录下*.c中main函数在那个文件中的命令是grep main *.c
- 使用wc统计hello.c共有几行代码的的命令是:wc -l hello.c
- 把ls命令显示当前目录的结果存入ls.txt的命令输出重定向命令是:ls > ls.txt
- tee命令可以同时重定向到多个文件。
- Ctrl+a快捷键的作用是:将光标移至输入行头,相当于Home键。
- 强制删除test文件的命令是:rm -f test 。
- 数据结构中有线性查找算法,C标准库中没有这个功能的函数,但Linux中有,这个函数是:lfind或lsearch
- 查找当前目录下所有目录的find命令是:find . -type d
- 查找宏 STDIN_FILENO 的值的命令是:grep -nr XXX /usr/include
- 操作系统中最基本的四个抽象是:虚拟机、进程、虚拟存储器、文件。
- 链接器的两个主要任务是:符号解析和重定位。
- 加载器将可执行文件的内容映射到存储器,并运行这个程序。
- Linux中显示文件(file )属性(status)的命令是stat
- 使用du命令对当前目录下的目录或文件按大小排序 的命令是:du -sk *| sort -rn
- vi中查看函数qsort的帮助文档的快捷键为(K)
- 抽象是CS中一个重要的概念,在出来器里,指令集结构提供了对实际处理器的抽象。
- gcc -f PIC xxx.c 中的PIC的意思是:位置无关的代码。
vim
- vim编辑器,常用的三种模式:普通模式、插入模式和命令行模式。需要熟悉这三种模式之间的切换方式:
- 普通→插入: i 或 a
- 插入→普通: Esc 或 Ctrl + [
- 命令行→普通:Esc 或 Ctrl + [
gcc
常用选项:
- -c 只编译不链接,生成目标文件.o
- -S 只编译不汇编,生成汇编代码
- -E 只进行预编译,不做其他处理
- -g 在可执行程序中包含标准调试信息
- -o file 将file文件指定为输出文件
- -v 打印出编译器内部编译各过程的命令行信息和编译器的版本
- -I dir在头文件的搜索路径列表中添加dir目录
编译过程:
- 预处理:gcc –E hello.c –o hello.i; “-o”是指目标文件,“.i”文件为已经过预处理的C程序。
- 编 译:gcc –S hello.i –o hello.s; “-S”选项只进行编译而不进行汇编,结果生成汇编代码。
- 汇 编:gcc –c hello.s –o hello.o; “.s”文件转成目标文件
- 链 接:gcc hello.o –o hello ; gcc -o 调用ld** 创建可执行目标文件
- -o后面是接的你给生成的文件指定的名字,如果不指定,则默认为a.out
gdb
- 使用GCC编译时要加“-g”参数,然后才能够用gdb调试
- GDB最基本的命令有:
- gdb programm(启动GDB)
- l 查看所载入的文件
- b 设断点
- info b 查看断点情况
- run 开始运行程序
- bt 打印函数调用堆栈
- p 查看变量值
- c 从当前断点继续运行到下一个断点
- n 单步运行(不进入)
- s 单步运行(进入)
- quit 退出GDB
四种断点:
- 行断点:b [行数或函数名] <条件表达式>
- 函数断点:b [函数名] <条件表达式>
- 条件断点:b [行数或函数名] <if表达式>
- 临时断点:tbreak [行数或函数名] <条件表达式>
Make和Makefile
- make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同时,它通过读入makefile文件的内容来执行大量的编译工作。
- makefile是make读入的惟一配置文件
- 在一个makefile中通常包含如下内容:
1、需要由make工具创建的目标体,通常是可执行文件和目标文件,也可以是要执行的动作,如‘clean’;
2、要创建的目标体所依赖的文件,通常是编译目标文件所需要的其他文件。
3、创建每个目标体时需要运行的命令,这一行必须以制表符TAB开头
- 在makefile中的变量定义有两种方式:
递归展开方式(VAR=var)。
简单方式(VAR:=var)。
- make中的变量使用均使用的格式为:$(VAR)。
正则表达式
规则:
- \ 特殊符号,表示后面的字符本身
- [ ] 匹配其中任意字符,但每次匹配只匹配一个
- [^ ] 匹配除其中的任意字符,每次匹配只匹配一个
- {n} 次数修饰,重复n次,具体如下:
?= {0,1}
+= {1, }
*= {0, }
{m,n}:至少为m,至多为n
- 匹配方法:
^ 从字符串开始的地方匹配
$ 从字符串结束的地方匹配
| 可以匹配左或者右
信息的表示和处理
- 数字表示:无符号、补码、浮点数。
- 字节顺序是网络编程的基础。小端法——在存储器中按照从最低有效字节到最高有效字节的顺序存储对象。大端法——从最高有效字节到最低有效字节的顺序存储。
- 二进制值是计算机编码、存储、操作信息的核心(0、1)。
- 有符号数的计算机表示方式:正数的补码=原码。负数的补码=原码各位取反再加1。
- 扩展数字的位表示:零扩展、符号扩展。
IEEE浮点表示:
- 用V = (-1)s * M * 2E的形式来表示一个数:
- 符号:s决定这个数是负数(s = 1)还是正数(s = 0),而对于数值0的符号位解释作为特殊情况处理。
- 尾数:M是一个二进制小数,它的范围是1 ~ 2-ε,或者是0 ~ 1-ε。
- 阶码:E的作用是对浮点数据加权,这个权重是2的E次幂(可能是负数)。
- 将浮点数的位表示划分为三个字段,分别对这些值进行编码:
- 一个单独的符号位s直接编码符号s。
- k位的阶码字段exp = ek-1…e1e0编码阶码E。
- n位小数字段frac = fn-1…f1f0编码尾数M,但是编码出来的值也依赖于阶码字段的值是否等于0。
- 两种常见的格式:单精度浮点格式float 和双精度浮点格式double。
程序的机器级表示
- 对于机器级编程来说,两种重要的抽象是:ISA,虚拟地址。
- gcc -S xxx.c -o xxx.s 获得汇编代码,gcc -c xxx.c -o xxx.o 产生目标文件,二进制格式。也可以用objdump -d xxx.o 反汇编。64位机器上想要得到32代码:gcc -m32 -S xxx.c。MAC OS中没有objdump, 有个基本等价的命令otool。
- 数据传送指令的三个变种:movb 传送字节、movw 传送字、movl 传送双字。
- C语言中的条件表达式在汇编中是结合有条件跳转和无条件跳转实现的。
- C语言中的循环结构可以用条件测试和跳转组合起来实现。
- IA32指令中,操作数的三种类型是:立即数、寄存器、存储器。
- 有效地址的计算方式 Imm(Eb,Ei,s) = Imm + R[Eb] + R[Ei]*s
- %esi %edi可以用来操纵数组,%esp %ebp用来操纵栈帧。
- 栈用来传递参数、存储返回信息、保存寄存器、本地存储。
- Linux汇编中,形成空调用栈帧的语句是push %ebp movl %esp %ebp。
- Linux汇编中,函数有返回值存在 %eax 寄存器中。
转移控制:
1、call指令有一个目标,即指明被调用过程起始的指令地址,效果是将返回地址入栈,并跳转到被调用过程的起始处。
2、ret指令从栈中弹出地址,并跳转到这个位置,使用这个指令栈指针要指向call指令存储返回地址的位置。
处理器体系结构
- ISA:指令集体系结构——一个处理器支持的指令和指令的字节级编码。
- HCL:硬件控制语言——一种描述硬件系统控制部分的简单语言。
- Y86的处理器有8个程序寄存器,%eax,%ecx,%edx,%ebx,%esi,%edi,%esp,%ebp。
- 创建Y86代码唯一的工具是汇编器。
- IA32的movl指令分成了4个不同的指令:irmovl,rrmovl,mrmovl,rmmovl分别显示地指明源和目的的格式。源可以是立即数(i)、寄存器(r)、或存储器(m)。指令名字的第一个字母表明了源的类型,第二个字母指明了目的类型。目的操作数可以是:寄存器(r)、存储器(m)。
- 4个整数操作指令:addl、subl 、andl 、xorl 。它们只对寄存器数据进行操作,而IA32还允许对存储器数据进行这些操作。这些指令会设置三个条件码:ZF、SF、OF。
- 7个跳转指令:jmp 、jle、jl 、je 、jne 、jge 、jg
- 6个条件传送指令:cmovle、cmovl、cmove、cmovne、cmovge、cmovg。这些指令的格式与寄存器-寄存器传送指令rrmovl一样,但是只有当条件码满足所需要的约束时,才会更新目的寄存器的值。
- call指令将返回地址入栈,然后跳到目的地址,ret指令从这样的过程调用中返回。
- pushl和popl指令实现了入栈和出栈。
- halt指令停止指令的执行。IA32中有一个与之相当的指令hlt。执行halt指令会导致处理器停止,并将状态码设置为HLT。IA32的应用程序不允许使用这条指令,因为它会导致整个系统暂停运行。
- Stat描述程序执行的总体状态:
值 名字 含义
1 AOK 正常操作
2 HLT 处理器执行halt指令
3 ADR 遇到非法地址
4 INS 遇到非法指令
- 实现一个数字系统需要三组成部分:组合逻辑、存储器元素、时钟信号。
- Y86中,使用时钟寄存器保存程序计数器PC、条件代码CC和程序状态Stat。
- Y86中,指令执行分为六个阶段:取指、译码、执行、访存、写回、更新PC。
存储器层次结构
- 存储器系统是一个具有不同容量、成本和访问时间的存储设备的层次结构。
- 存储层次结构的中心思想是:上层作为下层的缓存。
- 高速缓存存储器:作为CPU和主存之间的缓存区域
- 局部性原理:一个编写良好的计算机程序,常常倾向于引用临近于其他最近引用过的数据项的数据项,或者最近引用过的数据项本身。局部性有两种形式时间局部性、空间局部性。
- 随机访问存储器(RAM)分为两类:静态RAM(SRAM)、动态ARM(DARM)。
- 根据携带信号不同,总线可分为数据总线、地址总线、控制总线三种。
- CPU使用存储器映射I/O技术向I/O设备发出命令。
- 对磁盘扇区的访问时间包括三个部分:寻道时间、旋转时间、传送时间。
- 逻辑磁盘块的逻辑块号可以翻译成一个盘面、磁道、扇区三元组。
- 计算磁盘容量的公式:磁盘容量 = 字节数/扇区 X 平均磁盘数/磁道 X 磁道数/表面 X 表面数/盘片 X 盘片数/磁盘
- 一个程序中局部性的简单原则:
1、重复引用同一个变量的程序有良好的时间局部性。
2、对于具有步长为k的引用模式的程序,步长越小,空间局部性越好。
3、对于取指令来说,循环有好的时间和空间局部性。循环体越小,循环迭代次数越多,局部性越好。
缓存命中:
当程序需要第k+1层的某个数据对象d时,首先在当前存储在第k层的一个块中查找d,如果d刚好缓存在第k层中,就称为缓存命中。该程序直接从第k层读取d,比从第k+1层中读取d更快。
缓存不命中:
即第k层中没有缓存数据对象d。这时第k层缓存会从第k+1层缓存中取出包含d的那个块。如果第k层缓存已满,就可能会覆盖现存的一个块。
决定该替换哪个块又缓存的替换策略控制,如随机替换策略,最近最少被使用LRU替换策略。
缓存不命中的种类:
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个块偏移位。
- 高速缓存的大小/容量C指所有块的大小的和,不包括标记位和有效位,所以:C=S*E*B
自己的收获
我感觉对第三章,第四章,第五章,第六章内容,书看的比较扎实,可能有些硬知识没有牢记于脑海,软知识的掌握有一定的信心。当刚学到一个新的知识的时侯觉得挺“深”的,可掌握了之后新的问题自然而然就来了,感觉又不“深”了。或许这就是所谓的“深入了解计算机系统”吧。或许这就是自学的带个我的一种学习模式吧。
自己的不足
过于注重了“看书”,没有注重Linux虚拟机的实际操作,对gcc、gdb,的运用不是很熟练。没当“梁山好汉之前”和当了“梁山好汉”之后学习效果很不一样,看来老师的“好汉”名单对我很有用,也从侧面反映自己学习主动性不是很强,要对自己反思,现在虽然脱离了待及格区,之后每周也要写两篇博客。
课程建议和意见
觉得每周测试题,对于书上的知识考查的不是很深,有点浅,看看书就能回答上来,希望老师考查一些稍微有深度的知识。如果检测质量提上去了,检测就是学习情况的反映。