3

I'm trying to use A86 to assemble some code for 8086. I narrowed my problem down to 4 lines of code.

MOV BX, testz
ADD AL, [testz]

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

What do you think is wrong with this code? I am moving the address itself to BX register and adding the byte-value in the testz address to AL.

In a bigger program I also get #ERROR 13: Byte/Word Combination Not Allowed.

But label is a word where [label] is a byte. Why can't my compiler differentiate between those?

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

Because I can't see any Byte/Word conflict.


My compiler interprets offset testz and testz equally. I looked at the bytecodes and couldn't see any difference.

MOV BX, testz
ADD AL, [BX]

The code above works, but is there any other way that I can do this in one line like

ADD AL, [testz]

Whenever I put a label name in [], it is just not acceptable according to my compiler a86. But I feel they are allowed in the language.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
EralpB
  • 1,621
  • 4
  • 23
  • 36

3 Answers3

5

I suspect you want MOV BX, offset testz. It appears that your assembler interprets [testz] and testz to mean the same thing.

You might confirm this by trying instead the notionally equivalent LEA BX, testz

EDIT: (from 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.
Managu
  • 8,849
  • 2
  • 30
  • 36
  • Aah! For example this works ADD AL, testz B. So when I wrote [testz] I actually meant testz B. But was my syntax and assumptions wrong? Or is it my compiler who chose to implement them that way? – EralpB Jun 08 '12 at 02:10
  • It's been ... decades? ... since I touched A86. The de facto standard for 8086 assembler syntax is the syntax of MASM. But A86 does things a little bit differently. It feels like A86 is attempting to do single pass assembly, while MASM used a multipass approach. But I don't remember for sure. – Managu Jun 08 '12 at 02:14
4

The problem you are running into stems from the fact that A86 is a single pass assembler. When you use symbols like testz and second before defining them A86 has to guess what they are. It assumes that they will be immediate values, but later on it discovers that they're actually labels. A multi-phase assembler might go back and change the decision it made earlier, but A86 doesn't do that. It simply barfs forth an error (#16). This is why the error appears in the source file near the definition: that's where A86 was when it discovered the problem.

You can use the directives offset, d, w, and so on to tell A86 explicitly what you want it to do, so it won't have to make guesses.

The A86 manual explains: "IMPORTANT: you must understand the distinction between a label and a variable, because you may generate a different instruction than you intended if you confuse them. For example, if you declare XXX: DW ?, the colon following the XXX means that XXX is a label; the instruction MOV SI,XXX moves the immediate constant address of XXX into the SI register. On the other hand, if you declare XXX DW ? with no colon, then XXX is a word variable; the same instruction MOV SI,XXX now does something different: it loads the run-time value of the memory word XXX into the SI register. You can override the definition of a symbol in any usage with the immediate-value operator OFFSET or the memory-variable operators B,W,D,Q, or T. Thus, MOV SI,OFFSET XXX loads the immediate value pointing to XXX no matter how XXX was declared; MOV SI,XXX W loads the word-variable at XXX no matter how XXX was declared."

This should answer your second question: When A86 sees add bl, [second] it assumes that second will be an immediate byte sized operand since bl is a byte sized register.

Your next line mov bx, second expects second to be an immediate word sized operand, but A86 has already made a note that second will be a byte, so you get error #13.

You can get what you want by doing this instead:

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

Generally, these problems will disappear if you define your symbols before using them. For example, this will work:

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

but this will not work:

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
Paganini
  • 109
  • 1
  • 5
  • 1
    So A86 basically has the worst of all possible worlds, where the meaning of `mov ax, label` depends on whether the label is a code or data label? I thought MASM was bad enough, where "variables" magically imply an operand-size and `[]` around constants are [sometimes ignored](https://stackoverflow.com/questions/25129743/). But at least MASM is (I think) consistent that bare label is always a memory operand, not immediate. (And NASM is consistent the other way: bare symbol is *always* an immediate, `[]` is always a memory operand, and you can tell without looking at other source lines.) – Peter Cordes Mar 28 '20 at 19:15
  • Anyway, interesting to see where later assemblers got their syntax ideas from. – Peter Cordes Mar 28 '20 at 19:16
  • Are there many A86 questions on SO? There's currently no tag for A86, but we could create one. (Users with high rep can create tags and make edits without having to go through a review queue, so maybe leave some links in a comment if you know of a few more.) – Peter Cordes Mar 28 '20 at 19:29
  • 1
    @Peter-Cordes Yes, the reason I answered this question is that a week or so ago I was struggling in confusion with this exact same thing - brackets sometimes work to dereference, but not others. I tried to write the answer I wished I'd found then. :) As far as A86 questions, after I completed my SO "orientation," SO suggested some questions I might be interested in based on the tags (x86 and so on) I selected. A few of them were about A86, so I searched "A86" and got about 50 hits. Some of them are false positives, however (quite a few were about columns in Microsoft Excel...) – Paganini Mar 28 '20 at 19:48
  • @PeterCordes - Although segments are weird in A86. There's not really a data area like there is in MASM. The "data" segment in A86 is just where A86 keeps track of how much space all the run-time variables will need. Constants and initialized variables have to go in the code segment. Below are some links that directly reference doing things in A86, either in the question or in the answers. – Paganini Mar 28 '20 at 20:21
  • MASM has the same distinction of `label:` being a normal symbol (without implied operand-size) vs. `label dd ...` being a "variable". But I think MichaelPetch said older versions of MASM don't accept `label:` in data segments. IDK, I've never actually used MASM (and would never choose to), I just know about it from SO questions. – Peter Cordes Mar 28 '20 at 20:24
  • 1
    I searched to and tagged several questions; you can remove those link comments. I created https://stackoverflow.com/tags/a86/info. Some of the questions you linked, and others that mention a86, did so only in answers, or mentioned it in the question but weren't *about* A86. – Peter Cordes Mar 28 '20 at 21:28
1

The DOS Manual instructs for a pointer for a handler for such :

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

to where BBBB is the base

also is the reference to the base for the segment-the same after pushing cx[i think-I cant remember]

to which the same is as above except at BBBB is SSSS for segement

Now I wrote a handler when my mouse stopped functionign becasue of a bad crash and I used this word ptr as a byte instead of a word and it appears to work as i never made an actual word pointer but just used 'word ptr' in teh program along with a backwards binary conversion of the byte into hex [A6 backwards is 65].

Also is the error I found int eh DOS amnual for making an INT call [not as in debug assembly or programmign assembly by calling int ## but actually making a direct call to the 8080 and to which the fact of this is that it is not an interrupt call but an IRQ call.The instruction code is incorrect-specifically in the presentation. Also on the Intel es:[bx] does not work-must use es[bx]

Also ine xtension-wheres my head at---to answer your question you are making a reference to an 8 bit register and then the 16 bit register-to whcih you are instructing ADD bl and then change bx after the add operand.This is your error #13.

What you must do is assure that bl is compatable with BX prior to-or such you will get a no forward reference error to which basicially what this is.The ADD instruction automatically protects the BX from being amnipulated until tis calculation request or command request is fully complete unless it is undertaken as an IRQ request to which it may be suspended with sti and cli to which in between is a reference for changing the page table or the reference table.