jyyOS-1
源代码程序是状态机
- 状态 = 堆 + 栈
- 初始状态 =
main
的第一条语句 - 迁移 = 执行一条简单语句
- 任何 C 程序都可以改写成 “非复合语句” 的 C 代码
¶C程序的语义
- 状态 = stack frame 的列表 (每个 frame 有 PC) + 全局变量
- 初始状态 = main(argc, argv), 全局变量初始化
- 迁移 = 执行 top stack frame PC 的语句; PC++
- 函数调用 = push frame (frame.PC = 入口)
- 函数返回 = pop frame
非递归汉诺塔:switch模拟状态机,把不同状态的frame放入call中
1 | typedef struct { |
二进制程序是状态机
- 状态 = 内存 + 寄存器
- 初始状态 = (稍后回答)
- 迁移 = 执行一条指令
¶操作系统上的程序
所有的指令都只能计算
- deterministic: mov, add, sub, call, …
- non-deterministic: rdrand, …
- 但这些指令甚至都无法使程序停下来
¶特殊指令:syscall
-
把内存M、寄存器R完全交给操作系统,任其修改
-
实现与操作系统中的其他对象交互
- 读写文件/操作系统状态 (例如把文件内容写入M )
- 改变进程 (运行中状态机) 的状态,例如创建进程/销毁自己
¶程序 = 计算 + syscall
在程序的两个视角之间切换
“状态机” 顺便解决了一个非常重要的基本问题:什么是编译器?
编译器:源代码S (状态机) → 二进制代码C (状态机)
编译 (优化) 的正确性 (Soundness):
- S与C的可观测行为严格一致
- system calls; volatile variable loads/stores; termination
- Trivially 正确 (但低效) 的实现
- 解释执行/直接翻译S的语义
操作系统中的一般程序
操作系统收编了所有的硬件/软件资源
- 只能用操作系统允许的方式访问操作系统中的对象
- 从而实现操作系统的 “霸主” 地位
- 这是为 “管理多个状态机” 所必须的
- 不能打架,谁有权限就给他
¶二进制程序状态机的初始/结束状态
main()
的开始/结束并不是整个程序的开始/结束
gdb info proc {mappings,...}
- 打印进程内存
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 慎治の万事屋!