A LONG JOURNEY

appreciate and cherish.
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Review of Win32 Assembly (Memory Management part one)

Posted on 2009-08-21 23:04  alleoo  阅读(427)  评论(0)    收藏  举报

保护模式下内存管理

by Yariv Kaplan


When the processor is running in protected-mode, two mechanisms are involved in the memory translation 
process: 
Segmentation and Paging. Although working in tandem, these two mechanisms are completely
independent of each other. In fact, the paging unit can be disabled by clearing a single bit in an internal 
processor register. In this case, the linear addresses which are generated by the segmentation unit pass 
transparently through the paging unit and straight to the processor address bus.

当处理器运行在保护模式下时,内存寻址过程中会用到分段及分页两种机制,尽管工作流程中它们是串联的,但这两种机制并
无太多关联。事实上,分页功能单元是可以通过设置(清除)一个寄存器的bit位来实现启用和关闭的。如此,经过分段单元产
生的线性地址空间内地址就显示的传递给分页处理单元,从而最终形成物理地址放到处理器地址总线上。


Figure 1 - Protected-mode address translation process

Segmentation 

分段机制

The role of the segmentation unit is the same as on the 8086 processor. It allows the operating system to divide programs into 
logical blocks and place each block in a different memory region. This makes it possible to regulate access to critical sections of 
the application and help identify bugs during the development process. The implementation of the segmentation unit on the 80386 
(and above) is simply an extension of the old 8086 unit. It includes several new features such as the ability to define the exact 
location and size of each segment in memory and set a specific privilege level to a segment which protects its content from 
unauthorized access.

分段机制的作用和在8086处理器下是一样的。这允许操作系统能够将代码分成逻辑上的块而存储到不同的内存区域,
这使得对应用程序的某些关键块进行访问控制成为可能,而且能够使开发过程中引入的
bug暴露出来。80386及之后
更先进的处理器使用的分段机制只是较老的
8086处理器的扩展。它包括了一些新特性,如能够在内存中精确定义每
块的地址和大小, 能够对每个段设置特权级别,从而保护所存储的数据阻止未授权的访问。

Not only real-mode applications use segment registers for accessing memory. The same process takes place under
 protected-mode. However, there are several differences which should be considered. 
First, there is a slight change in terminology. Under protected-mode, segment registers receive the name 
Selectors 
which reflects their new role in the memory translation process. Although still 16-bit in size,
their interpretation by the processor is inherently different. 
Figure 2 presents the structure of a selector along with the various bit-fields which comprise it.

并不是只在实模式下应用程序才使用段寄存器访问内存的。在保护模式下也会用到。然而,必须注意到它们之间有
几个不同之处。第一就是术语方面的不同
。保护模式下,段寄存器内存放的是选择子,选择子这个名字能反映出它
在寻址过程中的作用,尽管段寄存器也是16位的,但处理器解释其存储的内容的意义是不同的。图2表明的就是选择
子及其组成域的结构。


Figure 2 - Internal composition of a selector

Instead of shifting segment registers (selectors) four bits to the left and adding an offset (like in real-mode), the processor treats each selector as an index to a Descriptor Table.

并不象在实模式下段寄存器值左移四位加上偏移形成物理地址,此时它作为段描述符表的索引。

Descriptor Tables 

段描述符表

Descriptor tables reside in system memory and are used by the processor to perform address translation. Each entry in a 
descriptor table is 8 bytes long and represents a single segment in memory. A descriptor entry contains both a pointer to 
the first byte in the associated segment and a 20-bit value which represents the size 
of the segment in memory. Several other fields contain special attributes such as a privilege level and the 
segment's type. Figure 3 presents the exact structure of a descriptor entry along with a description of each of its internal fields.

段描述符表位于系统内存区,它被用来进行地址转换。在段描述符表中每一个描述符项长度为8个字节代表内存中一个
段的信息。一个描述符项包含了向其相应段的入口地址(32bit),以及表示该段在内存中宽度的
20bit的数据。
其它一些区域包含一些特殊参数如特权级别和段类型。图3所示的是段描述符的完整结构。


Figure 3 - Structure of a descriptor entry

Table 1 contains a complete list of all descriptor fields and their functionality.

Field

Designated Role

BASE

Segment Base Address (32-bits)
This field points to the segment's starting location in the 4GB linear address space.

D/B

Segment Size Bit
When the descriptor entry describes a code segment, this bit is used to specify the default length 
of operands and addresses.

When the bit is set, the processor assumes a 32-bit segment.
When the bit is clear, a 16-bit segment is assumed.

When the descriptor entry describes a data segment, this bit is used to control the operation of
the stack.

When this bit is set, stack operations use the ESP register.
When this bit is clear, stack operations use the SP register.

DPL

Descriptor Privilege Level (2-bits)
This field defines the segment privilege level. It is used by the protection mechanism built into the 
processor to restrict access to the segment.

段描述符特权级

它定义了段的特权级别。保护模式下用来限制对段的访问。

G

