为什么我无法更改段寄存器的值? (MASM)
我决定自学汇编语言。
我意识到,如果我尝试更改任何段寄存器的值,我的程序将无法编译。
我发现的每一篇文章都说我确实可以更改至少 4 个段寄存器的值,那么给出了什么?
我真的只对为什么在这一点上感兴趣,我没有任何改变这些地址的真正目的。
I decided to teach myself assembly language.
I have realized that my program will not compile if I attempt to change the value of any segment register.
Every article that I have found says that I can indeed change the value of at least 4 segment registers, so what gives?
I am really only interested in the why at this point, I don't have any real purpose in changing these addresses.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您说您对原因感兴趣,所以:
在实模式下,段是物理内存的 64K“窗口”,并且这些窗口间隔 16 个字节。 在保护模式下,段是物理或虚拟内存的窗口,其大小和位置由操作系统决定,并且它具有许多其他属性,包括进程必须具有什么权限级别才能访问它。
从这里开始,我所说的一切都是指保护模式。
内存中有一个表称为全局描述符表(GDT),其中保存有关这些窗口大小和位置以及其他属性的信息。 每个进程也可能有本地描述符表,它们的工作方式类似,所以我只关注 GDT。
加载到段寄存器中的值称为段选择器。 它是 GDT 或 LDT 的索引,带有一些额外的安全信息。 当然,如果程序尝试加载超出 GDT 范围的描述符,就会发生异常。 此外,如果进程没有足够的权限来访问该段,或者其他内容无效,则会发生异常。
当异常发生时,内核会进行处理。 这种异常可能会被归类为分段错误。 所以操作系统杀死了你的程序。
最后需要注意的是:在 x86 指令集中,您无法将立即值加载到段寄存器中。 您必须使用中间寄存器或内存操作数或 POP 到段寄存器中。
我认为应该指出的是,该架构允许存在大量段。 但据我所知,当涉及到主流的 x86 操作系统时,段寄存器仅用于几个目的:
除了用于 TLS 的每个线程一个段之外,实际上仅使用少数段(乘以处理器数量),并且仅由操作系统使用。 应用程序可以完全忽略段寄存器。
这是由于操作系统设计,而不是任何技术限制。 可能有一些嵌入式操作系统需要用户空间程序来使用段寄存器,但我不知道。
You said you were interested in why, so:
In real mode, a segment is a 64K "window" to physical memory and these windows are spaced 16 bytes apart. In protected mode, a segment is a window to either physical or virtual memory, whose size and location is determined by the OS, and it has many other properties, including what privilege level a process must have to access it.
From here on, everything I say refers to protected mode.
There is a table in memory called the global descriptor table (GDT), which is where the information about these window sizes and locations and other properties are kept. There may also be local descriptor tables on a per-process basis, and they work in a similar way, so I'll just focus on the GDT.
The value you load into a segment register is known as a segment selector. It is an index into the GDT or LDT, with a bit of extra security information. Naturally if a program tries to load a descriptor which is outside the bounds of the GDT, an exception occurs. Also if the process does not have enough privilege to access the segment, or something else is invalid, an exception occurs.
When an exception occurs, the kernel handles it. This sort of exception would probably be classed as a segmentation fault. So the OS kills your program.
There's one final caveat: in the x86 instruction set, you can't load immediate values into segment registers. You must use an intermediate register or a memory operand or POP into the segment register.
I think it should be pointed out that the architecture allows for heaps of segments. But AFAIK, when it comes to the mainstream x86 operating systems, segment registers serve only a few purposes:
Apart from a segment per thread for TLS, really only a handful of segments (times the number of processors) are used, and only by the OS. Application programs can completely ignore the segment registers.
This is due to OS design, not to any technical limitations. There may be embedded operating systems that require user-space programs to work with the segment registers, though I don't know of any.
您正在编写 Windows 可执行文件吗?
在保护模式(Win32)下,不再使用段寄存器。
参考:
Are you writing windows executables?
In protected-mode (Win32), segment registers are not used any more.
Reference: