1 USING A86 This is intended as a guide to get A86 to work for all the programs in the Tutor. It only covers things that won't work or things A86 does differently. It does not cover any of the benign options like local labels. ===== CHAPTER 1 You need to take your text editor and change the last line of the template files. At the moment they read: END start You may either eliminate the line or change it to: END main If you don't, you will get this error message: END start~40 Conflicting Multiple Definition Not Allowed~ Do this for all the original template files, because this line will always cause an error. You will find out why when you get to Chapter 10. You should also insert the word PUBLIC just before the line with ASSUME. Do this in all the template files. PUBLIC ASSUME cs:CODESTUFF, ds:DATASTUFF You will find out why in Chapter 15. A86 has some unusual defaults, so you need to change them when you assemble a file. If your file is named myprog.asm, the command line you want to use for the rest of this tutorial is: >a86 +DOSX myprog.asm You must use the file extension .asm when you call the program. You can make a batch file (let's call it QASM.BAT) which has: a86 +DOSX %1.asm Then all you need to do is: >qasm myprog Those four options on the command line are: ______________________ The PC Assembler Tutor - Copyright (C) 1990 Chuck Nelson The PC Assembler Tutor 2 ______________________ +D numbers with leading 0s are default decimal +O make an object file +S don't create an ancillary symbol table +X require specific declaration of external information They should be used from now on. When you are through with all the chapters, you can decide whether you want to continue using them all. If you are using D86, you need to eliminate the 'S'. The declaration should be +DOX since you will need the symbol table. ===== CHAPTER 2 Please read all of chapter 2 before you read these comments. The defaults and definitions are the same with two exceptions. First, any number that begins with a '0' is hex by default. That is, 22 is a decimal number and 022 is a hex number. This has some serious side effects. Take the number: 0847d This is 847, right? No. It is 0847Dh = 34,637. In Chapter 7 we will use these binary numbers: 01001011b 00000100b These should be 75 and 4 respectively, but A86 evaluates them as 01001011Bh = 268500992 and 0100Bh = 4107. Since half of the binary numbers you use will start with a 0, half of your binary numbers will be wildly incorrect. In order to correct the situation, you need to put a +D on the command line. This is the 'D' of +DOSX. The D will insure that all numbers starting with 0 will be decimal. This gets rid of all the side effects. Alternatively, you can put: RADIX 10 at the top of your files before any of the code or data. This has the same effect. Of course, if you really do want hex numbers, this can be overridden with a specific 'h' after any number. There is another major problem with data definitions. Let's say that you want the following definitions: weight dw ? cost dw 20 profit dw ? but you forget to put in some of the initializations in your text file (a situation which is not unknown): weight dw Using A86 3 _________ cost dw profit dw ? All other assemblers will generate an error. You must either put in an initial value or you must say that you want no initial value (by putting in a question mark). Not only does A86 not generate an error, it does something strange. If there is neither initialization nor a question mark, A86 will calculate an address for the variable but WILL ALLOCATE NO SPACE FOR IT. What this means is that in our above example, 'weight', 'cost', and 'profit' will all be at the same memory address. 'Weight' and 'cost' will have the same address with no space allocation. 'Profit' will be at the same memory address too, but will have space allocated for it. This is all done silently, so you don't know that this is being done. There is no way to shut this off. You might be able to find that this is happening by looking at the symbol table, but that means that you suspect that it is happening. What you need to do whenever you use A86 is: ALWAYS CHECK ALL DATA TO MAKE SURE THAT IT IS INITIALIZED OR HAS A QUESTION MARK ===== CHAPTER 10 We now come to some actual differences. A86 does not produce a list file. You can read the justification for this in your documentation. Does this make a difference? It would be nice to have one, but we can normally live without it. Just follow what is happening with the MASM listing. p94 - ASSUME statements. Both TASM and MASM keep track of how you want the segments to be referenced. A86 doesn't. It simply ignores any ASSUME statements. This means that any segment overrides must be coded into the text file with: mov cx, ss:variable4 mov cx, es:variable2 mov cx, ds:variable1 mov cx, cs:variable3 A86 assumes that all code uses CS (which it must), and that all data uses DS unless there is a specific segment override. Is this a big imposition? Not really. If you use a segment register other than DS, it is normally for dealing with arrays, and in those cases you need a segment override anyways. You will find out about that in the next chapter. p97 - END statements. END is not necessary in A86. It knows that the end has come when the file is finished. The default starting point for an A86 file is the label 'main'. If A86 sees a label name after an END statement, then it RENAMES that word 'main', and renames all occurances of that word in the file 'main'. It does not change the default starting name. This means that if you The PC Assembler Tutor 4 ______________________ have a statement like: END start and you also have the label 'main' in your file, A86 will change all occurances of 'start' to 'main', causing multiple use of the same label. ======== Chapter 15 p154 - You do not need PUSHREGS and POPREGS. With A86, PUSH is exactly the macro PUSHREGS: PUSHREGS ax, bx, cx, dx, si PUSH ax, bx, cx, dx, si These are exactly the same. POP shows the actual order that things will be popped, while POPREGS has the reverse order so that you can use a word processor to copy the PUSHREGS part. For the above PUSH declaration, this is the correct POP: POP si, dx, cx, bx, ax POPREGS ax, bx, cx, dx, si From now on, whenever you see PUSHREGS, change it to PUSH, and whenever you see POPREGS, change it to POP but reverse the order of registers so that it is the actual order in which things are POPped. You can delete the line: include \pushregs.mac from your template file. ; - - - - - - - - - - Please read the whole chapter before reading the rest of these comments. For some reason, A86 makes ALL normal variables and labels PUBLIC unless you specifically tell it not to. The whole thrust of programming for the last 20 years (PASCAL, C, and all structured languages), has been to make NOTHING public unless specifically requested, so this is an unwelcome default setting. You turn it off by naming any normal (but not local) variable PUBLIC. In fact, if you use the word PUBLIC alone: PUBLIC without any name after it, A86 will turn this off. That is why you put it in all the template files. Always have this in all your assembler files. A86 also assumes that any variable that has no data declaration is EXTRN. This is a bad policy. What will happen is the following. You are using the variable 'last_occurance' and you Using A86 5 _________ misspell it 'last_ocurrance'. A86 sees no data declaration so assumes that it is an external variable and assembles the file. Three hours later you link the 6 modules of your program together and you get a link error. The linker cannot find 'last_ocurrance' anywhere. Just as you should need to explicitly name things PUBLIC, you should need to explicitly name things EXTRN. You do this by putting +X (forced external declarations) on the command line. This is the 'X' in the '+DOSX' that you have been using on the command line. ===== CHAPTER 21 You need to change the ORG statement so it is in front of main ORG 100h main proc near This is because you are using main as the starting address, so it must be at 100h. This 100h is optional with A86. If it is making a .COM file it automatically starts at 100h. A86 is designed to give you a .COM file directly, so all you need to do with a single file is: >a86 +DS myfile.asm and you will get MYFILE.COM as the output file. In the example where we make a .COM file from multiple files, these files are set up to be .OBJ files. If you want to make them into a .COM file directly, you need to take out all PUBLIC, EXTRN and END statements (and adjust PUSHREGS and POPREGS) and then do: >a86 +DS prog1.asm prog2.asm prog3.asm making sure that prog1.asm is first. The output file should be prog1.com. ===== CHAPTER 26 You need to read all of Chapter 26 before reading any of the following. A86 will work fine with any standard segment definitions. It also has two special segment statements of its own. The first: CODE SEGMENT will generate the following: _TEXT SEGMENT PUBLIC 'CODE' The second statement: DATA SEGMENT The PC Assembler Tutor 6 ______________________ is NOT a segment declaration. It generates NO segment, it allocates NO space and it initializes NO data. What is it? I'll explain how it operates, but I have no idea why it exists. The first time you use the 'DATA SEGMENT' instruction in a file it is followed by ORG: DATA SEGMENT ORG 1000h ORG relocates the counter for where the assembler is allocating space in memory. From this point on, every time you define variables: time dw ? distance dw ? space dw ? A86 generates an distinct address for each variable. However, it ALLOCATES NO SPACE. This is just an address that the code can use when it refers to the variables. If you have the following variables: year dw 1990 prime dw 73 cost dw 5167 A86 will generate address for these variables but (1) will allocate NO space, (2) will do NOTHING with those initializing values and (3) WILL NOT COMPLAIN that you have tried using initialized data in a DATA SEGMENT statement. A86 will do the equivalent of: year dw ? prime dw ? cost dw ? This data is technically in the CODE SEGMENT. If the code is longer than that initial ORG number, some of the code will be in the same place as some of the data and if you write to the data you will overwrite the code. A86 will not complain. For instance, we had ORG 1000h (4096d). If the code is 6000 bytes long, the last 2000 bytes of code will share the space with the data. This leads to either bad data or bad code or both. Why have this? Well, when DOS loads a .COM file into memory, it uses ALL of memory. If I have: INTSCRN.COM 541 07/23/90 17:45 a .COM file that is 541 bytes long, DOS will allocate about 550,000 bytes for it on my computer. 549,459 bytes of this are wasted space. It is A86's idea to put data in this wasted space. There is no reason for this, so don't do it. If you have a .COM file, put all your data in the CODE SEGMENT. If you have an .OBJ Using A86 7 _________ file you need to create a legitimate SEGMENT for the DATA. Its name cannot be: DATA SEGMENT PUBLIC 'DATA' If I have the following program: ; - - - - - - - - - - - - - - - DATA SEGMENT PUBLIC data1 db "This is the output string", 13, 10, "$" data2 db 100 dup (0) ENDS CODE SEGMENT main: mov ax, seg DATA mov ds, ax mov ah, 09h ; print string lea dx, data1 int 21h mov ax, 4C00h ; exit int 21h ; - - - - - - - - - - - - - - - and I try to make an object file with it, I get the following error: mov ax, seg DATA~61 Overlapping Local Not Allowed~ The ability to put the segment starting address in the segment register is a minimal requirement for doing anything. This effectively eliminates the possibility of using DATA as the name for a segment. Therefore, those of you who use Turbo Pascal need to use: DSEG SEGMENT PUBLIC as an alternative. This will work with no problems.