32位下CPU的寻址方式
要清楚CPU的寻址方式,首先我们不得不先搞清楚逻辑地址,线性地址以及物理地址之间的区别,还要知道32位模式下进程内存的布局情况。在这里我首先给大家扫个盲
逻辑地址:机器语言指令中出现的内存的内存地址,都是逻辑地址,需要转换成线性地址,在经过MMU转换成物理地址才能被访问到。
线性地址:线性地址:线性地址 = 段基址+逻辑地址。 X86保护模式下,段的信息(段基线性地址,长度、权限等)即段描述符占8个字节,段信息无法直接存放在段寄存器中(段寄存器只有2字节)。Intel的设计师段描述符集中存放在GDT(全局描述符表)和LDT(局部描述符表)。而段寄存器存放的是段描述符在GDT或LDT内的索引值。
LINUX中逻辑地址等于线性地址。因为linux所有的段的线性地址都是0x00000000开始,长度4G,这样,线性地址 = 逻辑地址+0x00000000.也就是逻辑地址等于线性地址了。
而且在linux中只用到了GDT。
物理地址:真正在内存中的地址。
32位模式下进程默认布局情况:(画工不好多多见谅)
地址映射过程:
在保护模式下,控制寄存器CR0的最高位PG位控制着分页管理机制是否生效,如果PG=1,分页机制生效,需通过
页表查找才能把线性地址转换物理地址。如果PG=0,则分页机制无效,线性地址就直接做为物理地址。
实模式:寻址空间采用和8086相同的16位段和偏移量,最大寻址空间1MB,最大分段64KB,可以使用32
位指令。
ps:第一次写的真的不好,请多多指教吧 最后附上在linux中在pagemap文件中通过逻辑地址求出物理地址的
代码。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
void vadrtophy(unsigned long vadr,unsigned long *phy)
{
uint64_t pagesize = getpagesize();
unsigned long v_index = vadr/pagesize;
unsigned long v_offset = v_index * (sizeof(uint64_t));
unsigned long page_offset = vadr % pagesize;
uint64_t item = 0;
int fd = open("/proc/self/pagemap",O_RDONLY);
if(fd == -1)
{
printf("open pagemap filed\n");
}
if(lseek(fd,v_offset,SEEK_SET) == -1)
{
printf("lseek filed\n");
}
if(read(fd,&item,sizeof(uint64_t)) != sizeof(uint64_t))
{
printf("read item filed\n");
}
if(((uint64_t)1 << 63) & item == 0)
{
printf("flag error\n");
}
uint64_t phy_index = (((uint64_t)1 << 55) - 1) & item;
*phy = phy_index * pagesize + page_offset;
}
unsigned long a = 0;
int main()
{
unsigned long addr = 0;
//unsigned char *a = (unsigned char *)malloc(sizeof(100));
unsigned int pid = fork();
if(pid == 0)
{
//strcpy(&a,"hello");
//a = 10;
}
vadrtophy(&a,&addr);
printf("pid = %d,vit addr = %x,phy addr = %x\n",getpid(),&a,addr);
sleep(100);
return 0;
}