Operating System Services
注:
- system call 就是 user space 和 kernel space 之间的桥梁
- 红圈内的就是为用户提供服务(抽象资源),蓝圈内的就是优化服务(分配资源)
User and Operating System-Interface
(略)
System Calls
解释:
1. printf
本质上就是 write
的一个 wrapper
2. write
函数(i.e. 上面的 __libc_write
),里面有一个 syscall,将控制流从用户手中交给系统
3. 注意 %eax
为 1
,因为 Linux x86 的 syscall 的 1 号就是 write
解释:进入 kernel space 之后,就做下面三件事
1. 无论如何,kernel_entry
的代码先会被执行
2. 然后根据传入的 %eax
,从 syscall_table
中获取 ksys_write
的地址并 call
3. 在完成之后,执行 ret_to_user
,并最终返回用户态
图示
syscall 的完整流程如上
Types of System Calls
System Services
(略)
Linkers and Loaders
注:中间缺了一个预处理环节
ELF Format
使用 readelf
查看 ELF 格式文件
readelf -S <file>
:获取<file>
的分区信息,各分区的(虚拟内存)地址、(文件中对应的)偏移量、权限等等readelf -s <file>
:获取符号表,以及各符号的所在地址、所在分区编号、类型、名字等等readelf -p <section> <file>
: Displays the contents of the indicated section as printable strings.readelf -x <section> <file>
: Displays the contents of the indicated section as a hexadecimal bytes.
Answer to quiz:
1. 所有 const
都去 .rodata
2. 对于非 const
,若已经初始化,就去 data
3. 若尚未初始化,就去 bss
如下图所示:
[Nr] Name Type Address Offset Flags
[15] .rodata PROGBITS 00000000000007e0 000007e0 AX
[22] .data PROGBITS 0000000000011000 00001000 WA
[23] .bss NOBITS 0000000000011014 00001014 WA
Note: A(alloc), X(execute), W(write)
Details of Loader
a.dynamic
就是动态编译(也是默认编译选项)的产物。其中 .interp
段指定了解释器。
Running a binary
对于动态加载库的 elf 文件,在操作系统上运行,初始化如下:
- Who setups ELF file mapping
- Kernel: exec
syscall
- Kernel: exec
- Who setups stack and heap
- Kernel: exec
syscall
- Kernel: exec
- Who setups libraries
- Loader:
ld-xxx
- Loader:
动态/静态链接的 syscall
对比
执行 a.dynamic
的时候,可以看到用到了 ld.so
至于 a.static
(左图),相比 a.dynamic
(右图),就会少很多各种加载
动态/静态链接的内存布局对比
a.static
如下,很干净:
a.dynamic
如下,在 heap
和 vvar
之间,有 libc
的动态链接库(不同虚拟内存,映射到同一个文件,但是权限不同);在 vdso
和 stack
之间,就是 loader 的动态链接库(同上)
动态/静态链接执行流程对比
如图:上面是静态,下面是动态。区别就一点:动态的时候,load_elf_binary
直接跳转至 loader 的起始地址(而不是二进制程序的起始地址)。
然后 loader 进行一通操作(i.e. mmap
),将动态链接库文件(e.g. libc
)映射到内存中,最后再跳至 _start
。
Why Applications are Operating System Specific Operating-System Design and Implementation
Operating System Structure
TL;DR
Linux Kernel 一览
Different Kernels
- 宏内核(Monolithic Structure):各种 driver 等等辅助组件都在 kernel 内部,并且通过 privileged mode 运行
- PROS
- 速度快
- CONS
- 内核代码多,不易移植和扩展
- 如果 driver 在内核态运行过程中崩溃,那么就容易导致整个系统崩溃,稳定性差
- 安全性相对差
- PROS
- 微内核(Microkernel):不那么重要而 drivers,就不在 kernel 内部,并且在用户态下运行
- PROS
- 内核代码少,易于移植和扩展
- 尽量不在内核态中执行,稳定性好
- 安全性好
- CONS
- 由于很多模块位于用户态中,但是又必须通过
syscall
来执行关键步骤、传递信息,因此调用链长,速度慢(如下图)
- 由于很多模块位于用户态中,但是又必须通过
- PROS
- hybrid kernel:前两者混合,取长补短
微内核调用链
Building and Booting an Operating System
(略,见 lab0)
Operating System Debugging
工具一览
Rules of thumb:
- Remember the separation of policy and mechanism
- log(包含
printk
和 core dump 等等)为主,gdb 为辅 - 不要在代码中用 tricks,尽量多加注释、简洁明了
- 推荐工具
strace
- trace system calls invoked by a processgdb
- source-level debuggerperf
- collection of Linux performance toolstcpdump
- collects network packets