文章目录
0.前言
os课程的视频回放:
南大操作系统课视频回放
往期南大课程笔记
本章节课程实验M1: M1: 打印进程树
1.概述
jyy推荐的库
- z3: 求解任何逻辑方程组的工具
- sympy: 可以用于符号计算
1.1 为什么要学操作系统
1.2 什么是操作系统
- 从硬件视角来看: 操作系统就是一个c程序, 只管取指执行就行
- 从软件视角来看: 操作系统是一个库里面包含有大量的对象和API
1.3 怎么学习操作系统
- 读可靠的教材
- Operating Systems: Three Easy Pieces
- Computer Systems: A Programmer’s Perspective
- The Art of Readable code
- 问题驱动, 不怕写代码.
问: 怎么删除代码复制过来时候的行号?
答: vscode中Alt+shift
, 使用鼠标拖动范围即可, 再统一删除
2.应用视角下的操作系统
计算机=数字电路=状态机
同时课上提到的通过非递归来实现递归可以查看博客: 非递归方法实现递归
2.1 理解高级语言程序
函数是由很多个栈帧组成的, 每一个栈帧都有一个pc值, 函数调用的本质就是, 在栈顶上添加新的一帧, 该帧的pc为0; 函数的返回则是, 将栈顶"pop"掉; 函数的执行, 取栈顶上pc值对应的语句执行.
所以所谓的C语言其实就是一个状态机:
-
状态: 栈帧列表和全局变量组成
-
初始状态: main函数的第一条语句
-
状态迁移:
- 执行frames.top.PC处的简单语句
- 函数调用 = push frame
- 函数返回 = pop frame
2.2 操作系统上的软件
系统上只有一个进程(程序)有访问屏幕操作的权限, 所有的程序vscod, xedit都是对该程序进行send和receive.
所以所有的程序, 都是计算一个状态机, 然后执行系统调用
strace
的使用
- 使用类似
strace ls |& grep -e read -e write
来简化strace
的结果. strace -o trace.txt your_command
可以保存strace
的结果, 同时保证you_command
的正常执- 将多条命令的系统调用序列拼接起来
strace -o trace.txt command1
strace command2 >> trace.txt 2>&1
strace command3 >> trace.txt 2>&1
# 2>&1: 表示将标准错误(文件描述符2)重定向到标准输出(文件描述符1)
2.3 系统调用示例
命令(xxxxxxx) = -1 XXX
: "= -1"通常表示该系统调用失败, XXX表示错误码, 表示具体的错误原因:
EINVAL
: 该错误码表示传递给系统调用的参数有误ENOENT
: 该错误码表示指定的文件或目录不存在
openat
: 用于打开文件或目录, 调用成功返回文件描述符
mmap
: 用于将一个文件的一部分映射到进程的地址空间, 调用成功返回映射的起始地址
execve
: 用于在新的进程中执行一个可执行文件
arch_prctl
: 用于调整进程或线程的架构相关参数
newfstatat
: 用于获取文件状态信息,
3.硬件视角下的操作系统
程序编译链接流程:
- .c -> 预编译 -> .i -> 编译 -> .s -> 汇编 -> .o -> 链接 -> a.out
硬件厂商会约定好CPU Reset后的状态, 主板厂商只要提供Firmware, 主板上的固件通常被称为BIOS(基本输入/输出系统)或UEFI(统一扩展固件接口.
如今Firmware面临更多的硬件, 所以需要UEFI.
BIOS提供机制, 将程序员的代码(操作系统)载入内存
- 以 Legacy BIOS为例, 它将第一个可引导扇区的第一个512字节加载到物理内存的7c00位置
3.1 调试MBR
mbr.img: mbr.S
gcc -ggdb -c $<
ld mbr.o -Ttext 0x7c00
objcopy -S -O binary -j .text a.out $@
run: mbr.img
qemu-system-x86_64 $<
debug: mbr.img
qemu-system-x86_64 -s -S $< & # Run QEMU in background
gdb -x init.gdb # RTFM: gdb (1)
clean:
rm -f *.img *.o a.out
-s
: 在tcp的1234端口打开gdbserver
-S
: 不启动cpu
3.2 编译运行操作系统内核
以hello.c
为例
NAME := hello
SRCS := hello.c
export ARCH := x86_64-qemu
# 执行make run, 会启动一个qemu的虚拟机, 通过该虚拟机来执行SRCS
include $(AM_HOME)/Makefilesole
# 虚拟机build的操作
(
cat $AM_HOME/am/src/x86/qemu/boot/bootblock.o;
head -c 1024 /dev/zero;
cat /home/ziqiang/os2023/3-Demo2/build/hello-x86_64-qemu.elf
) > /home/ziqiang/os2023/3-Demo2/build/hello-x86_64-qemu
运行的程序就称为进程
4.Python建模操作系统
问: 什么样的指令序列可以调用c++中的虚函数.
答: (ChatGPT的答案)
C++ 中的虚函数调用是通过虚函数表(vtable)实现的。当对象被创建时,一个指向虚函数表的指针(vptr)被添加到对象的内存布局中。每个类都有自己的虚函数表,其中包含类的虚函数的地址。当调用虚函数时,程序会使用 vptr 找到正确的虚函数。
在汇编语言层面,对虚函数的调用可能涉及到加载 vptr 的值、查找虚函数表、获取函数地址并跳转到函数等操作。
应用中,关心的两种东西:
- 纯粹的计算(内存的数据结构->内存中的数据结构)
- 系统调用
程序就是个状态机
def main():
x = sys_choose(['Head', 'Tail'])
x = x.lower()
sys_write(f'{x}\n')
上述程序的状态机如下:红字说明是系统调用,当执行write
系统调用时,程序本身的状态没有发生改变(x='head'
),圆圈是程序的状态,方框是操作系统的状态
操作系统就是状态的管理者, 本身可以容纳多个状态机
线程可以有共享的内存, 而进程只有独立的内存能够访问
系统调用——切换线程的做法:
- 封存当前状态机的状态
- 恢复另一个被封存的状态机的执行
后面就是看jyy操作的时候,太秀了55555
补充学习
- yield关键字
- 小的编程技巧,如何在main函数执行之前或执行结束的时候再执行一部分代码