什么是可执行文件

一个数据结构,描述了状态机初始状态和迁移

动手

试着使用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越来越复杂