分段和地址¶
内存地址类型¶
| 地址类型 | 描述 |
|---|---|
| 逻辑地址 | 机器语言指令使用的地址,指定一个操作数的地址或一条指令的地址 |
| 线性地址 | 线性地址是一个无符号整数,范围0x00~0xffffffff(ffffffff), 由逻辑地址的 段基址+段偏移计算得到若无分页机制,线性地址即物理地址 |
| 物理地址 | 内存单元的实际地址,用于芯片级内存单元寻址 |
地址范围由操作系统上虚拟地址长度和物理地址长度决定
| Bash | |
|---|---|
1 2 3 4 | |
8086分段¶
由于8086有20跟地址总线,但是寄存器只有16bit.
无法通过单一寄存器寻址20地址线对应的空间
所以将存储分段,使用段地址+段内偏移的方式寻址.
8080 将内存分为4个段:
- 数据段
- 代码段
- 堆栈段
- 额外数据段

8086地址计算¶
段地址左移4位+段内偏移

CPU工作模式¶
实地址模式¶
即早期8086的工作模式,
早期8086有16位数据总线,20位地址总线,
16位地址可寻址64KB地址空间,
在有20位地址线的情况下,使用段地址+段内偏移的方式可寻址1M地址空间.
详细可参见上一节。
保护模式¶
目前寄存器和地址总线目前已达到32bit/64bit,(主流操作系统已经放弃对32系统的支持)
32bit地址总线即可寻址4GB地址空间,64bit地址总线可寻址更大内存空间
如果使用段地址+段内偏移的方式寻址,每个程序都可以访问整个内存空间
因此,增加保护模式。
保护模式寻址¶
将段的信息(即段描述符,包含:段基址,长度,属性等)放到段描述符表,
段描述符表又分为全局段描述符表(GDT)和局部段描述符表(LDT)
全局描述符表位于内存中,表的地址放到GDTR寄存器中,
使用16位段选择子(即原来的段寄存器CS/DS/ES/GS的低16位,保护模式下改了用处)从描述符表里选段信息,
段描述符¶
8字节
| 字段 | 长度 | 描述 |
|---|---|---|
| segment limit | 20bit | 段长 |
| base address | 32bit | 段基地址 |
| type | 4bit | 段类型,自行查文档 |
| S | 1bit | 0:系统段描述符 1代码段或者数据段描述符 |
| DPL | 2bit | 特权级,0为最高特权级,3为最低,表示访问该段时CPU所需处于的最低特权级 |
| P | 1 | 1:有效 0:无效 |
| A | ||
| DB | ||
| G | 1bit | 范围粒度 0:粒度为1字节,20bit可寻址1MB 1:粒度为4KB,20bit可寻址4GB |


段选择子¶

段寻址¶
Linux64位系统下,段基址都为0


分页¶

寻址语法¶
1.立即数寻址¶
直接使用数字
格式:$number
| GAS | |
|---|---|
1 2 | |
2.寄存器寻址¶
数据直接存寄存器里
格式:%寄存器名字
| GAS | |
|---|---|
1 2 | |
3.直接寻址¶
访问并使用变量
| GAS | |
|---|---|
1 2 3 4 5 | |
4.寄存器间接寻址¶
寄存器里储存的是变量的地址,通过寄存器访问变量
格式:(%寄存器名)
| GAS | |
|---|---|
1 2 3 4 5 6 7 | |
5.寄存器相对寻址¶
寄存器里存储的变量的相对地址,通过寄存器加偏移访问变量
格式:偏移量(%寄存器名)
| GAS | |
|---|---|
1 | |
6.基址变址寻址方式¶
格式:base_addrsss(offset_address, index, size)
数值:base_address + offset_address + index * size
其中0值可省略
offset_address和index是寄存器类型
| GAS | |
|---|---|
1 2 3 4 5 | |
参考¶
Segmentation in Intel x64(IA-32e) architecture - explained using Linux
Linux内存寻址二三事