什么是可执行文件
一个数据结构,描述了状态机初始状态和迁移
动手
试着使用strace观察(可执行)文件的执行 execve在以下各种情况的返回值(在文档中均有描述) 1.没有执行权限的文件 2.非可执行文件 3.设备
execve的interpreter script
shebang的语法是#!
个人猜测可能类似vim中!的用途
通过编写一个打印所有参数的程序,可以验证shebang的行为似乎就是替换execve参数实现
Warning
./a.out arg1 arg2
arg数组长度为3
shell脚本中0为文件名。python中arg数组从文件名开始
binutils
数据结构的查看/操作工具
什么是编译器
将C状态(语句 stackframe)
翻译成机器视角(指令 内存 寄存器)以及debug info
debug info用来做反向的过程,可以从机器的某个运行状态回推当前对应的代码,但是并不太好做
stack unwinding
似乎说的就是打印某个时刻函数调用栈的信息
在xv6中做过,通过栈上的返回地址不断回跳
jyy这里做的更巧妙,使用了链表来描述这个过程
增加了O2优化之后,这个方法就不行了,但是gdb仍然一定程度上能做到 👍
重定位(Relocation)
完成那些之前不能确定的(即引用外部的?)符号的引用处的地址的填写
需要满足assertion
0xa hello(); // callq 5个字节
0xf 某个语句;
assert( (char *)hello ==
(char *)main + 0xf + // call hello 的 next PC
*(int32_t *)((uintptr_t)main + 0xb) // call 指令中的 offset );应该是因为x86指令集的跳转约定是跳到下条指令加上offset的地址,offset是我们要填的东西
理解了这段就可以理解elf中的约定
Offset Type Sym. Name + Addend
00000000000b R_X86_64_PLT32 hello - 4将S+A-P填入
P是要填入的起始位置(main+0xb)
S是调用的函数
A是-4,应该是要填入的位置的末尾到开头的偏移?
P17的其他内容
进程初始化时候内存设置的spec
rsp指向存放arg的内存位置…
两个loader的实现简述
动态链接
将应用程序打散
主要是运用了这个机制
call *func(%rip)目前的合理理解是func是符号,func这个位置存放了所需的函数的绝对地址
在export的func中存放了func相对于dl文件头的偏移,加上实际加载到内存空间后的首地址就得到了func函数的实际地址
func(%rip)计算func这个标志的位置相对于rip的偏移量,反正call能跳转到func标志中指向的函数
void Tsum() {
for (int i = 0; i < N; i++) {
int t = load(sum);
t += 1;
store(sum, t);
}
}假设每行语句原子
对于多个线程执行该程序的最小可能sum结果为2
我的目前理解是
一个线程读到t=sum=0,t++,然后让另一个线程执行到最后一轮,再让前一个线程保存sum=1,让另一个线程读t=sum=1,t++,然后直到所有线程结束再写回,得到2
p15的其他内容
vsc,np complete问题,3sat
文件描述符fork和dup时共享偏移量,并且操作是原子的
xv6中做过的cow
fork的几个用处
并行搜索 快速回溯 也可以backtrack的时候一下子往回跳到某个状态而不是一步步 状态复用 fork一份完成了初始化的系统(nemu,android) 容错试错 如果某个错误只有极小概率触发呢?
a fork in the road
随着系统加入更多东西,fork越来越复杂