操作系统 - 系统以下
操作系统 - 系统以下
物理内存 vs 程序员眼中的内存
内存的物理机制
- 内部部分 - 内存集成电路
 
- 引脚 (接口) 部分 - 有多个电路引脚 (以那种单片机上黑色的22引脚的小内存为例) - (2) VCC 电源,GND 电源
- (10) A0-A9 地址信号引脚。= 10位 = 1024个地址 = 索引1024Byte的空间
- (8) D0-D7 数据信号引脚。= 8位 = 一字节 = 每个地址可以存储8个字节
- (2) RD WR 控制信号引脚。即读还是写
 
- 信号引脚中,通过5V高电平,0V低电平,来表示10
- 顺序 - 写则依次:(1) 指定地址、(2) 输入数据、(3) 将WR设为1
- 读则依次:(1) 制定地址、(2) 将RD设为1、(3) 从数据引脚中获取
 
 
- 有多个电路引脚 (以那种单片机上黑色的22引脚的小内存为例) 
字节序
详见CSAPP或内存管理相关笔记
高级语言、汇编语言、机器语言
略,详见CSAPP
objdump -d -S hello.o // -S可以看对应的C语言语句
不过还是Godbolt香 (戈伯特)
CPU执行过程
物理
集成电路,根据指令处理各种处理的电子电路,每个指令对对应相应的电子电路工作
- 控制器:负责传入寄存器,得到结果后控制计算机
- 寄存器 (20~100个):暂存指令、数据等(PC(计数器)有可能也在这个位置,例如IP就是指令指针寄存器)
- 运算器:运算
流程
- 读取:CPU从内存中读取指令
- 解码:将10串拆成操作码和操作数,知道要去执行什么操作
- 执行
- (循环,根据计数器(PC)循环)
CPU指令集
- arm架构CPU
- X86架构CPU
查看CPU架构
- windows:systeminfo,找 "系统类型" 一栏
- linux:lscpu,找 "Architecture" 一栏
常用指令
详见SCAPP
- mov A,B
- add A,B
- push A
- pop A
- call A
- ret 无
常用操作数
- 寄存器 - rbp (register base pointer):栈基址寄存器(栈帧指针),指向当前帧的栈底地址
- rsp (register stack pointer):栈顶寄存器(栈指针),指向栈顶元素
- (函数调用时会使用上面两个)
- rip:存储下一条指令的内存地址
 
- 内存
- 常数
程序 - 机器码 的对应
函数调用
int mod(int a, int b) {
    return a % b;
}
int add(int a, int b) {
    int res = mod(a, b);
    return res + b;
}
void main() {
    int a = 3;
    int b = 2;
    int c = add(a, b);
}函数调用栈
- 函数调用链:main -> add -> mod -> add -> main
- 每个栈帧会包含: - 参数值
- 局部变量
- 返回地址 (出栈时使用,并返回对应的位置)
 
汇编:
000000000000000 <mod>
	push rbp			# 栈基址
	mov rbp, rsp
	……
	pop rbp				# 将rbp和rsp退出上一个栈中。退回地址:rbp退回到他指向的地址
	ret					# 回调。回调地址:rip存着
	
000000000000015 <add>
	push rbp			# 栈基址
	mov rbp, rsp
	……
	call 32 <add+0x1d>	# 调用mod函数
	mov DWORD PTR [rbp-0x4], eax
	……
	leave				# = mov rbp, rsp + pop rbp
	ret
	
00000000000003f <main>
	push rbp			# 栈基址
    mov rbp, rsp
	……
	call 64 <main+0x25>	# 调用add函数
	mov DWORD PTR [rbp-0xc], eax
	leave
	retmain函数不是第一个被调用的函数,被名为start函数调用。在执行main函数之前,就已经存在栈帧了
其他指令
if 指令
void main() {
    int a = 3;
    int a = 2;
    int c;
    if (a == b) {
        c = a + b;
    } else {
        c = a - b;
    }
    return c;
}汇编
000000000000000 <main>
	push rbp
	mov rbp, rsp
	# int a = 3;
    mov DWORD PTR [rbp-0x8], 0x3
    # int b = 2;
    mov DWORD PTR [rbp-0xc], 0x2
    # int c;
    # if (a == b) {
    mov eax, DWORD PTR [rbp-0x8]
    cmp eax, DWORD PTR [rbp-0xc]	# cmp =compare,比较结果放在条件码寄存器(标志位寄存器)
    jne 27 <main+0x27>				# jnp = jump if not equal,会去查看条件寄存器的零标志位
    mov eax, DWORD PTR [rbp-0xc]
    	# c = a+b;
    mov edx, DWORD PTR [rbp-0x8]
    add eax, edx
    mov DWORD PTR [rbp-0x4], eax
    jmp 34 <main+0x34>
    # } else {
    #  	  c = a - b
0x0027
	mov eax, DWORD PTR [rbp-0xc]
	mov edx, DWORD PTR [rbp-0x8]
	sub edx, eax
	mov eax, edx
	mov DWORD PTR [rbp-0x4], eax
	# }
	# return c;
0x0034
	mov eax, DWORD PTR [rbp-0x4]
	# }
	pop rbp
	retfor 指令
int main() {
    int a = 0;
    for (int i = 0; i < 3; i++) {
        a += i;
    }
    return a;
}汇编
000000000000000 <main>
	push rbp
	mov rbp, rsp
	# int a = 0;
	mov DWORD PTR [rbp-0x4], 0x0
	# for (int i = 0; i < 3; i++) {
	mov DWORD PTR [rbp-0x8], 0x0
	jmp 1e <main+0x1e>
	#     a += i;
0x0014
	mov eax, DWORD PTR [rbp-0x8]
	add DWORD PTR [rbp-0x4], eax
	# int main() {
	#     int a = 0;
	#     for (int i = 0; i < 3; i++) {
	add DWORD PTR [rbp-0x8], 0x1
0x001e
    cmp DWORD PTR [rbp-0x8], 0x2
    jle 14 <main+0x14>
	#         a += i;
	#     }
	#     return a;
	mov eax, DWORD PTR [rbp-0x8], 0x4
	# }
	pop rbp
	retgoto
C语言有个goto指令,可以代替条件控制。用那个来代替 if、for 等流程控制(或者说在流程控制出来前就是这样做的),应该就很好理解了
链接到当前文件 0
没有文件链接到当前文件