我正在研究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设置为单元格。在没有.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
指令
两者都有效。谢谢你的帮助
TASM 32位
答案 0 :(得分:5)
如果未明确指定代码段的属性,则使用.386
指令会将默认操作数侧设置为32位。
引用TASM manual:
请注意,您可以在两个位置指定模型修改器,以便与之兼容 MASM 5.2。如果你不使用模型说明符,Turbo Assembler as.sumes the NEARSTACK修饰符和USE32(如果选择了80386或80486处理器)。
这并不意味着您可以使用32位寄存器 1 ,但汇编程序将以“镜面”方式发出指令。
x86计算机中的所有代码都具有默认操作数大小 当以32位运行时,它是32位,当以16位运行时,它是16位(64位更多涉及,它仍然是32位,但可以用REX.W前缀覆盖)。
默认操作数大小确定立即操作数的默认大小,即指示期望值的指令的操作码之后的字节数。
mov ax, 0b800h
和mov 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拒绝组装不符合所选处理器系列的指令。
答案 1 :(得分:2)
在使用x86保护模式(16位或32位变体)的任何可能性之前,必须运行某些机器指令组,将CPU从实模式转移到保护模式。这是一件非常简单的事情,因为您需要设置至少最少数量的系统表和系统寄存器,例如CR0。英特尔软件开发人员手册Volume 3中详细介绍了汇编程序中的示例。
请注意,之后处理器行为的所有内容都会发生变化:您作为汇编程序输入写入的指令将不再意味着它们的含义(因为默认操作数和地址大小可能已更改),但最重要的是内存地址没有更长的只是指向物理内存,而是通过分段和分页进行转换。甚至必须重新计算您的控制台地址,以确保您指向正确的物理地址。请注意,良好的旧DOS中断将不再起作用,因为它们被写入以实模式工作并且不期望保护模式;它只会挂起或重启。
也许你应该澄清你想要实现的目标,以及为什么现有的实模式代码不能满足你的需求。如果你的目标是学习,那么我建议你熟悉一下保护模式是什么,如何将CPU转移到它,以及如何为它编写程序。我估计第一点需要花费80%或者你的时间,第二点是15%,程序本身只花费5%或更少的时间。