Granularity Bit
This bit controls the resolution of the segment limit field.
When this bit is clear, the resolution is set to one byte.
When this bit is set, the resolution is set to 4KB.

LIMIT

Segment Limit (20-bits)
This field determines the size of the segment in units of one byte (When the granularity bit is clear) 
or in units of 4KB (When the granularity bit is set).

P

Segment Present Bit
This bit specifies whether the segment is present in memory.

When this bit is clear, a segment-not-present exception is generated 
whenever a selector for the descriptor is loaded into one of the segment registers.

This is used to notify the operating system of any attempt to access a segment which
 has been swapped to disk (virtual memory support) or which was not previously allocated 
(a protection violation).

段存在位

该位表示该描述符描述的段是否存在于内存中。

此位被清零,此时如果指向该描述符的选择子被加载到段寄存器时就会引发段不存在异常。

它被用来通知操作系统任何企图访问由虚拟内存提供的内存段或者是未被申请却企图访问的内存段。

S

Descriptor Type Bit
This bit determines whether this is a normal segment or a system segment.
When this bit is set, this is either a code or a data segment.
When this bit is clear, this is a system segment.

Type

Segment Type (4-bits)
When the descriptor entry describes a code segment, this field determines the type of the segment:
 execute-only or execute-read, conforming or non-conforming.

When the descriptor entry describes a data segment, this field determines the type of the segment: 
read-only or read-write, expand-down or expand-up.

Accessesing an expand-up segment with an offset which exceeds the segment limit value, causes an exception.
The limit field in expand-down data segments is treated differently by the processor. Offsets which cause an exception to occur
 in expand-up segments are valid in expand-down segments. An access into an expand-down segment must be done with an offset larger than the segment limit or else an exception is 
generated.

Decreasing the segment limit value in an expand-down segment causes memory to be allocated at the bottom of the segment. This is very useful for 
stacks since they tend to grow toward lower memory addresses.

Since each selector points to a specific descriptor entry, there is a one to one relationship between selectors 
and segments in memory. This concept is demonstrated in the following figure.

因为每一个选择子都指向一个特定的段描述符。所以选择子和线性空间中的段是一对一的关系,下图做了清淅的说明。


Figure 4 - Relationship between selectors and segments

As figure 5 shows, linear address calculation (which can be the physical address if paging is disabled) is done by using 
the selector as an index to the descriptor table, getting the base address of the segment, and adding the offset.

如图5所示,线性地址的计算(如不启用分页机制就是物理地址)是由选择子做为索引找到描述符表,
然后在描述符表中拿到段的基地址,加上
32位的偏移就形成最终的物理地址。


Figure 5 - Virtual to linear address translation

Two types of descriptor tables are used by the processor when working in protected-mode. 
The first is known as the 
GDT (Global Descriptor Table) and is used mainly for holding descriptor entries 
of operating system segments. The second type is known as the 
LDT (Local Descriptor Table) and contains entries 
of normal application segments (although not necessarily). During initialization, the kernel creates a single GDT which
 is kept in memory until either the operating system terminates or until the processor is switched back to real-mode.

实际在保护模式下处理器要用到两种类型的段描述符表。第一种被称之为全局段描述符表(GDT,它主要是用来
保存操作系统的段相应的描述符
;第二种叫做局部段描述符表,它保存的是应用程序的段对应的描述符
(有时不是必须的)。操作系统初始化时,内核会在内存中创建一个
GDT,它将一直存在于内存中(被使用)
直到退出操作系统或是处理器被切换到实模式。

Whenever the user starts an application, the operating system creates a new LDT to hold the descriptor entries which represent 
the segments used by the new task. This makes it possible for the operating system to isolate each task's address space by
 enabling a different LDT whenever a task switch occurs. Bugs and other errors in the application cannot affect other running
 processes and are limited in scope to the currently mapped memory segments.

Note that not all operating systems behave exactly as described above (for instance, all Windows applications share
 a single LDT). However, this is the recommended programming practice as offered by Intel.

When looking for a specific descriptor entry, the addressing unit in the processor uses the TI bit 
(which is part of the selector) to decide which descriptor table should be used (the GDT or the currently active LDT).
 Figure 6 shows this process in clarity.

每当用户开启一个应用程序,操作系统将为它创建一个新的LDT用于保存该任务的段所对应的描述符。
由此,当发生任务切换时,操作系统就可能通过切换到不同的
LDT来实现隔离各个任务的地址空间。
当一个应用程序因其错误或缺陷致使其崩溃时就不会影响到其它正在运行的程序进程,
再者这些缺陷也被限止到一该任务的段空间中。

注意并不是所有操作系统都是按照如上的方式运行的(例如,所有的windows应用程序共享一个LDT),
但这是
Intel 推荐的方式。

当查找某个特定的段描述符时,处理器的寻址单元使用TI标识位(选择子的一个组成部分)
来确定使用那个描述符表(
GDT 或者当前激活任务LDT)。由图6示。


Figure 6 - The Table Indicator bit