【问题标题】:Using ES register gives errors使用 ES 寄存器会出错
【发布时间】:2016-03-11 08:54:20
【问题描述】:

我正在将一个程序从 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 中不起作用?

【问题讨论】:

  • mov es, [startaddr] mov al, [colour] + 缺少hplot:
  • hplot: 标签并没有丢失,它只是缩进与代码不同,这使得它的可读性降低了很多。问题是loop hplot:。冒号只出现在标签 def 上,而不是引用。
  • @PeterCordes :这是正确的。我要做的一个观察是,所呈现的程序的第一个版本实际上具有hplot: 标签作为上一行注释的一部分(所以从技术上讲它是缺失的)。 OP确实转过身来解决了这个问题。我猜 Dirk 可能看到了原始代码。

标签: assembly x86 nasm x86-16 cpu-registers


【解决方案1】:

其他答案的替代方案

由于 0xA000 是一个常量,因此可以这样定义它,然后将其用作立即值而不是内存操作数。为了使这种方法起作用,您需要将常量放在中间寄存器中,然后将其移动到段寄存器中。


您可以将 startaddr 定义为常量(不是包含段值的内存地址)。您可以使用 EQU 创建常量(立即值)。更改此行:

startaddr   dw  0a000h  ;start of video memory   

startaddr   EQU  0a000h  ;start of video memory   

由于您不能 MOV 直接将值直接传递给 DSESSS,因此将值放入中间寄存器,然后将其移动到段寄存器。所以这段代码:

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

vplot:
mov es:[di],al

需要用方括号内的段来写。它们应该如下所示:

mov [es:di],al      ;set pixel to colour

vplot:
mov [es:di],al

我强烈推荐你阅读NASM documentation关于生成DOS COMEXE程序

【讨论】:

  • @rkhb :当我决定提供答案时,我实际上考虑到了这一点。这样做是非常合法的(因为您可以将内存操作数移动到 ES)。我决定展示为视频内存地址定义常量的典型方法。两种方式都有效,但是对于这段代码所做的典型习惯用法恕我直言,这是我呈现它的方式。所以两者都做同样的事情。我只是避免使用保持常量的内存变量。
  • @rkhb 写了一条建议 mov es, [startaddr] 的评论(现已消失)。将方括号放在操作数周围使其成为内存引用,并且可以与 OPs 代码一起使用。我的评论是对此的回应。有人已经使用该方法提供了答案,我选择了一种稍微不同的方法,这种方法通常更典型(尤其是在使用的视频内存地址不变的情况下)
  • 看到太晚了,@user3144770回复了,删了评论。对不起。
  • 没问题@rkhb,但我认为你对我的回答有一个有效的评论。我没有回答的是我提供了另一个答案的替代方案。我打算修改我的答案以明确这一点,所以我感谢你实际上提出这个问题。
【解决方案2】:

在 NASM 中,您必须使用方括号来检索 startaddr 处的值。

写:

mov es, [startaddr]       ;put segment address in es    

NASM 还希望您在这些括号之间写入段覆盖:

mov [es:di],al      ;set pixel to colour

NASM 无法为您检测到的另一个错误是您认为已检索到 colour 变量的方式。您还应该在此处使用 []

mov al, [colour]

【讨论】:

    【解决方案3】:

    没有处理器指令可以直接加载esds。您必须加载一个数据寄存器,然后将其移动到段寄存器

    mov ax,0A000h
    mov es,ax
    

    【讨论】:

      猜你喜欢
      • 2017-12-12
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 1970-01-01
      • 2012-03-23
      相关资源
      最近更新 更多