蒋岩炎老师 2024spring 操作系统第二课。
- 如何用一行代码破坏不好的 oj:无限长的随机数
#include "/dev/urandom"
- 指令集里没有一条关闭计算机的指令,如何关闭计算机?
由电路操控
syscall 指令,状态机完全交给计算机
- 任何程序 = minimal.s = 状态机
- 应用程序 = 计算 + 操作系统 API
操作系统,从应用程序的视角来看,就是 syscall,提供各种系统的 api
操作系统的职责:提供令应用程序舒适的抽象(对象 + api)
- C 语言是怎么变成二进制代码的?
- 预处理
- 编译,代码 -> 汇编语言
- 汇编,汇编语言 -> 机器代码
- 链接,将目标文件和所需库文件合并 -> 可执行文件
【汉诺塔:递归版本到非递归版本的实现】
# 编程
# Minimal
早期 C 语言由于资源限制和编译器限制,允许程序员做调用 “未声明的函数”
但在现代编译器中, -Wimplicit-function-declaration
是一个在 C 语言编译过程中使用的编译器选项,这个选项的作用是让编译器发出警告,如果源代码中有函数被调用却没有事先声明,就会触发这个警告。
#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
尝试链接中间产物(经过编译器编译,但是没有链接的中间产物,目标文件包含了源代码编译后的机器语言代码)
objdump -d hello.o
gdb 的一些用法:
gdb a.out
starti
layout asm
layout src
si
q
info re
为什么以下程序编译的时候出现了 segmentation fault?
int main() {
}
https://www.cnblogs.com/bangerlee/archive/2012/05/22/2508772.html
也许你会问:咦?以上 disassemble 的输出不是 main 函数的汇编指令吗,怎么输出中也有上面两条指令?难道 main 也是一个 “被调函数”?
是的,皆因 main 并不是程序拉起后第一个被执行的函数,它被_start 函数调用,更详细的资料参看这里。
retq 相当于:popq % rip; retq 对应的是 callq,相当于:pushq % rip【% rip 存的是它永远指向下一条即将执行的地址。】
加了 #include<stdio.h>
之后,从 main 函数返回的地址不再是 0
最小汇编:
make minimal
strace 命令的使用:
strace -f gcc -o hello hello.c
如何化简 strace 的命令输出,gcc 打开的文件比较重要,编译汇编命令在哪里:
strace -f gcc -o hello hello.c 2>&1 | vim -
:将输入输出给 vim 编辑%!grep -v -e '-1'
在编辑器里面进行筛选,!
表示执行外部指令,-v
表示反向选择%!grep -e read
正向选择,-e
表示正则筛选
# 非递归汉诺塔
(todo)