Assembly 使用ES寄存器会产生错误

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 ;=

我正在将一个程序从EMU8086环境转换为NASM。组装NASM时会出现以下错误:

system\kernel.asm:14:错误:操作码和操作数的组合无效

system\kernel.asm:20:错误:操作码和操作数的组合无效

system\kernel.asm:28:错误:操作码和操作数的组合无效

我的代码是:

    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]
+missing
hplot:
标签没有丢失,只是缩进与代码不同,使其可读性大大降低。问题是
循环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