从逻辑地址到线性地址

首先明确三个概念(以80x86为例):
逻辑地址:包含在机器语言指令中用来指定一个操作数或一条指令的地址。我们程序中用到的地址,都是逻辑地址。
线性地址:是一个32位无符号整数,可以用来表示高达4G的地址。
物理地址:用于内存芯片级内存单元寻址,即在物理内存上的地址。
一个进程拥有4G的虚拟空间,其中0-3G属于用户空间,这3G的空间划分为多个段,如下图所示:
在这里插入图片描述
从下往上,5个部分依次是:
代码区:存放可执行的指令,只能读,不能写
数据区:存放初始化的全局变量和静态变量
BSS区:存放未初始化的全局变量和静态变量
heap:存放malloc/new申请的变量
stack:存放临时变量,函数参数等
下面是一段测试代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int a = 0;
    char *b = "hello";
    char *p = (char*)malloc(4);

    printf("[stack]a=0x%08x\n[data] b=0x%08x\n[heap] p=0x%08x\n", 
    &a, b, p);
    
    return 0;
}

变量a栈上,变量b在数据区,变量p在堆上,执行结果:

[stack]a=0xa288094c
[data] b=0x004005d8
[heap] p=0x0071b010

一、段选择符

linux是通过分段机制,将逻辑地址转化为线性地址。上面的变量b就属于数据段。通过数据段寄存器ds,可以找到此进程数据段所在的段描述符,再通过段描述符找到相应的线性地址。
寄存器ds中保存了16位的段选择符,段选择符格式如下:
在这里插入图片描述
TI:指明段描述符是在全局描述符表(GDT, TI=0)中或局部描述符表(LDT, TI=1)中
索引号 index:指定该段在GDT或LDT中的位置。

二、段描述符

每个段都有不同的属性,如首字节的线性地址,段的访问级别(DPL)等,段描述符就保存了段的这些属性。段描述符长度为8字节,格式如下:
在这里插入图片描述
BASE:包含段的首字节的线性地址
DPL:用于限制对这个段的存取。为0时,只有内核态可以访问;为1时,都可以访问

三、逻辑地址到线性地址

在这里插入图片描述

做以下假设:

  1. 寄存器ds的值为0x13
  2. 全局描述符表中的内容为0x00020000

获取变量b的线性地址过程如下:

  1. 段选择符为0x13,则TI为0,该段信息保存在GDT中;index值为2(0x13的高13位)
  2. GDT中的内容为0x00020000,每个段描述符占8字节,则变量b所在数据段描述符地址为0x00020000+(2 * 8),即0x00020010。
    段描述符中BASE字段(16-39位和56-63位),保存的就是变量b所在数据段的线性地址基址,基址+变量b在段内的偏移量可得到变量b的线性地址(0x004005d8)。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值