【问题标题】:DOS Console data memory access when 32bit registers are accessible assemblery32 位寄存器可访问时的 DOS 控制台数据内存访问汇编
【发布时间】:2018-07-23 02:04:51
【问题描述】:

我正在处理 TASM 汇编中的一个项目,当我在汇编器中使用 32 位寄存器(使用.386)时,我无法将颜色输出到 DOS 控制台的特定单元格。

这是我通常会如何做的一个例子:

单元格的 BX 位置,
AH颜色/单元格字符

mov ah , 01000000b ; Color Red to ah
mov ax,0b800h ; memory location of the console 
mov es,ax ; to es 
mov es:[bx] , ah ; mov data from ah to the cell of bx 

这可行,但是当我在开始时将.386 设置为 32 位时,此代码将停止工作......有人知道解决问题的方法吗? 短的 : 代码需要将 Color 设置为 cell 。在没有 .386 的情况下工作并停止使用 .386

代码段:

.386
.Model small
.data 
 ;all my data 
 .code 
  Start:
  ; all the code in there also the output code snippet I showed 
 end start 

由 Ped7g 修复: 将.386 行放在.code 段内

由玛格丽特布鲁姆修复: 将USE16 修饰符添加到MODEL 指令

两者都在工作。感谢您的帮助

任务 32 位

【问题讨论】:

  • 不要认为.386 制作任何 32 位的东西并且应该同样工作。它只是指定您有 386+ 条指令可用。
  • @TomZe - 问题中的示例代码是 16 位代码。请添加示例 32 位代码。您确定该工具集正在构建 16 位 DOS 控制台程序(.COM 或 .EXE)吗?
  • 问题是,您使用.386 太早(将使您的.code 指令定义32b 保护模式代码段-> 16b 实模式的错误指令操作码)。如果您首先指定.model,然后指定.code 段,那么在.code 段内使用.386 将被不同地处理(代码段将已设置为16b 实模式代码,而.386 将只是允许 32b 英寸)。 .dotDirectives 是简化的快捷方式,用于以常用方式设置常用事物,因此如果您以错误的顺序使用它们,或者与完整的 segment 指令/等混合使用,它们可能会损坏。
  • 并且...从您的问题中不清楚,您完全了解 16b 实模式和 32b 保护模式之间的区别。您确定要使用 32b 模式指令吗?然后你的.386 是正确的,代码停止工作,因为你没有切换到保护模式,并按原样执行(在保护模式下,你可以将视频内存映射到平面内存寻址映射,所以不需要然后使用段,只需mov ebx,0B8000h - 但这意味着您已经编写了自己的小型操作系统或者您使用了 DOS 扩展器)。 IMO 您更有可能希望保持 16b 实模式,并使用 32b inst./regs.
  • @Ped7g - 对于 Masm 6.11 - Microsoft 16 位工具集的一部分,.386 的位置无关紧要,因为 Masm 6.11 只会生成 16 位实模式代码根据需要使用 386 个前缀以在 16 位实模式下使用 32 位寄存器。我不知道同一版本的 Tasm 可以根据 .386 指令所在的位置生成 16 位或 32 位代码。

标签: windows assembly memory dos tasm


【解决方案1】:

如果您没有明确指定代码段的属性,则使用 .386 指令会将默认操作数设置为 32 位。

引用TASM manual

请注意,您可以在两个地方指定模型修饰符,以兼容 MASM 5.2。如果您不使用模型说明符,Turbo Assembler 假定 NEARSTACK 修饰符和 USE32(如果选择了 80386 或 80486 处理器)。

这并不意味着您可以使用 32 位寄存器1,而是汇编器将以“镜面”方式发出指令。

x86 机器中的所有代码都有一个默认操作数大小。
在 32 位运行时为 32 位,在 16 位运行时为 16 位(64 位涉及更多一点,它仍然是 32 位,但可以用 REX.W 前缀覆盖)。

默认操作数大小决定了直接操作数的默认大小,即期望值的指令的操作码后面的字节数。

mov ax, 0b800hmov eax, 0b800h 等指令的编码方式相同:使用操作码 B8
在此操作码之后,它跟在 16 位或 32 位的立即操作数之后。
具体大小取决于默认操作数大小。

要访问“其他”大小,即在 32 位代码中指定 16 位版本的指令,反之亦然,存在操作数大小覆盖前缀(值 66)。

放在桌子上

                    +-----------------------------------------+
                    |           Default operand size          | 
+-------------------+---------------------+-------------------+ 
|Instruction        |      16             |        32         |
+-------------------+---------------------+-------------------+
|                   |                     |                   |
|mov ax, 1234h      |     B8 34 12        |    66 B8 34 12    |  
|                   |                     |                   |
|mov eax, 12345678h |  66 B8 78 56 34 12  |   B8 78 56 34 12  |   
|                   |                     |                   |
+-------------------+---------------------+-------------------+

当汇编器假定默认操作数大小为 32 位时,看看 mov ax, 0b800h 是如何用 66 B8 编码的?
并且当以 16 位代码执行时,66 B8 被解码具有 32 位立即数?

这搞砸了后续指令的解码。

汇编为 32 位代码执行为 16 位代码时发布的片段导致:

00000000  B440              mov ah,0x40
00000002  66B800B88EC0      mov eax,0xc08eb800
00000008  26678827          mov [es:edi],ah

如何解决这个问题

为每个代码段明确指定代码大小属性或使用MODEL 指令设置默认值。
例如,如果您使用SMALL 内存模型:

.MODEL USE16 SMALL 

1 就 CPU 而言,您总是如此,只是 TASM 拒绝汇编与所选处理器系列不兼容的指令。

【讨论】:

  • 我的代码中当然有一个 MODEl 指令,这只是匹配较长代码的问题部分的代码 sn-p,这个输出的东西在我的“.code”段中。我只是不想通过发布我所有的代码来浪费人们的时间......
  • @TomZe 您的MODEL 指令中似乎缺少USE16 修饰符。
【解决方案2】:

在您可以使用任何可能的 x86 保护模式(其 16 位或 32 位变体)之前,您必须运行某些机器指令组,将 CPU 从实模式转移到保护模式。这不是一件小事,因为您至少需要设置最少数量的系统表和系统寄存器,例如 CR0。英特尔软件开发人员手册Volume 3 中有很好的描述,并带有汇编程序中的示例。

请注意,从字面上看,此后处理器行为的所有内容都会发生变化:您作为汇编程序输入编写的指令将不再意味着它们的含义(因为默认操作数和地址大小可能已更改),但最重要的是内存地址没有不再简单地指向物理内存,而是通过分段和分页进行转换。甚至您的控制台地址也必须重新计算,以确保您指向正确的物理地址。请注意,好的旧 DOS 中断将不再起作用,因为它们被编写为在实模式下工作并且不期望保护模式;它只会挂起或重启。

也许您应该澄清您要达到的目标以及现有实模式代码为何不能满足您的需求。如果您的目标是学习,那么我建议您熟悉什么是保护模式,如何将 CPU 转移到它,以及如何为其编写程序。我估计第一个点将花费 80% 或您的时间,第二个 15% 并且程序本身将只花费您 5% 或更少的时间。

【讨论】:

  • 当前的实模式代码不能满足我的需要,因为当我在程序开始时执行 .386 代码停止工作时它不起作用。另请注意,这当然不是我的全部程序。这只是 650 行程序的输出部分。这是不起作用的部分。
  • 好的,我已在编辑中添加了我的片段以使其更清晰
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多