我决定自学汇编语言。
我意识到如果我尝试更改任何段寄存器的值,我的程序将无法编译。
我发现的每一篇文章都说我确实可以改变至少 4 个段寄存器的值,那么给出了什么?
我真的只对为什么在这一点上感兴趣,我没有任何真正的目的来更改这些地址。
你说你对为什么感兴趣,所以:
在实模式下,段是物理内存的 64K“窗口”,这些窗口相隔 16 个字节。在保护模式下,段是物理或虚拟内存的窗口,其大小和位置由操作系统确定,并且它具有许多其他属性,包括进程必须具有什么特权级别才能访问它。
从这里开始,我所说的一切都是指保护模式。
内存中有一个称为全局描述符表 (GDT) 的表,其中保存了有关这些窗口大小和位置以及其他属性的信息。每个进程也可能有本地描述符表,它们的工作方式类似,所以我只关注 GDT。
加载到段寄存器中的值称为段选择器。它是 GDT 或 LDT 的索引,带有一些额外的安全信息。自然,如果程序试图加载超出 GDT 边界的描述符,就会发生异常。此外,如果进程没有足够的权限来访问该段,或者其他内容无效,则会发生异常。
当异常发生时,内核会处理它。这种异常可能会被归类为分段错误。所以操作系统会杀死你的程序。
最后一个警告:在 x86 指令集中,您不能将立即值加载到段寄存器中。您必须使用中间寄存器或内存操作数或 POP 进入段寄存器。
MOV DS, 160 ;INVALID - 无法组装 MOV AX, 160 ;VALID - 汇编,但可能会导致 MOV DS, AX ;异常,从而导致你的程序死亡
我认为应该指出的是,该架构允许大量的段。但是 AFAIK,当涉及到主流 x86 操作系统时,段寄存器仅用于几个目的:
除了 TLS 的每个线程一个段之外,实际上只有少数段(处理器数量的倍数)被使用,并且仅由操作系统使用。应用程序可以完全忽略段寄存器。
这是由于操作系统设计,而不是任何技术限制。可能有嵌入式操作系统需要用户空间程序来处理段寄存器,尽管我不知道。
你在写windows可执行文件吗?
在保护模式 (Win32) 中,不再使用段寄存器。
参考:
内存模型也与过去的 16 位世界截然不同。在Win32下,我们不再需要关心内存模型或段了!只有一种内存模型:平面内存模型。不再有 64K 段。内存是4 GB的大连续空间。这也意味着您不必使用段寄存器。您可以使用任何段寄存器来寻址内存空间中的任何点。这对程序员来说是一个很大的帮助。这就是使 Win32 汇编编程像 C 一样简单的原因。