Assembly 使用ES寄存器会产生错误
我正在将一个程序从EMU8086环境转换为NASM。组装NASM时会出现以下错误: system\kernel.asm:14:错误:操作码和操作数的组合无效 system\kernel.asm:20:错误:操作码和操作数的组合无效 system\kernel.asm:28:错误:操作码和操作数的组合无效 我的代码是:Assembly 使用ES寄存器会产生错误,assembly,x86,nasm,x86-16,cpu-registers,Assembly,X86,Nasm,X86 16,Cpu Registers,我正在将一个程序从EMU8086环境转换为NASM。组装NASM时会出现以下错误: system\kernel.asm:14:错误:操作码和操作数的组合无效 system\kernel.asm:20:错误:操作码和操作数的组合无效 system\kernel.asm:28:错误:操作码和操作数的组合无效 我的代码是: jmp start ;============================== ;Draws a horiz and vert line ;=
jmp start
;==============================
;Draws a horiz and vert line
;==============================
startaddr dw 0a000h ;start of video memory
colour db 1
;==============================
start:
mov ah,00
mov al,19
int 10h ;switch to 320x200 mode
;=============================
horiz:
mov es, startaddr ;put segment address in es *** 1st ERROR HERE!
mov di, 32000 ;row 101 (320 * 100)
add di, 75 ;column 76
mov al,colour
mov cx, 160 ;loop counter
hplot:
mov es:[di],al ;set pixel to colour *** 2nd ERROR HERE!
inc di ;move to next pixel
loop hplot
vert:
mov di, 16000 ;row 51 (320 * 50)
add di, 160 ;column 161
mov cx, 100 ;loop counter
vplot:
mov es:[di],al ; *** 3rd ERROR HERE!
add di, 320 ;mov down a pixel
loop vplot
我已经用错误标记了这些行。为什么这在NASM中不起作用 没有处理器指令直接加载
es
或ds
。您必须加载一个数据寄存器,然后将其移动到段寄存器
mov ax,0A000h
mov es,ax
在NASM中,必须使用方括号来检索startADR处的值 写:
mov es, [startaddr] ;put segment address in es
NASM还希望您在这些括号之间写入段替代:
mov [es:di],al ;set pixel to colour
NASM不可能为您检测到的另一个错误是您认为如何检索颜色变量。您还应在此处使用[]:
mov al, [colour]
其他答案的替代方案
由于0xA000是一个常量,因此可以将其定义为常量,然后将其用作立即数,而不是内存操作数。为了使这种方法起作用,您需要将常数放入中间寄存器,然后将其移动到段寄存器
您可以将StartADR定义为常量(而不是包含段值的内存地址)。您可以使用eq创建常量(立即值)。更改此行:
startaddr dw 0a000h ;start of video memory
到
由于不能直接向DS、ES和SS输入立即数,因此可以将该值放入中间寄存器,然后将其移动到段寄存器。所以这个代码:
mov es, startaddr ;put segment address in es
可以是:
mov ax, startaddr
mov es, ax ;put segment address in es
注意:如果创建可读代码,并且使用上述方法,我建议将startaddr重命名为startaddr。全大写标识符的约定向读者建议它是一个常量(立即值),而不是一个变量
其他错误与EMU8086和NASM之间的语法差异有关。这些线路:
mov es:[di],al ;set pixel to colour
及
需要使用方括号内的段写入。它们应该是这样的:
mov [es:di],al ;set pixel to colour
及
我强烈建议您阅读关于生成DOS COM和EXE程序的文章
mov es,[startaddr]
mov al,[color]
+missinghplot:
标签没有丢失,只是缩进与代码不同,使其可读性大大降低。问题是循环hplot:
。冒号只出现在def标签上,而不是reference上。@PeterCordes:这是正确的。我要观察的一点是,所展示的程序的第一个版本实际上有hplot:
标签,作为上面一行注释的一部分(因此从技术上讲它是缺失的)。OP确实扭转了局面,解决了这个问题。我猜德克可能看到了原始代码。@rkhb:当我决定提供答案时,我确实考虑到了这一点。这样做是非常合法的(因为您可以将内存操作数移动到ES)。我决定展示为视频内存地址定义常量的典型方法。这两种方法都是有效的,但这段代码的典型用法IMHO就是我介绍它的方式。所以两者都做同样的事情。我只是避免一个内存变量包含常量。@rkhb写了一条注释(现在不见了),建议mov-es,[startaddr]
。在操作数周围放上方括号将使其成为内存引用,并可用于OPs代码。我的评论是对此的回应。有人已经用这种方法给出了答案,我选择了一种稍微不同的方法,这通常更为典型(特别是如果正在使用的视频内存地址没有改变的话),我看到@user3144770给出了答案,并删除了评论,但为时已晚。对不起,没问题@rkhb,但我认为你对我的回答的评论是正确的。我没有在回答中说明的是,我提供了另一个答案的替代方案。我打算修改我的答案,使之更清楚,所以我感谢你实际上提出了它的一般性。
vplot:
mov es:[di],al
mov [es:di],al ;set pixel to colour
vplot:
mov [es:di],al