32位下CPU的寻址方式

       要清楚CPU的寻址方式,首先我们不得不先搞清楚逻辑地址,线性地址以及物理地址之间的区别,还要知道32位模式下进程内存的布局情况。在这里我首先给大家扫个盲

    逻辑地址:机器语言指令中出现的内存的内存地址,都是逻辑地址,需要转换成线性地址,在经过MMU转换成物理地址才能被访问到。

线性地址:线性地址:线性地址 = 段基址+逻辑地址。   X86保护模式下,段的信息(段基线性地址,长度、权限等)即段描述符占8个字节,段信息无法直接存放在段寄存器中(段寄存器只有2字节)。Intel的设计师段描述符集中存放在GDT(全局描述符表)和LDT(局部描述符表)。而段寄存器存放的是段描述符在GDT或LDT内的索引值。
LINUX中逻辑地址等于线性地址。因为linux所有的段的线性地址都是0x00000000开始,长度4G,这样,线性地址 = 逻辑地址+0x00000000.也就是逻辑地址等于线性地址了。 而且在linux中只用到了GDT。

物理地址:真正在内存中的地址

32位模式下进程默认布局情况:(画工不好多多见谅)

32位下CPU的寻址方式

地址映射过程:

32位下CPU的寻址方式

在保护模式下,控制寄存器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;
}