【问题标题】:What is the value of segment registers in 8086?8086中段寄存器的值是多少?
【发布时间】:2013-09-21 04:05:06
【问题描述】:

我刚开始阅读有关 intel 8086 的信息,并且对它的内存有疑问。

我读到地址总线是20位宽的,也就是说地址空间是1MB,这个空间被分割成段。

问题是:

  1. 四个段寄存器CSDSSSES,它们是只读的还是我可以设置它们的值,它们的默认值是什么?

  2. 我看到了下面的组装教程:

    ORG 100h
    MOV AX, 0B800h ; set AX = B800h (VGA memory).
    MOV DS, AX ; copy value of AX to DS.
    MOV CL, 'A' ; CL = 41h (ASCII code).
    MOV CH, 01011111b ; CL = color attribute.
    MOV BX, 15Eh ; BX = position on screen.
    MOV [BX], CX ; w.[0B800h:015Eh] = CX.
    RET
    

关于第一行,这是否意味着这段代码将存在于代码段空间或整个地址空间中的地址0x100

还有一行:

MOV [BX], CX

这是否意味着每次我在MOV 指令中引用一个地址时,该地址都应该从数据段的起始地址开始估算? (正如他所写,目的地是数据段reg中的值+值)

【问题讨论】:

  • ...目的地是值+数据段reg中的值。这是不正确的。应该是,...目的地是值+数据段reg中的值乘以16。 20 位地址来自 16 位偏移加上 16 位段寄存器左移 4 位。
  • 它们是处理超过 2**16 字节的笨拙方法,几乎​​没有理论意义,编码痛苦,在这一点上,只有微弱的历史意义。一个更有趣的问题是,“80x86-32 位段寄存器呢?”那有一个从未被使用过的有趣的“理论”应用程序。见stackoverflow.com/a/10810340/120163
  • 我从未发现它们会导致“很多编码痛苦”。计算您需要的数据段并根据需要加载寄存器并不难。此外,只有在处理大数据时才需要它。

标签: assembly x86 x86-16


【解决方案1】:

首先,我不得不指出,您似乎在这里谈论的是 8086“实模式”寻址,这是一种非常古老的做事方式,几乎不再使用。几乎所有现代操作系统都在“保护模式”下运行,该模式支持许多增强功能(例如平面 32 位和 64 位内存空间寻址、虚拟内存等),从而大大改变了所有这些工作的方式。

据我所知,现在的大多数操作系统甚至都没有办法运行这样的代码(在实模式下),所以如果你有兴趣学习汇编以进行编程现代 PC,您可能希望找到一些更新的资源来学习。

话虽如此,假设您确实有一些理由想要这样做(例如使用某些嵌入式处理器),或者只是出于历史目的而好奇:

  1. 是的,可以修改 8086 实模式段寄存器。执行此操作的指令和选项比修改更通用的寄存器更受限制(例如,没有指令直接将值加载到段寄存器中,这就是为什么在您引用的代码中,值是首先加载到AX,然后AX 加载到DS),并且还可以根据您使用的段寄存器而有所不同。

    一般来说,您永远不会想直接修改CS(“代码段”)寄存器,因为这会导致立即更改处理器正在运行的代码(可能以您真正不想要的方式) .修改CS 的常用方法是使用“长跳转”或“长调用”指令,这将同时更新CSIP(指令指针)。同样,SS(“堆栈段”)通常在程序执行开始时设置并且从不更改(但从技术上讲,如果您有一些非常令人信服的理由这样做)。

    DSES 是通用数据段寄存器,程序更改这些寄存器是很常见的,但是他们希望最好地访问他们想要使用的内存(如上面的示例代码所示)。

    至于这些寄存器的初始值,通常由操作系统在调用程序代码之前确定。传统上,在 MS-DOS 中,有两种编写程序的方法,即 .COM 文件或 .EXE 文件。 (上面代码中的ORG 100h 行表明它打算作为COM 程序运行。)在COM 的情况下,MS-DOS 最初会将所有段寄存器设置为与CS 相同(即也就是说,在调用程序之前,它们都会指向 DOS 决定将程序加载到内存中的任何位置)。 EXE 文件格式稍微复杂一些,并且允许指定一个单独的“数据段”,在这种情况下,操作系统会在启动程序之前将DSES 设置为指向该段。在 EXE 程序中,DOS 通常也会为它们设置一个单独的堆栈段 (SS)。

  2. The ORG 100h 行告诉汇编器“假设以下代码将被加载到地址 100h”。在实模式代码中,像这样的地址总是相对于CS(因此程序实际上可以加载到内存中的许多地方,只要将CS设置为正确的值以使代码相对于100h到CS)。

  3. 大多数数据操作的地址(例如MOV)将默认相对于DS计算(对于某些指令,您可以通过显式指定不同的段来更改它使用,但是否以及如何做到这一点取决于操作码和您使用它的方式)。但是,有一些指令被设计为默认使用其他段。总之,最好阅读您想了解的每个操作码的文档,以确定它如何使用哪些段寄存器。

【讨论】:

  • 谢谢,我想评论你的答案,但发现太长,我把它分成单独的 cmets
  • 首先,我被要求为intel 8086实现一个模拟器。我没有阅读这些模式,我只是搜索信息,这就是我发现的,谢谢你的澄清。这是我从您的回答中得到的,如果我错了,请纠正我:1-所以,所有段寄存器都可以在程序执行之前由操作系统设置 2-不建议在运行期间更改 CS 的值程序执行,除了你上面提到的情况。
  • 3- SS 值可以在代码中更改,但应作为程序中的第一条指令更改。 4- DS 和 ES 可以在代码中的任何位置更改 5- 某些文件格式(如 .com)让操作系统将所有寄存器设置为代码寄存器,在这种情况下,所有地址都指向相同的段 6- exe 文件格式,可以告诉操作系统为每个寄存器设置不同的值
  • 基本正确。请注意,稍后在程序中更改 SS 并没有什么问题,只是更改堆栈的位置通常不是很有用的(而且由于堆栈包含诸如 CALLs 的返回地址之类的东西,所以你想要非常小心在子例程中执行此操作等)。初始值实际上都只是 MS-DOS 约定。如果您使用的是其他操作系统(或根本没有操作系统),那么它们几乎可以是任何东西。
【解决方案2】:

获取英特尔 8088/86 手册。这都在里面解释了。

是的,您可以更改它们,您必须能够更改它们才能使它们有用。默认情况下使用明显的段(代码对代码,数据对数据),但有些地方可以在数据指令上指定其他段。

org 0x100 表示此代码(或遵循 org 指令的数据)从段内的地址 0x100 开始。

【讨论】:

    猜你喜欢
    • 2012-02-26
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 2017-02-05
    • 2019-03-05
    • 1970-01-01
    • 2014-04-04
    • 2012-02-14
    相关资源
    最近更新 更多