先说说逻辑地址:
我们时常会看到一种地址的表述方式——segment:offset,比如0x0:0x7c2d
这里的地址表述方式是逻辑地址方式,在没有开启分段机制之前,物理地址的寻址通过这种方式。
相关的,segment:offset的组织形式,是virtual address,虚拟地址.真正的物理地址是通过 segment<<4 + offset运算得到的.
线性地址:
分段机制开启之后就是使用的线性地址了
比方说下面截图中,那个mov 0x1001c %eax 中的0x1001c就是使用的偏移地址,数据段CS的偏移量,而<bootmain>旁边的那个00007d0a也是地址,代码段的偏移地址,当前obj文件代码段CS内的偏移地址,“(CS:IP)始终指向下一条指令所处的地址”这句话里的地址就是代码段内的偏移地址,下图中的00007d0a,7d0b,7d0e。。。这些都是代码段的偏移地址,而 0x10000这些地址是当前数据段的偏移地址 ,$0x464c457fz只是个立即数
上述下划线部分是最近update
第二次update: 把握住上面下划线的分析,容易知道这里的偏移地址其可以根据seg:offset解析做线性地址,进而根据分页的机制,解析如果映射到物理地址
上述这个反汇编看到的截图地址和我们平日写hello world反汇编看到的地址无异,都是使用的线性地址。而由于普通的user space用户一般都不会去接触boot.S那段代码。所以根本就没有逻辑地址的“需求”.对于普通用户来说,就两种地址,要么这个地址是"假的" ,要么这个地址是“真的”,这里理解的假,真,都是由于对是否这个地址真正对应物理内存来说的。由于用户空间的线性地址不是真正对应的物理地址,所以人们就把这种地址也叫做虚拟地址
所才会有下图(截取自CSAPP)的现象,明明是线性地址空间,被称作虚拟内存空间.
自然的物理内存地址就不必说了.
之所以这么强调地址概念的区分.一是之前自己晕了好久,半吊子,似懂非懂.
再者,遇到一个问题,触发我去把这个理清楚
看下面的截图,这段代码出自Xv6(MIT-JOS)的 /kern/pmap.h
第一个函数的功能说明是把“takes a kernel virtual address,returns the corresponding physical address”
这里说的把把虚拟地址转换成物理地址就是把线性地址转换成物理地址,
而且实现方法也论证了这一点, 直接的kva - KERNBASE ,这里KERNBASE是0xF0000000
而这里指的“物理地址”也不是别的IO端口的地址,就是内存地址,内存的首地址被映射到KERNBASE
So ...现在就很清楚了
第二个把物理内存地址转换成线性地址就是直接把physical address加上 KERNBASE即可 : -)
总结:
人们会容易混淆的原因在于直接把线性地址称作虚拟地址了,这并没有错(听线性地址的人也不多吧),对于大多数程序员来说,都是接触的线性地址,由于这个地址不是实际的物理地址,所以就习惯性的称作虚拟地址了.使用范围内也就是这个“虚拟地址”(比方说写个C hello world,里面反汇编也就看到的是线性地址)。 大多数人不需要接触到真正的物理地址,这里的概念就变成了对比性的了,不是物理地址的就是虚拟的,使用的是线性地址,由于"不需要那么多概念",于是就把虚拟地址和线性地址挂钩了,而且这里早期的分段未开启的时候虚拟地址的概念已经不存在了,这样时候不会有重叠,于是大家都这么用了....
仅此个人学习总结,如有误解望及时指正.