1.markdown
第一章:引言
1.1 关于本书
本书着重介绍Unix和Linux的功能以及编程实践
1.2 系统编程的作用
1.3 本书的目标
1.3.1 强化学生的编程背景知识
1.3.2 动态数据结构的应用
1.3.3 进程概念和进程管理
1.3.4 并发进程
1.3.5 定时器和定时功能
1.3.6 信号、信号处理和进程间通信
1.3.7 文件系统
1.3.8 TCP/IP和网络编程
1.4 目标读者
1.5 本书的独特之处
1.6 将本书用作系统编程课程的教材
1.7 其他参考书
1.8 关于Unix
Unix是一种通用操作系统(定义)
诞生于20世纪70年代早期(时期)
肯.汤普森和丹尼斯.里奇(创作人)
PDP-11微型计算机 (开发机器)
1975年 (发布时间)
1.8.1 AT&T Unix
美国电话电报公司开发
单CPU系统,20世纪80年代后期,该系统被扩展为多处理器版本
1.8.2 Berkeley Unix
伯克利软件发行中心在1977-1985开发的一组Unix操作系统变体
实现了TCP/IP协议族和套接字接口
1.8.3 HP Unix
惠普公司开发的专有Unix操作系统
第一版发布于1984年
可代替Unix标准rwx文件权限的内置逻辑卷管理器
1.8.4 Sun Unix
Sun公司开发
以其可扩展性而闻名
1.9 关于Linux
Linux是一个类Unix系统(定义)
林纳斯.托瓦兹 (项目发起人)
Intel X86个人计算机 (开发机器)
纳入了许多GUN软件 (特性)
1991年 (开发时间)
免费使用、易于安装、兼容性强(优点)
1.10 Linux版本
1.10.1 Debian Linux
专注于免费软件
1.10.2 Ubantu Linux
同一套软件可用于所有变体
1.10.3 Linux Mint
社区主导型
纳入一些专有软件
提供完全开箱即用多媒体支持
1.10.4 基于RPM的Linux
分为两种版本,商业和社区
1.10.5 Slackware Linux
以高度可定制而著称
1.11 Linux硬件平台
1.12 虚拟机上的Linux
1.12.1 VirtualBox
1.12.2 VMware
1.12.3 双启动Slackware和Ubuntu Linux
1.13 使用Linux
1.13.1 Linux内核映像
在典型的Linux系统中,内核映像位于/boot目录中
内核映像由三部分组成
BOOT 512字节的启动程序 现已不用于启动
SETUP 一段16位和32位的汇编代码 用于转换保护模式
linux kernel是实际内核 用于解压内核映像并放入内存中
1.13.2 Linux启动程序
最受欢迎的启动加载程序是GRUB和LILO
1.13.3 Linux启动
Linux内核的两阶段启动
1.13.4 Linux运行级别
多用户模式运行
1.13.5 登录进程
三个文件流
stdin 用于输入
stdout 用于输出
stderr 用于错误输出
1.13.6 命令执行
cd 更改目录
exit 退出
logout 注销
1.14 使用Ubuntu Linux
1.14.1 Ubuntu版本
推荐15.10或更高版本
易于安装
易于安装额外安装包
定期更新何改进
拥有庞大的用户群
方便连接无线网和接入互联网
1.14.2 Ubuntu Linux的特性
验证用户密码
可更改路径
提示用户执行命令
必须安装插件才能生成32位代码
GUI用户界面
支持有线无线网络
1.15 Unix/Linux文件系统组织
1.15.1 文件类型
(1)目录文件
(2)非目录文件
常规文件
特殊文件
字符特殊文件
块特殊文件
(3)符号链接文件
1.15.2 文件路径名
1.15.3 Unix/Linux命令
1.15.4 Linux手册页
1.16 Ubuntu Linux系统管理
1.16.1 用户账户
1.16.2 添加新用户
sudo adduer
1.16.3 sudo命令
username ALL(ALL) ALL
第二章:编程背景
2.1 Linux中的文本编辑器
2.1.1 vim
三种不同的操作模式:命令模式、插入模式、末行模式
命令模式:用于输入命令
插入模式:用于输入和编辑文本
末行模式:用于保存文件并退出
1移动光标的命令键(命令模式)
h:左移一位
l:右移一位
j:下移一位
k:上移一位
2输入文本进行编辑(插入模式)
i:插入文本
a:追加文本
esc:退出插入模式
3命令模式下输入“:”(末行模式)
:w:写入文件(保存)
:q:退出
:wq:保存并退出
:q!强退
2.1.2 gedit
gedit是GNOME桌面环境默认的文本编辑器
2.1.3 emacs
emacs是一款强大的文本编辑器,可在多个不同的平台上运行
以上所有编辑器都支持直接输入、全屏模式下的文本编辑、关键字搜索和用新文本替换字符串。
2.2 使用文本编辑器
2.2.1 使用emacs
2.2.2 emacs菜单
2.2.3 emacs的集成开发环境
2.3 程序开发
2.3.1 程序开发步骤
(1)创建源文件
使用文本编辑器创建一个或多个程序源文件(使用C语言或汇编语言)
其中C语言程序中有五种变量:
全局变量 函数外定义 唯一性
局部变量 函数内定义
静态变量 静态全局和非静态全局 可见范围不同
自动变量 调用时出现,退出时消失
寄存器变量 分配在CPU寄存器中
(2)用gcc把源文件转换成二进制可执行文件
如:gcc t1.c t2.c生成一个二进制可执行文件,文件名为a.out
(a.out是”assembler output”的缩写格式,代表汇编程序输出。在较早版本的类unix系统中,a.out是一种输出格式,用于可执行文件,目标文件和共享库。早期的 PDP-7系统上没有链接器,程序的创建过程是先把所有源文件连接成一个文件,然后进行汇编,产生的汇编程序保存在a.out中。这样a.out是名副其实的汇编输出,但到PDP-11之后,人们为其编写了链接器,程序的创建是先编译然后链接输出保存到a.out中,这时a.out其实已经是链接输出了,但输出的可执行文件仍然延续这个命名习惯。)
(3)gcc是什么?
gcc是一个程序,包含三步骤
将C源文件转换为汇编代码文件 .c>>.s
把汇编代码转换成目标代码 .s>>.o
链接
2.3.2 静态与动态链接
静态链接 (静态库)
链接器将所有必要的库函数代码和数据纳入a.out文件中
特点:a.out文件完整、独立,但非常大
动态链接 (共享库)
库函数未包含在a.out文件中,但是此类函数的调用以指令形式记录在其中
特点:减小文件的大小、可共享相同的库函数、修改库函数无需重新编译源文件
2.3.3 可执行文件格式
(1)二进制可执行平面文件
包含可执行代码和初始化数据,便于直接执行
(2)a.out可执行文件
包含文件头、代码段、数据段和bss段
(3)ELF可执行文件
包含一个或多个程序段,更适合动态链接
2.3.4 a.out文件的内容
(1)文件头 包含文件的加载信息和大小
(2)代码段 包含程序的可执行代码
(3)数据段 包含初始化全局变量和初始化静态数据
(4)符号表 仅为运行调试所需
注:bss段(未初始化全局变量和未初始化静态局部变量)和自动局部变量不在文件中
2.3.5 程序执行过程
在类unix操作系统中,在sh命令行 “a.out one two three”执行a.out文件,已标记字符串作为命令行参数。未执行命令,sh创建一个子进程并等待该子进程终止。
按照以下步骤创建新的执行映像:
(1)读取a.out文件头,确定所需的总内存大小,包括堆栈空间大小:
(2)sh从总大小中分配一个内存区给执行映像
(3)然后sh放弃旧映像,执行新映像
(4)执行从crt0.o开始,调用main(),将argc和argv作为参数传递给main()
2.3.6 程序终止
正常终止:如果程序执行成功,main()最终会返回到crt0.o调用库函数exit(0)进行清理工作,然后发出系统调用来终止进程
异常终止:在执行a.out时,进程可能会遇到错误,如无效地址、非法指令、越权等,会被识别为异常,然后将错误类型转换成信号,传递给进程使进程终止
2.4 C语言中的函数调用
2.4.1 32位GCC中的运行时堆栈使用情况
此处以书上例题为原型进行总结
(1)执行a.out文件时,先创建一个进程映像,其中包含bss段
(2)每个CPU中有以下寄存器
PC(IP) 指向CPU要执行的下一条指令
SP(SP) 指向栈顶
FP(BP) 指向当前激活函数的栈帧
返回值寄存器(AX) 返回值的寄存器
(3)main函数由crt0.o调用
(4)C函数入口,编译代码运行为变量分配空间
(5)CPU执行代码,将变量放入分配的空间
(6)main函数调用sub函数,使CPU进入sub函数(对此处倒序推送参数理解不是很充分)
(7)激活函数sub让指针FP进行下移,为sub函数中变量分配空间
(8)计算机进行计算后给出返回值,AX捕捉返回值,清除参数,继续执行
2.4.2 long jump
long jump程序可以实现函数的跳跃,若有两个函数A和B在主函数中,使用该程序给B,即可直接跳过A给出返回值
2.4.3 64位GCC中的运行时堆栈使用情况
在该模式,CPU扩展为rax、rbx、rcx、rdx、rbp、rsp、rsi、rdi、r8到r15
GCC编译器生成的代码可保持堆栈指针固定不动,默认保留红色区域128字节
不同于32位,该模式使用栈帧指针rbp来访问参数和局部变量
2.5 C语言程序与汇编代码的链接
2.5.1 用汇编代码编程
1.将C代码编译成汇编代码
2.汇编代码说明
三部分组成:入口代码、函数体代码、退出代码
2.5.2 用汇编语言实现函数
看书上例题
2.5.3 从汇编中调用C函数
看书上例题
2.6 链接库
静态链接库和动态链接库
2.6.1 静态链接库
(1)gcc -c xx.c
(2)ar rcs xx.a xx.o
(3)gcc -static xx.c -L -lmylib
(4)a.out
注:-L指定路径 -l指定链接库
2.6.2 动态链接库
(1)gcc -c -fPIC xx.c
(2)gcc -shared -o xx.so xx.o
(3)gcc xx.c -L -lmylib
(4)export LD_LIBRARY_PATH=./
(5)a.out
注:设置LD_LIBRARY_PATH,以指向包含数据库的目录
2.7 makeflie
2.7.1 makeflie格式
一个make文件由一系列目标项、依赖项和规划组成
目标项:创建或更新的文件 引用的指令或标签
依赖项:源文件、目标文件、或其他目标项
规划:使用依赖项列表构建目标项所需的命令
2.7.2 make程序
通过比较依赖项中源文件的时间戳确定构建哪些目标项
2.7.3 makefile示例
看书上例题
makefile变量:makefile支持变量还包含自动变量
$@ 当前目标名
$< 第一个依赖项名
$^ 所有依赖项名
$* 不包含扩展名的当前依赖项名
$? 比当前目标更新的依赖项列表
2.8 GDB调试工具
GNU调试工具(GDB)是一个交互式调试工具,可以调试用C、C++和其他几种语言编写的程序
2.8.1 在emacs IDE中使用GDB
(1)源代码
gcc -g -o t xx.c(-g用来标记)
(2)编译源代码
make -k
(3)启动GDB
gdb -i=mi t
设置断点
b main
b sub
b 10
(4)多窗口GDB
打印全局变量
p g
p h
(5)附加GDB命令
清除断点
clear line#
clear name
更改变量值
set var a =100
set var b =200
监视变量值改变
watch c每次变化显示新旧值
回溯追踪
bt stackFrame#回溯追踪栈帧
2.8.2 有关使用调试工具的建议
所有调试工具之能提供有限的帮助
2.8.3 C语言程序中的常见错误
(1)未初始化的指针或含有错误值的指针
(2)数组下标越界
(3)字符串指针和char数组使用不当
(4)assert宏
(5)在程序代码中使用fprintf和getchar
2.9 C语言结构体
2.10 链表处理
2.11 树
2.12 二叉树
以上2.9-2.11在之前的学习中已经学过,查看以往笔记即可