蒋岩炎老师 2024spring 操作系统第二课。

  1. 如何用一行代码破坏不好的 oj:无限长的随机数
#include "/dev/urandom"
  1. 指令集里没有一条关闭计算机的指令,如何关闭计算机?

由电路操控

syscall 指令,状态机完全交给计算机

  1. 任何程序 = minimal.s = 状态机
  2. 应用程序 = 计算 + 操作系统 API

操作系统,从应用程序的视角来看,就是 syscall,提供各种系统的 api

操作系统的职责:提供令应用程序舒适的抽象(对象 + api)

  1. C 语言是怎么变成二进制代码的?
    1. 预处理
    2. 编译,代码 -> 汇编语言
    3. 汇编,汇编语言 -> 机器代码
    4. 链接,将目标文件和所需库文件合并 -> 可执行文件

【汉诺塔:递归版本到非递归版本的实现】

# 编程

# Minimal

早期 C 语言由于资源限制和编译器限制,允许程序员做调用 “未声明的函数”

但在现代编译器中, -Wimplicit-function-declaration 是一个在 C 语言编译过程中使用的编译器选项,这个选项的作用是让编译器发出警告,如果源代码中有函数被调用却没有事先声明,就会触发这个警告。

image-20240402003629676

#include 只是做了一个复制粘贴的动作。

比如说,你可以使用 #include '/dev/urandom' 来轰炸 oj

objdump -d a.out | less 查看二进制文件,但太过复杂

file a.out 确定文件的类型

gcc 的一些用法:

gcc hello.c -static 静态链接库

gcc --verbose hello.c 啰嗦一点

gcc -c hello.c compile and assemble, but do not link 生成 hello.o 文件

ld hello.o 尝试链接中间产物(经过编译器编译,但是没有链接的中间产物,目标文件包含了源代码编译后的机器语言代码)

image-20240402003653374

objdump -d hello.o

gdb 的一些用法:

gdb a.out
starti
layout asm
layout src
si
q
info re

为什么以下程序编译的时候出现了 segmentation fault?

int main() {
}

image-20240402003713140

https://www.cnblogs.com/bangerlee/archive/2012/05/22/2508772.html

也许你会问:咦?以上 disassemble 的输出不是 main 函数的汇编指令吗,怎么输出中也有上面两条指令?难道 main 也是一个 “被调函数”?

是的,皆因 main 并不是程序拉起后第一个被执行的函数,它被_start 函数调用,更详细的资料参看这里

retq 相当于:popq % rip; retq 对应的是 callq,相当于:pushq % rip【% rip 存的是它永远指向下一条即将执行的地址。】

image-20240402003733663

加了 #include<stdio.h> 之后,从 main 函数返回的地址不再是 0

最小汇编:

make minimal

strace 命令的使用:

strace -f gcc -o hello hello.c

如何化简 strace 的命令输出,gcc 打开的文件比较重要,编译汇编命令在哪里:

  1. strace -f gcc -o hello hello.c 2>&1 | vim - :将输入输出给 vim 编辑
  2. %!grep -v -e '-1' 在编辑器里面进行筛选, ! 表示执行外部指令, -v 表示反向选择
  3. %!grep -e read 正向选择, -e 表示正则筛选

# 非递归汉诺塔

(todo)