8086汇编 - 定义与前向引用冲突

时间:2012-06-08 01:49:53

标签: assembly x86-16 forward-reference

我将问题缩小到4行代码。

MOV BX, testz
ADD AL, [testz]

INT 20h
testz:
~     ^
#ERROR 16: Definition Conflicts With Forward Reference                    @@@@#
db ?

您认为这段代码有什么问题?我正在将地址本身移动到BX寄存器并将testz地址中的字节值添加到AL。

在更大的程序中,我也得到#ERROR 13:不允许字节/字组合。

但标签是[label]是一个字节的单词。为什么我的编译器不能区分它们?

ADD BL, [second]
MOV BX, second
~             ^
#ERROR 13: Byte/Word Combination Not Allowed   
second:
~      ^
#ERROR 16: Definition Conflicts With Forward Reference                    @@@@#
db ?

因为我看不到任何字节/字冲突。

感谢。

更新:我想有点长的评论,所以我编辑了我的问题

我的编译器同样解释偏移testz和testz。 我查看了字节码,看不出任何区别。

MOV BX,testz 添加AL,[BX]

上面的代码可行,但是我可以在一行中使用其他任何方式,例如

ADD AL,[testz]

每当我在[]中添加标签名称时,根据我的编译器a86,这是不可接受的。但我觉得他们被允许使用这种语言。

3 个答案:

答案 0 :(得分:4)

我怀疑你想要MOV BX, offset testz。看来你的汇编程序将[testz]testz解释为同一个东西。

您可以尝试通过相反的概念等效LEA BX, testz

来确认这一点

编辑:(来自http://www.csn.ul.ie/~darkstar/assembler/manual/a14.txt):

ERROR 16: Definition Conflicts With Forward Reference

   This error occurs when the assembler has previously guessed
   the type of a forward-referenced symbol in order to determine
   what kind of instruction to generate, and the guess turned out
   to be wrong.  The error is reported at the time the symbol is
   defined.  For example, when A86 sees MOV AX,FOO, it will
   assume FOO is an immediate value.  This error is reported if
   FOO turns out to be a word variable: FOO DW 0.  You need to
   search backwards from the error message, to references of FOO,
   and specify the type you intend to be used: MOV AX,FOO W.  If
   you really did intend to load the offset of FOO and not the
   memory contents, you can code MOV AX,OFFSET FOO to make the
   error message go away.

答案 1 :(得分:4)

您遇到的问题源于A86是单遍汇编程序的事实。在定义符号之前使用testzsecond之类的符号时,A86必须猜测它们是什么。它假定它们将是立即值,但后来发现它们实际上是标签。多阶段汇编器可能会返回并更改先前做出的决定,但是A86不会这样做。它只是提出一个错误(#16)。这就是错误在定义附近的源文件中显示的原因:这是A86发现问题的所在。

您可以使用伪指令offsetdw等来明确地告诉A86您要执行的操作,因此不必进行猜测。

A86 manual解释:”重要提示:您必须了解标签和变量之间的区别,因为如果您混淆它们,可能会产生与预期不同的指令。例如,如果声明XXX:DW?,则XXX后面的冒号表示XXX是标签;指令MOV SI,XXX将XXX的立即数常量移至SI寄存器;另一方面,如果声明XXX DW?不带冒号,那么XXX是一个字变量;同一条指令MOV SI,XXX现在执行的操作有所不同:它将存储字XXX的运行时值加载到SI寄存器中。因此,无论如何声明XXX,MOV SI,OFFSET XXX都会加载指向XXX的立即值;而MOV SI,XXX W则加载指向立即值的OFFSET或内存变量操作符B,W,D,Q或T。无论XXX的声明方式如何,XXX处的单词都是变量。”

这应该回答您的第二个问题:当A86看到add bl, [second]时,它会假设second是立即字节大小的操作数,因为bl是字节大小的寄存器。

您的下一行mov bx, second期望second是立即字大小的操作数,但是A86已经注意到second将是一个字节,因此会出现错误#13。

您可以通过执行以下操作来获得所需的内容:

add bl, second b        ; add the byte at memory location ds:second to bl
mov bx, offset second

通常,如果您在使用符号之前定义符号,这些问题将消失。例如,这将起作用:

name example1 ; good code
code segment
org 0100h
main:                   ; - MACHINE CODE
  mov bx, main          ; BB0001        - put 0100h in bx
  mov bx, offset main   ; BB0001        - put 0100h in bx
;         ^ offset directive not needed here
;           A86 already knows what to do

  mov bx, [main]        ; 8B1E0001      - put 00BBh in bx
;         ^ brackets work fine to dereference main here

  mov bx, main w        ; 8B1E0001      - put 00BBh in bx
;              ^ w does the same thing as brackets

org 0150h
goodbye:
  int 020h
code ends
end main

但这不起作用:

name example2 ; will not assemble
code segment
org 0100h
main:                   ; - MACHINE CODE
  mov bx, goodbye       ; BB5001        - put 0150h in bx
;         ^ A86 assumes goodbye is an immediate value. This assumption
;           turns out to be a good one, so this line works OK

  mov bx, offset goodbye; BB5001        - put 0150h in bx
;         ^ offset directive tells A86 that goodbye will be an immediate
;           value. You can skip it, since A86 assumes that anyway

  mov bx, [goodbye] ; this line is the culprit!
;         ^ A86 doesn't know what to do about these brackets

  mov bx, goodbye w     ; 8B1E5001      - put 20CDh (`int 020h`) in bx
;                 ^ w directive tells A86 that goodbye will be a word 
;                   variable

org 0150h
goodbye:                ; label goodbye not defined until way down here!
  int 020h
code ends
end main

答案 2 :(得分:1)

DOS手册指示处理程序的指针:

mov ax,word ptr es:[bx],BBBB

以BBBB为基础

也是对段的基础的引用 - 在推送cx之后相同[我认为 - 我无法记住]

与上述相同,除了在BBBB处是SSSS用于分段

现在我写了一个处理程序,当我的鼠标因为一个坏的崩溃而停止了functionign时我用这个词ptr作为一个字节而不是一个单词它似乎工作,因为我从来没有做过一个真正的单词指针而只是用'word ptr '在程序中以及将字节向后二进制转换为十六进制[A6向后为65]。

也是我在DOS amnual中发现的一个错误,用于进行INT调用[不是在调试程序集或程序集程序中通过调用int ##但实际上是直接调用8080而且事实是这样的它不是中断调用,而是IRQ调用。指令代码不正确 - 特别是在演示文稿中。 同样在英特尔es:[bx]不起作用 - 必须使用es [bx]

另外,xtension-我的头脑 - 回答你的问题,你正在引用一个8位寄存器然后是16位寄存器 - 你指示ADD bl然后在添加操作数后改变bx这是你的错误#13。

你必须做的是确保bl在之前与BX兼容,否则你将得到一个无正向参考错误,这基本上是什么.ADD指令自动保护BX不被处理,直到计算请求或命令请求是完全完成的,除非它是作为IRQ请求进行的,它可以用sti和cli暂停,其间是更改页表或参考表的参考。