好书推荐: B. Kernighan and D. Ritchie. The C Programming Language, Second Edition.
一、 gcc 编译指令
gcc -o out_file in_file1 in_file2 ...
gcc 包含预处理器 cpp,编译器 cc1,汇编器 as,链接器 ld。
- cpp 将
*.c
源文件转化为*.i
预处理后的源文件。 - cc1 将
*.i
预处理后的源文件编译为*.s
的汇编语言源文件。 - as 将
*.s
汇编语言源文件汇编成二进制文件*.o
,该文件为可重定位目标程序。 - ld 将多个
*.o
文件和库文件合并成可执行目标文件。
1.1 部分命令行参数
-
指定 C 标准的选项:
-std=
常见 C 标准有:gnu89,c89,ansi,c99,gnu11,c11
-
指定字长(指针类型的大小)的选项
-m32
,-m64
-
指定优化程度的选项
-Og
,-O1
,-O2
-Og
表示不优化 -
输出汇编代码
-S
-
输出可重定位目标程序
-c
-
指定 AVX2 浮点体系结构
-mavx2
二、gdb 调试指令
2.1 启动方式
gdb prog
表示对可执行文件 prog 执行 gdb。- 添加选项
-q
或--silent
可以屏蔽掉 gdb 的启动信息 - 添加选项
--args
可以指定该可执行文件的命令行参数。
2.2 程序运行与环境设置
(gdb) quit 或 q
退出 gdb。(gdb) run 或 r
从 main 开始运行程序,可以在此给出命令行参数和重定向符号,该指令会使程序运行到断点。(gdb) start
相当于在 main 函数处添加一个临时断点再执行 run。(gdb) file
后跟可执行文件名,将调试程序更改为该文件。(gdb) set args
设置当前程序的命令行参数。(gdb) cd
后跟目录名,修改当前工作目录。(gdb) path
后跟字符串,临时修改 PATH 环境变量。
2.3 设置通常的 breakpoint
(gdb) break 或 br 或 b
添加断点,若不加参数则在当前位置添加断点。该指令前后可以跟两个参数,第一个参数表示位置,包括地址、函数名、文件名:函数名、源码行、文件名:源码行、+ x、- x(x 为相对于当前所在行的偏置量);第二个参数表示中断条件(格式如if x == 0
),当输入的表达式为真时才会中断程序。(gdb) tbreak 或 tb
与 break 的格式类似,但添加的是临时断点,即该断点生效一次便会被删除,须注意使用 next 经过断点也算生效。(gdb) rbreak
后跟正则表达式,在所有的与该表达式匹配的函数名处添加断点。
2.4 设置 watchpoint
-
(gdb) watch
后跟表达式表示监控该表达式的值,执行该命令后每次当前位置前进时若表达式的值发生了改变都会导致程序停止(观察断点 watchpoint),并打印改变前和改变后的值。监控的表达式后面也可以添加中断条件。须注意 continue 命令也会因为表达式的值发生改变而停止。须注意如果表达式是数组名,则数组中的元素发生改变时也会导致程序停止。如果当前程序跳出了监控的表达式的作用域,则该 watchpoint 失效。 -
(gdb) rwatch
与 watch 的格式类似,但程序停止条件为读取该表达式。 -
(gdb) awatch
与 watch 的格式类似,但程序停止条件为读取该表达式或改变该表达式的值。watchpoint 分为 hardware watchpoint 和 software watchpoint,hardware watchpoint 会使用一个寄存器来协助观察表达式的值,但这种 watchpoint 可能由于寄存器数量不足或其他原因被禁用。此外 rwatch 和 awatch 必须使用 hardware watchpoint。
2.5 设置 catchpoint(特殊的 breakpoint)
-
(gdb) catch
建立捕捉断点(catchpoint,属于 breakpoint),后跟三种事件,格式如下:throw
后跟异常类的名称表示程序将在发生该异常时停止执行,若不跟名称则表示任意异常均可。catch
后跟异常类的名称表示程序将在该异常被捕获时停止执行,若不跟名称则表示任意异常均可。load
后跟正则表达式,当文件名匹配该表达式的动态库被装载时程序停止执行,若不跟正则表达式则表示任意动态库均可。unload
后跟正则表达式,当文件名匹配该表达式的动态库被卸载时程序停止执行,若不跟正则表达式则表示任意动态库均可。
当 catch 捕获到事件时,使用
up
指令可以查看事件发生处的源码。 -
(gdb) tcatch
用法与catch
相同,但创建的捕捉断点是临时的。
2.6 使能、删除与查看 breakpoint 和 watchpoint
(gdb) condition
后跟一个数字表示各种断点的编号,再跟一个表达式(不加 if)表示向该断点设置条件。(gdb) ignore
后跟两个数字,第一个数字表示需要暂时失效的断点编号,第二个数字表示失效次数。(gdb) disable 或 disable breakpoints
后跟若干个数字,表示禁用这些断点。若不跟数字表示禁用所有断点。(gdb) enable 或 enable breakpoints
用法与 disable 类似,含义相反,表示启用断点。在启用的断点编号列表前面可以加三种参数:once
表示只启用一次,之后回到禁用状态。count 数字
,表示只启用这些次,之后回到禁用状态。delete
表示只启用一次,之后断点会被删除。
(gdb) clear
后跟类似 break 命令的位置参数,表示删除该位置的所有断点。(gdb) delete
删除断点,若不加参数则删除所有断点,若后跟数字表示删除特定编号的断点。(gdb) info break 或 info breakpoint
查看所有断点信息。若后跟数字表示查看特定编号的断点。(gdb) info watchpoint
查看所有 watchpoint 信息。若后跟数字表示查看特定编号的 watchpoint。
2.7 控制程序执行
(gdb) continue 或 c
使程序执行到下一个断点。输入回车可再次执行。(gdb) next 或 n
默认使程序执行一行,若后面加数字表示每次执行的行数。输入回车可再次执行。(gdb) step 或 s
与 next 相似,但遇到函数调用时会跳转到函数内部。(gdb) until
后面加行数表示执行到这一行,若不加行数通常和 next 的意义相同,但如果当前在循环的最后一行,则可以执行完循环体。
2.8 显示一般信息
-
(gdb) list 或 l
显示 10 行源码。输入回车可继续输出接下来的 10 行源码。 -
(gdb) print 或 p
后面可以跟两个参数。第一个参数可选,表示输出格式,第二个参数表示输出的值。输出格式包括下面几种:/x
十六进制/d
有符号十进制/u
无符号十进制/o
八进制/t
二进制/f
浮点数/c
字符
可以输出的数值有以下几种:
- 常数、变量或表达式。需要注意表达式会被执行,如赋值表达式会向变量赋值。
- 寄存器存储的值,格式如
$rax
。该值亦可用于表达式,如$rax + 8
。 - 内存地址存储的值,格式如
*(long long*) 表示地址的数值
,其中表示地址的数值可以是上面两种值,该语法类似 C,即将数值转化为long long*
类型再进行取地址操作。
-
(gdb) x
后面紧跟 “/” 号和一个数字,再紧跟一个 “b”,最后写一个地址或函数名,表示显示该地址之后若干字节的数值。 -
(gdb) display
语法与 print 类似,但每次程序暂停时都会显示值,并且格式参数和 display 之间不能有空格。 -
(gdb) undisplay
后接若干个 display 的编号,表示删除这些 display。 -
(gdb) delete display
用法和含义与 undisplay 相同。 -
(gdb) disable display
用法与 undisplay 类似,但表示禁用这些 display。 -
(gdb) enable display
用法与 undisplay 类型,但表示启用这些 display。 -
(gdb) info display
查看所有 display 信息。
2.9 显示栈帧信息
(gdb) frame
指定当前栈帧并打印当前栈帧的函数名、实参和代码行,后跟三种参数:函数名、栈帧地址、编号、up 数字,down 数字,其中当前函数的编号为 0,调用该函数的函数的编号为 1,依此类推。up 和 down 后跟的数字 x 表示使用当前栈帧的向上数第 x 个或向下数第 x 个栈帧,其中上表示高地址即栈底方向。也可不跟参数,此时不指定栈帧只打印当前栈帧的信息。(gdb) up
后跟数字 x 表示指定当前栈帧为当前栈帧的向上数第 x 个栈帧,若不跟数字表示 x 为 1。(gdb) down
后跟数字 x 表示指定当前栈帧为当前栈帧的向下数第 x 个栈帧,若不跟数字表示 x 为 1。(gdb) info frame
显示栈帧的各种信息。(gdb) info args
显示当前函数的参数信息。(gdb) info locals
显示当前函数的局部变量信息。(gdb) backtrace
默认打印所有栈帧信息,后可跟两个可选参数,第一个可选参数为-full
,表示打印局部变量的值,第二个可选参数为一个数字 x,若为正则表示打印最里层 x 个栈帧的信息,若为负则表示打印最外层 x 个栈帧的信息。
2.10 源码编辑与搜索
(gdb) edit
后跟行号或文件名:行号,打开环境变量 EDITOR 指定的编辑器编辑源码的指定位置。若未指定 EDITOR,则打开 ex 编辑器或 vim 的 Ex 模式。(gdb) search
后跟正则表达式,表示从当前行向后搜索。(gdb) reverse-search
后跟正则表达式,表示从当前行向前搜索。
2.11 信号处理
-
(gdb) info handles
查看可以处理的信号种类,每一列的含义如下:Signal
信号名Stop
信号发生时是否终止程序执行Print
信号发生时是否打印提示信息Pass to program
信号是否对程序可见Description
信号含义
-
(gdb) handle
后接两个参数。第一个表示要设定的信号名,若写 all 则表示针对所有信号。第二个参数表示具体的设定模式,包括如下几种:nostop
、stop
、noprint
、print
、nopass 或 ignore
、pass 或 noignore
。
2.12 其他非 gdb 调试指令举例
objdump -d prog.o
反汇编 prog.o 文件ldd prog
显示可执行文件 prog 需要装载的动态库kill -l
查看 Linux 中定义的各种信号的名称
三、命令行运行一个可执行文件的步骤
- 用户从键盘输出指令,shell 将请求建立一个子进程,操作系统将硬盘中的程序读入到内存中(DMA 方式或经过 CPU)
- 当时间片流转到该程序时,CPU 读取程序并执行,若有输出程序,则将输出的字符串拷贝到显卡
四、存储器层次结构
读写速度:寄存器 > 三级缓存 > 主存 > 外存 > 远程存储
L1 缓存分为数据缓存和指令缓存
每个核的 L2 缓存是不区分数据和指令的
多核处理器的 L3 缓存是共享的
五、虚拟内存结构
---------------------- 0xFFFFFFFFFFFFFFFF
内核专用
----------------------
栈
|
v
----------------------
共享库映射
----------------------
^
|
堆
----------------------
可读可写数据
----------------------
代码和只读数据
---------------------- 程序由此开始
空白
---------------------- 0x0000000000000000
六、Unix 的文件概念
字节流即文件,包括各种 I/O 设备,磁盘文件,目录文件,网络套接字等等
七、telnet
telnet 客户端可以向 telnet 服务器建立一条 TCP 连接,客户端输入一个字符串并发送 Segment,服务器会返回一个 Segment,其中包含请求结果字符串
八、Amdahl 定律:求系统某一部分的性能提升对整体性能提升的影响
S = 1 1 − ( α + α / k ) S = \frac{1}{1-(\alpha+\alpha/k)} S=1−(α+α/k)1
其中 S S S 为加速比,即旧运行时间除以新运行时间, α \alpha α 为优化前该部分的运行时间与整体的运行时间之比, k k k 表示优化前该部分的运行时间与优化后该部分的运行时间之比,即优化的程度
九、并行技术
超线程:通常线程切换需要上万个时钟周期,但超线程处理器可以通过备份的寄存器在一个时钟周期内在两个线程间切换
指令级并行:流水线
单指令多数据并行:如底层的向量加法
十、计算机系统的抽象层次
I/O 设备 => 文件
主存 + I/O 设备 => 虚拟内存
处理器 => 指令集架构
指令集架构 + 虚拟内存 => 进程
操作系统 + 进程 => 虚拟机