2 * D-Group Assembler for MMURTL (DOS Version).
\r
4 * Copyright 1991,1992,1993,1994 R.A. Burgess
\r
6 Version 1.2 11/20/93 - major rewrite on instruction table
\r
7 Version 1.3 8/28/94 - Clear macro buf on level 1 to 0 transition
\r
8 Version 1.4 9/29/94 - Smashed bug in 66| prefix for string commands
\r
9 Version 1.5 10/5/94 - Optimized a couple of commands and fixed
\r
10 bug in ENTER X,X instruction. This version seems
\r
11 really stable ("yeaaaaa Right," he says...)
\r
13 10/29/94 Fix problem with sign extending bytes on ADD
\r
14 Version 1.6 12/31/94 - Removed temp files on succesful assemble
\r
17 #define U32 unsigned long
\r
19 #define U16 unsigned int
\r
21 #define U8 unsigned char
\r
30 #include "runfile.h"
\r
35 U8 level = 0; /* current include level */
\r
36 U32 lineno[LEVELS]; /* line number being parsed */
\r
37 U8 fContinue = 0; /* True if just returned from include */
\r
39 char srcname[LEVELS][40]; /* also active include filenames */
\r
43 /* File handles for all files */
\r
45 FILE *src_fh[5] = {0,0,0,0,0}; /* Current source file */
\r
46 FILE *run_fh = 0; /* Current .RUN, .DLL, or .DDR (output) */
\r
47 FILE *ds_fh = 0; /* temp file for ALL DS strorage */
\r
48 FILE *cs_fh = 0; /* temp file for ALL CS code */
\r
49 FILE *lst_fh = 0; /* List file */
\r
50 FILE *sym_fh = 0; /* Symbol file for debugger */
\r
52 char *csname = "CS.TMP";
\r
53 char *dsname = "DS.TMP";
\r
55 U8 filetype = 1; /* 1 = RUN, 2 = DLL, 3 = DDR */
\r
57 U8 fListA = 0; /* True if detailed list file */
\r
58 U8 fListE = 0; /* True if Error only list file */
\r
59 U8 fSymDump = 0; /* True if we add symbols to the list file */
\r
60 U8 Column = 0; /* where are we on the LIST line */
\r
61 U16 error_count = 0;
\r
65 /* Max input line is 132, but 200 allows plenty for macro subs */
\r
66 S8 line_buf0[200]; /* Two buffers are swapped during macro substitution */
\r
68 S8 *line_ptr; /* pointer to next char on line */
\r
70 S8 list_buf[200]; /* Used to hold line string for list file */
\r
71 S8 fLineIn =0; /* TRUE is list_buf has something to list */
\r
73 S8 TString[133]; /* all parsed tokens are placed here in text form */
\r
74 S16 CBString; /* size of parsed token */
\r
75 S16 TSymnum; /* Symbol table entry number, else 0 */
\r
76 U32 TNumber; /* value of numeric token */
\r
77 S16 TInst; /* Instruction number, else 0 */
\r
78 S16 TReg; /* Register number, else 0 */
\r
79 S16 Token; /* Token type (also returned from parse) */
\r
80 S8 fPutBack = 0; /* TRUE (non=zero) if last token was not used */
\r
82 S8 LTString[133]; /* Duplicates of Token storage for ReturnToken(); */
\r
90 S8 UString[31]; /* Place to save unknown labels for Forward Reference */
\r
91 S16 UCBString; /* Size of Unknown label */
\r
93 /* The two Symbol tables have 5 entries; Type, Size, Pointer to Name,
\r
94 Segment Offset, and Line.
\r
95 As each symbol is found, it's identifed by type, and the name
\r
96 is moved to the packed symbol buffer. A pointer is added to the
\r
97 table to point to the name in the buffer, while it's size, type,
\r
98 segment offset, and line number are added to the table.
\r
99 Macro names are also stored in the symbol table, but offset entry
\r
100 for a macro indicates it's offset in the Macro buffer.
\r
103 /* Variables for symbol tables */
\r
105 /* Global Symbol Table */
\r
107 #define SYMSMAX 500
\r
108 #define SYMBUFMAX 10140 /* Avg of 10 byte per name, 700 Max */
\r
111 U16 Type; /* Token (e.g, CLabel) */
\r
112 U16 Line; /* Line symbol was declared on */
\r
113 U8 Size; /* Size of symbol name */
\r
114 S8 *Ptr; /* Pointer to name in packed buffer */
\r
115 U32 Offs; /* Offset in segment */
\r
118 struct symtab gst[SYMSMAX]; /* storage for the GST */
\r
120 /* S8 SymBuf[SYMBUFMAX]; */ /* Where names are stored. Will be Alloced */
\r
121 S8 *pSymBuf; /* ptr to allocated buffer */
\r
123 S8 *pSymNext; /* ptr to next new entry in symbol buffer */
\r
124 S16 iSymNext = 1; /* index to next new symbol table entry. */
\r
125 /* Starts at 1 - zero it reserved because */
\r
126 /* Parse returns 0 for EOL */
\r
132 /*********** Local Symbol Table *************/
\r
134 /* This is cleared after each include file from level 1 is closed */
\r
135 /* Clearing means we reset *pLSymNext to begining of buffer */
\r
136 /* and reset iLSymNext to 1. This "hides" local symbols. */
\r
138 #define LSYMSMAX 1800
\r
139 #define LSYMBUFMAX 16384 /* Avg of 7 bytes per name */
\r
141 struct symtab lst[LSYMSMAX]; /* storage for the LST */
\r
143 /* S8 LSymBuf[LSYMBUFMAX]; */ /* Where names are stored.*/
\r
144 S8 *pLSymBuf; /* for allocated buffer */
\r
146 S8 *pLSymNext; /* ptr to next new entry in symbol buffer */
\r
147 S16 iLSymNext = 1; /* index to next new symbol table entry. */
\r
148 /* Starts at 1 - zero it reserved because */
\r
149 /* Parse returns 0 for EOL */
\r
151 /************* Forward Ref Table *********************************/
\r
153 Labels that are encountered as forward references are
\r
154 stored in this table. When we run across a forward, we do
\r
155 not know what segment they are refering to unless it is from
\r
156 a jump, call, or loop instruction. We will NOT know for many
\r
157 items until they are actually declared. After all the code
\r
158 and data has been processed, we go through this table
\r
159 and fix all the unknown references using the relative
\r
160 The type of forward references are:
\r
162 1) DSEG DWORD item refers to UNK item (?Seg MemRef)
\r
163 2) CSEG DWORD item refers to UNK item (?Seg MemRef)
\r
164 3) CSEG to CSEG relative 8 (Jump, Jc, or Loop)
\r
165 4) CSEG to CSEG relative 32 (Jump or Call)
\r
167 MOTE: If a calculation is made with the unknown reference, 0
\r
168 is used in the calculation. We ALWAYS ADD the value we stored
\r
169 with what is found when the reference is resolved.
\r
173 #define FREFSMAX 32768/12
\r
174 #define FREFTABMAX 32768
\r
175 #define FREFBUFMAX 16384
\r
177 /* Types of forward references. */
\r
179 #define DSEGREF 1 /* 32 bit Abs Ref in DSeg, to what is unknown! */
\r
180 #define CSEGREF 2 /* 32 bit Abs Ref in CSeg, to what is unknown! */
\r
181 #define CCR32REF 3 /* 32 bit Relative in CSeg */
\r
182 #define CCR8REF 4 /* 8 bit Relative in CSeg */
\r
185 U8 Type; /* 1, 2, 3, or 4 */
\r
186 U8 NameSz; /* Size of ref name */
\r
187 U16 Line; /* Line reference was made on (for error if not found) */
\r
188 S8 *Ptr; /* Pointer to name in packed buffer */
\r
189 S32 Offs; /* Offset in segment were it should go */
\r
192 struct forreftab *pfrt; /* pointer to allocated table */
\r
195 S8 *pRefNext; /* ptr to next new entry in symbol buffer */
\r
196 S16 iRefNext = 0; /* index to next new forward ref table entry. */
\r
198 /************ External Reference table ************/
\r
200 /* External definitions that are encountered in a module are
\r
201 first entered in the Global Symbol Table (GST) as externals
\r
202 if they haven't already been defined (public) by the module
\r
204 When a reference is made to an external, we see if the public has
\r
205 already been defined. If so, we resolve it immediately. If not,
\r
206 we make an entry in the External Reference Table (ERT). The
\r
207 entry has the following 4 pieces of information:
\r
208 - Line where reference was made.
\r
209 - Index to place holder entry in GST.
\r
210 - Segment where reference was made (boolean - TRUE for code seg).
\r
211 - Offset in that segment where the resolution will be made.
\r
212 With this information we can reslove all the external references
\r
213 before we write the code segment to the run file.
\r
216 #define EREFSMAX 400
\r
219 U8 Type; /* Type of reference so we know how to apply it */
\r
220 U16 iSym; /* Index of gst entry. Hi bit seg if CSeg ref */
\r
221 U32 Offs; /* Offset in segment were ref needs 32 bit fixing */
\r
224 struct extreftab ert[FREFSMAX];
\r
226 S16 iERefNext = 0; /* index to next external ref table entry. */
\r
230 /*********** Fix Up Table *********************/
\r
232 /* This table holds 6 types of fixups along with the offset
\r
233 in the segment to be fixed up, and if applicable, an index
\r
234 to the DLL public name in the GST (which should be defined
\r
237 - Ref in CSEG to address in DSEG
\r
238 - Ref in CSEG to address in CSEG
\r
239 - Ref in DSEG to address in DSEG
\r
240 - Ref in DSEG to address in CSEG
\r
241 - CSEG DLL near 32 bit call used
\r
242 - CSEG DLL near 32 bit call defined
\r
243 - Offset of 32 bit reference to be resolved
\r
244 - Index to DLL public name in GST (if applicable)
\r
246 With this information we can supply the loader with the TAG entries
\r
247 in the RUN file needed to resolve them. Most of these entries will
\r
248 be made as we parse the code, but many will also be added after
\r
249 we fix the forward references because we won't know what segment
\r
250 the reference is made to until then.
\r
253 #define FIXUPSMAX 32768/7
\r
254 #define FIXUPBUFMAX 32768
\r
257 U8 type; /* Type of fixup C0, C1, C2, C3, C5, or C8 */
\r
258 U32 Offs; /* Offset in segment for 32 bit fixup */
\r
259 U16 iSym; /* index of DLL entry in gst, else 0 */
\r
262 struct futab *pfut; /* pointer to allocated Fix Up Table */
\r
264 S16 iFUNext = 0; /* index to next fix up table entry. */
\r
272 /********* Macro variables *******************/
\r
274 #define MACSMAX 200
\r
275 #define MACBUFMAX 3000
\r
277 S8 *rgMacPtr[MACSMAX]; /* pointer to simple macros */
\r
279 S8 *pMacNext; /* ptr to next new entry in macro buffer */
\r
280 S16 iMacNext = 0; /* index to next new symbol entry */
\r
282 /* Variables for current segment address offset tracking */
\r
284 S8 fStart = 0; /* True if they gave a start address */
\r
285 S32 StartAddr = 0; /* Filled in when .START is encountered */
\r
286 S32 oNextData = 0; /* Tracks current DSEG offset */
\r
287 S32 oNextCode = 0; /* Tracks current CSEG offset */
\r
288 S32 CodeOffset = 0; /* From Virtual Command */
\r
289 S32 DataOffset = 0; /* From Virtual Command */
\r
290 S32 *pNextAddr = 0; /* Points to current segment offset counter */
\r
291 S8 fDataSeg = 0; /* True if parsing DSEG, else parsing CSEG */
\r
292 S32 StackTotal = 0; /* Total Stack Specified in Code segs */
\r
294 /******************************************************************
\r
295 Variables for RAW operands in an instruction.
\r
296 These are used when we read in and separate each part of the
\r
297 operands so it can be evaluated.
\r
300 S16 rgToken[3][20]; /* Raw tokens in the operand (as many as 20) */
\r
301 S32 rgVal[3][20]; /* value if token is number/displacement */
\r
302 S16 rgTID[3][20]; /* Register ID if token is a register */
\r
303 S16 rgTCnt[3]; /* total count of tokens in raw operand */
\r
305 /******************************************************************
\r
306 These variables are filled in while parsing and evaluating
\r
307 instructions that have been read in.
\r
308 They have all the info needed to
\r
309 encode the instruction into the object module and
\r
310 produce FixUp Records if needed.
\r
313 /* These are used in the description of all OPERANDS for the current
\r
314 instruction we are working on.
\r
316 S16 rgOpType[3]; /* Operand type for compare to instruction */
\r
317 S16 rgOpReg[3]; /* If reg only, this which one */
\r
318 S8 OpSize[3]; /* Operand size for first two (fByte, fWord, fFar etc.) */
\r
319 S8 OpSizeA; /* Overall operand size for instruction */
\r
320 S8 OpPrefix; /* Bit set for a segment prefix (fESp etc.) */
\r
321 S16 iInstEntry; /* Which entry is it in rgINS */
\r
322 S16 CrntInst; /* instruction we are working on */
\r
323 S16 InstPfx; /* Special Insturction prefix for crnt inst */
\r
324 S16 nOperands; /* number of operands we found */
\r
325 S8 fForRef; /* Crnt inst makes a Forward Reference */
\r
327 /* The following vars are used if we have a memory reference that is
\r
328 encoded as part of the instruction.
\r
330 S8 OpMType; /* Mem type (compared to rgM32). 0 if not mem type */
\r
331 S16 OpBase; /* Base register if fBase is true */
\r
332 S16 OpIndx; /* Index register if fIndx is true */
\r
333 S32 OpDisp; /* Displacement if fDisp8 or fDisp32 is TRUE */
\r
334 S16 iMemEntry; /* If mem operand, which entry in rgM32 */
\r
336 /* The following are used if we have immediate values to be encoded as
\r
337 part of the instruction. Immediates can also be addresses such as
\r
338 those in Direct and Relative Jumps and Calls!
\r
340 S32 OpImm; /* Immediate value if fOpImm is true */
\r
341 S8 fOpImm; /* If OpImm has a value */
\r
342 S32 OpImm2; /* Second Imm value for iSAD and other multi-Imm types */
\r
343 S8 fOpImm2; /* If OpImm2 has a value */
\r
345 /* This is set for each type of fixup required after an instruction
\r
346 line. Data fixups are done directly in the code that generates
\r
347 storage in DSeg. */
\r
349 U8 nFixUp; /* Fixup number (Cx) */
\r
351 /*************************************************************************/
\r
353 /* In the final stages of building an instruction, these contain the
\r
354 fragment bytes of encoded instructions (along with flags for
\r
355 optional parts used).
\r
358 U8 bOpc1; /* Zero if not used */
\r
359 U8 bOpc2; /* Always used */
\r
360 U8 bModRM; /* ModRM byte value if used */
\r
361 U8 bSIB; /* SIB value if used */
\r
362 S8 fModRM; /* True if bModRM is used */
\r
363 S8 fSIB; /* True if bSIB is used */
\r
365 /*** These are used in the expression parser ******/
\r
367 U8 ExpType; /* 0 = Forward, 1 = Local, 2 = Global, 3 = Current Addr */
\r
369 S16 nExpSyms; /* Used by the numeric expression evaluator */
\r
370 S16 iExpSym, iExpSym0; /* if a symbol value translates to a SYMOFF,
\r
371 this holds the symbol table index. */
\r
372 S8 fOffset; /* True if derived from an Offset */
\r
374 /* Variables for Storage allocation */
\r
377 S8 fMoreStorage = 0; /* True when storage continues to next line */
\r
380 /**** Variables for building the RUN File (DLL or Device Driver) ********/
\r
382 /* Once we have the CS and DS tmp files run through to correct any external
\r
383 variables or forward labels, we build the run file. This is done
\r
384 by building the tag records, sending them followed by the proper data
\r
388 struct tagtype tag;
\r
391 /******************* END VARIABLES - BEGIN CODE ********************/
\r
393 /* ANSI prototypes for all functions are in DProtos.h */
\r
395 #include "DProtos.h"
\r
398 /***************************************************************/
\r
399 /* Write a DWord to the current segment and update the counter */
\r
400 /***************************************************************/
\r
402 void OutDWord(unsigned long Data)
\r
404 unsigned char *pOut, b;
\r
408 for (i=0; i<4; i++) {
\r
415 for (i=0; i<4; i++) {
\r
423 /******************************************************************/
\r
424 /* Write a DWord to the current segment and DO NOT update counter */
\r
425 /******************************************************************/
\r
427 void OutDWordCS(unsigned long Data)
\r
429 unsigned char *pOut, b;
\r
432 for (i=0; i<4; i++) {
\r
438 /******************************************************************/
\r
439 /* Write a DWord to the current segment and DO NOT update counter */
\r
440 /******************************************************************/
\r
442 void OutDWordDS(unsigned long Data)
\r
444 unsigned char *pOut, b;
\r
447 for (i=0; i<4; i++) {
\r
453 /**************************************************************/
\r
454 /* Write a Word to the current segment and update the counter */
\r
455 /**************************************************************/
\r
457 void OutWord(unsigned int Data)
\r
459 unsigned char *pOut, b;
\r
477 /**************************************************************/
\r
478 /* Write a BYTE to the current segment and update the counter */
\r
479 /**************************************************************/
\r
481 void OutByte(unsigned char Data)
\r
484 fputc(Data , ds_fh);
\r
488 fputc(Data , cs_fh);
\r
493 /*****************************************************************/
\r
494 /* Write a BYTE to the current segment and DO NOT update counter */
\r
495 /*****************************************************************/
\r
497 void OutByteCS(unsigned long Data)
\r
504 /* All the "grunt work" functions are in dasmq.c */
\r
508 /*********************************************
\r
509 This searches the Reference table for the name
\r
510 described by pb, cb. It only compares items that
\r
511 are the same length (cb == TRefSize[x]).
\r
512 It returns the number or 0 if not found.
\r
513 **********************************************/
\r
515 S16 findref(S8 *pb, S16 cb) /* pointer to, and size of string */
\r
520 strncpy(name, pb, cb); /* move name local */
\r
521 name[cb] = 0; /* null terminate */
\r
524 while (i>0) { /* backwards through forward ref table */
\r
526 /* Only compare if same size */
\r
527 if (pfrt[i].NameSz == cb) {
\r
528 if (strncmp(name, pfrt[i].Ptr, cb) == 0) return(i);
\r
535 /*****************************************************
\r
536 Evaluates only single token operands and sets up
\r
537 globals so EvalOper can finish the job.
\r
538 The actual value or register is left in
\r
539 rgToken[op][0], and the type is placed
\r
540 in rgTempl[op][0] for a memory operand.
\r
541 *****************************************************/
\r
542 S16 EvalOper1(S16 op)
\r
547 /* Set up symtype up front in case it's needed */
\r
549 if (ExpType == 1) /* Local */
\r
550 symtype = lst[iExpSym].Type;
\r
551 else if (ExpType == 2) { /* global */
\r
552 if (gst[iExpSym].Type & tEXTRN)
\r
554 symtype = gst[iExpSym].Type;
\r
558 switch (rgToken[op][0]) {
\r
560 if (is_r32(rgTID[op][0])) rgOpType[op] = r32;
\r
561 else if (is_r16(rgTID[op][0])) rgOpType[op] = r16;
\r
562 else if (is_r8(rgTID[op][0])) rgOpType[op] = r8;
\r
563 else if (is_rCRG(rgTID[op][0])) rgOpType[op] = rCRG;
\r
564 else if (is_rDRG(rgTID[op][0])) rgOpType[op] = rDRG;
\r
565 else if (is_rTRG(rgTID[op][0])) rgOpType[op] = rTRG;
\r
566 else if (is_rSEG(rgTID[op][0])) rgOpType[op] = rSEG;
\r
567 rgOpReg[op] = rgTID[op][0];
\r
570 if ((rgVal[op][0] >= -128) && (rgVal[op][0] <= 127))
\r
571 rgOpType[op] = val8;
\r
572 else if ((rgVal[op][0] >= -32768) && (rgVal[op][0] <= 32767))
\r
573 rgOpType[op] = val16;
\r
574 else rgOpType[op] = val32;
\r
576 OpImm = rgVal[op][0];
\r
580 OpImm2 = rgVal[op][0];
\r
584 case NUMOFF: /* OFFSET var name. IMMEDIATE VALUE. */
\r
585 OpSize[op] = fDWord;
\r
586 rgOpType[op] = val32;
\r
587 OpImm = rgVal[op][0];
\r
589 if (symtype & CLABEL)
\r
591 else if (symtype & DLABEL)
\r
596 case SYMOFF: /* Check for ALL jump, call & Loop instructions */
\r
598 if (ExpType == 1) /* Local */
\r
599 symtype = lst[iExpSym].Type;
\r
600 else if (ExpType == 2) { /* global */
\r
601 if (gst[iExpSym].Type & tEXTRN)
\r
603 symtype = gst[iExpSym].Type;
\r
605 else /* Unknown - Forward */
\r
608 if (((CrntInst >= xJA) &&
\r
609 (CrntInst <= xJZ)) ||
\r
610 (CrntInst == xCALL)) {
\r
612 if (OpSize[op] & fShort)
\r
613 rgOpType[op] = rel8;
\r
615 rgOpType[op] = relW;
\r
616 OpImm = rgVal[op][0];
\r
620 else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) {
\r
621 rgOpType[op] = rel8;
\r
622 OpImm = rgVal[op][0];
\r
626 rgOpType[op] = mem;
\r
627 OpMType |= fDisp32;
\r
628 OpDisp = rgVal[op][0];
\r
629 if (symtype & CLABEL)
\r
631 else if (symtype & DLABEL)
\r
642 /* print_Oper(op); Testing only... */
\r
647 /*********** EvalOper *******************************
\r
648 Evaluates the array of reserved words, registers,
\r
649 numbers, etc. that should make up an operand.
\r
650 For single token operands it's easy! BUT for memory
\r
651 operands it gets a little more complicated.
\r
652 For memory operands we look for key sequences of
\r
653 tokens that make up the "effective address" as
\r
654 described in the Intel documentation, then see if
\r
655 we have all the pieces to make one (EA).
\r
656 This returns 1 if we can classify the operand and
\r
657 there were no errors. The type of operand we find
\r
658 (e.g., r8, r16, r32, val8, val16, val32, mem,
\r
659 relW, etc.) is placed in rgOpType[op].
\r
660 This calls EvalOper1() to handle single token
\r
661 oprerands and evaluates multiple token operands
\r
662 internally. The reason we break single token operands
\r
663 out in a separate call is for speed and clarity
\r
665 Special handling is required for for JMP, Jcond,
\r
666 and CALL instructions because they may be using
\r
667 a forward reference not yet defined. This is the
\r
668 only case where such a reference is allowed.
\r
669 *****************************************************/
\r
671 S16 EvalOper(S16 op)
\r
674 S8 fDone, fOpenSQ, fError;
\r
677 These are the Raw operands:
\r
678 S16 rgToken[3][20]; Raw tokens in the operand
\r
679 S32 rgVal[3][20]; value if token is number/displacement
\r
680 S16 rgTID[3][20]; Register ID if token is a register
\r
681 S16 rgTCnt[3]; total count of tokens in raw operand
\r
683 This is what is produced:
\r
686 rgOpType[op] = 0; /* int - Operand type for compare to instruction */
\r
687 rgOpReg[op] = 0; /* If reg only, this which one */
\r
689 i = 0; /* index into raw tokens */
\r
690 fError = 0; /* set true for invalid operand error */
\r
691 fDone = 0; /* Set when no more tokens are expected in operand */
\r
692 fOpenSQ = 0; /* keep track of [] */
\r
694 /* flags for segment instruction prefix - NONE unless otherwise set */
\r
695 /* If it's a single token operand, take the fast, easy way out! */
\r
697 if (rgTCnt[op] == 1) {
\r
698 return (EvalOper1(op));
\r
701 else { /* multiple tokens in operand */
\r
703 /* with more than 1 token it is usually a memory reference
\r
704 but not always. We will default to mem and change those we
\r
705 find that aren't. */
\r
707 rgOpType[op] = mem;
\r
709 /* Segment prefix? If so, set flag and eat 2 tokens */
\r
711 if ((rgToken[op][0]==REGIST) && (is_rSEG(rgTID[op][0]))) {
\r
712 if (rgToken[op][1] == COLON) {
\r
713 switch (rgToken[op][0]) {
\r
714 case rDS: OpPrefix |= fDSp; break;
\r
715 case rES: OpPrefix |= fESp; break;
\r
716 case rSS: OpPrefix |= fSSp; break;
\r
717 case rFS: OpPrefix |= fFSp; break;
\r
718 case rGS: OpPrefix |= fGSp; break;
\r
719 case rCS: OpPrefix |= fCSp; break;
\r
722 i += 2; /* skip rSEG and colon */
\r
730 /* Loop through the raw tokens looking for Base Reg, Index Reg,
\r
731 Scale value, or displacement and setting varaibles as needed.
\r
734 while ((i < rgTCnt[op]) &&
\r
737 switch (rgToken[op][i]) {
\r
740 if (is_r32(rgTID[op][i])) { /* check for Indx & Base Reg */
\r
741 if (rgToken[op][i+1] == STAR) { /* Index w/Scale */
\r
742 if (!(OpMType & fIndx)) { /* still OK */
\r
744 OpIndx = rgTID[op][i];
\r
745 if (rgToken[op][i+2] == NUMBER) {
\r
746 switch (rgVal[op][i+2]) {
\r
747 case 2: OpMType |= fScale2; break;
\r
748 case 4: OpMType |= fScale4; break;
\r
749 case 8: OpMType |= fScale8; break;
\r
764 i+=3; /* get past *NUMBER */
\r
766 /* Must be base, unless fBase true, then try Index */
\r
768 if (!(OpMType & fBase)) { /* Base for sure */
\r
770 OpBase = rgTID[op][i];
\r
773 else { /* try Index */
\r
774 if (!(OpMType & fIndx)) { /* It's free, use it */
\r
776 OpIndx = rgTID[op][i];
\r
782 else { /* must be 32 bit general purpose register */
\r
789 case SYMOFF: /* One symbol was used by itself or in an expression */
\r
790 if (ExpType == 1) /* Local */
\r
791 symtype = lst[iExpSym].Type;
\r
792 else if (ExpType == 2) { /* global */
\r
793 if (gst[iExpSym].Type & tEXTRN)
\r
795 symtype = gst[iExpSym].Type;
\r
797 else /* Unknown - Forward */
\r
800 if (OpMType & (fDisp32|fDisp8)) { /* Already a disp! */
\r
805 /* Check for conditional jumps. */
\r
807 else if ((CrntInst >= xJA) &&
\r
808 (CrntInst <= xJZ) &&
\r
809 (CrntInst != xJMP) &&
\r
812 if (OpSize[op] & fShort)
\r
813 rgOpType[op] = rel8;
\r
814 else rgOpType[op] = relW;
\r
816 OpImm2 = rgVal[op][i];
\r
820 OpImm = rgVal[op][i];
\r
827 /* Check for JMP */
\r
829 else if (CrntInst == xJMP) /* && (!(fOpenSQ))) */
\r
831 if ((OpSize[op] & fFar) || (symtype & tFAR)) {
\r
832 rgOpType[op] = iSAD;
\r
834 OpImm2 = rgVal[op][i];
\r
838 OpImm = rgVal[op][i];
\r
842 else if (OpSize[op] & fShort) {
\r
843 rgOpType[op] = rel8;
\r
844 OpImm = rgVal[op][i];
\r
849 else if (OpSize[op] & fFWord) {
\r
850 rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */
\r
851 OpMType |= fDisp32;
\r
852 OpDisp = rgVal[op][i];
\r
853 if (symtype & CLABEL)
\r
855 else if (symtype & DLABEL)
\r
861 rgOpType[op] = relW;
\r
862 OpImm = rgVal[op][i];
\r
869 /* Check for CALL */
\r
871 else if ((CrntInst == xCALL) && (!(fOpenSQ)))
\r
873 if ((OpSize[op] & fFar) || (symtype & tFAR)) {
\r
874 rgOpType[op] = iSAD;
\r
876 OpImm2 = rgVal[op][i];
\r
880 OpImm = rgVal[op][i];
\r
884 else if (OpSize[op] & fFWord) {
\r
885 rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */
\r
886 OpMType |= fDisp32;
\r
887 OpDisp = rgVal[op][i];
\r
888 if (symtype & CLABEL)
\r
890 else if (symtype & DLABEL)
\r
895 else { /* Relative call */
\r
896 rgOpType[op] = relW;
\r
902 /* Check for SGDT SIDT */
\r
904 else if ((CrntInst == xSGDT) || (CrntInst == xSIDT))
\r
906 if (OpSize[op] & fFWord) {
\r
907 rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */
\r
908 OpMType |= fDisp32;
\r
909 OpDisp = rgVal[op][i];
\r
910 if (symtype & CLABEL)
\r
912 else if (symtype & DLABEL)
\r
919 /* Check for Loop */
\r
921 else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ))
\r
923 rgOpType[op] = rel8;
\r
924 OpImm = rgVal[op][0];
\r
930 OpDisp = rgVal[op][i];
\r
931 OpMType |= fDisp32;
\r
932 if (symtype & CLABEL)
\r
934 else if (symtype & DLABEL)
\r
942 case NUMBER: /* can be 8 or 32 bit disp, or hard address */
\r
943 OpDisp = rgVal[op][i];
\r
944 if ((rgVal[op][i] >= -128) && (rgVal[op][i] <= 127))
\r
947 OpMType |= fDisp32;
\r
967 case COLON: /* for far addresses */
\r
974 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
975 OpSize[op] |= fByte;
\r
984 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
985 OpSize[op] |= fWord;
\r
994 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
995 OpSize[op] |= fDWord;
\r
1004 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1005 OpSize[op] |= fFWord;
\r
1014 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1015 OpSize[op] |= fNear;
\r
1024 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1025 OpSize[op] |= fFar;
\r
1034 if (!OpSize[op]) {
\r
1035 OpSize[op] |= fShort;
\r
1045 fprintf(lst_fh, " %d ", rgToken[op][i]); /* TESTING */
\r
1052 if (fError) return(0);
\r
1053 if ((fDone) && (i< rgTCnt[op])) {
\r
1062 /********************************************
\r
1063 Adds ALL forward reference to the Ref table.
\r
1064 This holds references to all foward addresses
\r
1065 (unknown) in the current module.
\r
1066 This stores all Refs UPPER case.
\r
1067 *********************************************/
\r
1068 void ForRef(U8 type, S32 Offset)
\r
1072 if (pRefNext >= (pRefBuf + FREFBUFMAX))
\r
1073 fatal_error("Forward Reference buffer overflow...");
\r
1074 if (iRefNext >= FREFSMAX)
\r
1075 fatal_error("Forward Reference table overflow...");
\r
1077 /* Make a forward reference table entry */
\r
1079 strncpy(pRefNext, UString, UCBString);
\r
1080 pfrt[iRefNext].NameSz = UCBString; /* size of name */
\r
1081 pfrt[iRefNext].Ptr = pRefNext;
\r
1082 pfrt[iRefNext].Line = lineno[level]; /* for error reporting */
\r
1083 pfrt[iRefNext].Type = type; /* type of ref */
\r
1086 pfrt[iRefNext].Offs = Offset; /* Offset to correction in CS or DS */
\r
1088 /* update for next symbol */
\r
1090 pRefNext += UCBString;
\r
1095 /********************************************
\r
1096 Adds fixup table entries to be placed in
\r
1097 the run file. This includes DLL entries.
\r
1098 *********************************************/
\r
1100 void FixUp(U8 typef, S32 Offset, U16 iSymbol)
\r
1103 if (typef == CDFIXTAG)
\r
1105 else if (typef == DDFIXTAG)
\r
1107 else if (typef == DCFIXTAG)
\r
1109 else if (typef == CCFIXTAG)
\r
1113 if (iFUNext >= FIXUPSMAX)
\r
1114 fatal_error("Fixup Table overflow...");
\r
1115 pfut[iFUNext].type = typef;
\r
1116 pfut[iFUNext].Offs = Offset;
\r
1117 pfut[iFUNext].iSym = iSymbol; /* global symbol entry for DLL */
\r
1123 /********************************************
\r
1124 Adds External Reference to table.
\r
1125 This DOES NOT includes DLL Refs.
\r
1126 ETypes are the same as ForRef types
\r
1127 except there and no 8 bit externals.
\r
1128 *********************************************/
\r
1130 void ExtRef(U8 EType, U16 iSymbol)
\r
1133 if (iERefNext >= EREFSMAX)
\r
1134 fatal_error("External Reference Table overflow...");
\r
1137 ert[iERefNext].Offs = oNextData;
\r
1139 ert[iERefNext].Offs = oNextCode;
\r
1141 ert[iERefNext].iSym = iSymbol; /* global symbol entry for external */
\r
1142 ert[iERefNext].Type = EType; /* global symbol entry for external */
\r
1147 /*****************************************************
\r
1148 Reads in all of the reserved words, numbers, math
\r
1149 operators, etc. that make up one operand. They are
\r
1150 read into one of 3 2D arrays as indicated by "op".
\r
1151 Integer rgTCnt[op] is number if items. A special
\r
1152 case for jump and call instructions is tested if
\r
1153 we end up with an Unknown Symbol as and operand.
\r
1154 We Error out if we have an UNKSYM without a
\r
1156 *****************************************************/
\r
1158 S16 GetOper(S16 op)
\r
1171 rgTID[op][i] = TReg;
\r
1172 rgToken[op][i] = T;
\r
1174 case NUMBER: /* check for special case of REG*2,*4,*8 */
\r
1176 (rgToken[op][i-1] == STAR) &&
\r
1177 (rgToken[op][i-2] == REGIST)) {
\r
1178 rgVal[op][i] = TNumber;
\r
1179 rgToken[op][i] = T;
\r
1180 break; /* only break here if we find special case */
\r
1181 } /* Else fall thru to Expression */
\r
1184 case DOLLAR: /* These should all evaluate to a number!! */
\r
1189 if (Expression()) {
\r
1190 rgVal[op][i] = TNumber;
\r
1191 rgToken[op][i] = Token; /* Token instead of T (From Expr)*/
\r
1221 rgToken[op][i] = T;
\r
1231 /********************************************
\r
1232 This finds the first matching entry in rgINS
\r
1233 by first matching the instruction number,
\r
1234 then matching operands. The table is indexed
\r
1235 with an array providing the first entry for
\r
1236 the instruction. This speed things up a bit.
\r
1237 *********************************************/
\r
1239 S16 INSEntry(S16 InsNum, S16 nOpers)
\r
1243 i = rgInsLookUp[InsNum];
\r
1244 while (i <= nrgINS) {
\r
1246 /* instruction entries of the same type
\r
1247 are all kept together. This is an early out.
\r
1250 if (rgINS[i][0] != InsNum)
\r
1251 return(0); /* couldn't find a match at all... */
\r
1253 /* See if all the operators match by calling is_Comp for each.
\r
1256 if ((is_Comp(i,0)) &&
\r
1260 return(i); /* yes, they all match! */
\r
1262 i++; /* No, goto next entry */
\r
1267 /********************************************
\r
1268 EmitInst spits out the instruction bytes that
\r
1269 were encoded into variables by EncodeInst.
\r
1270 This handles output to the code segment
\r
1271 file as well as the text to the list file.
\r
1272 It updates the code segment address and
\r
1273 also adds fixup records as they are needed.
\r
1275 The instruction (up to 16 bytes) is ordered
\r
1277 Instruction Prefix 0 or 1 byte
\r
1278 Address Size Prefix 0 or 1 byte
\r
1279 Operand Prefix 0 or 1 byte
\r
1280 Segment Override 0 or 1 bytes
\r
1281 Opcode 1 or 2 bytes
\r
1282 MODR/M 0 or 1 bytes
\r
1284 Displacement 0,1,2 or 4 bytes
\r
1285 Immediate 0,1,2, or 4 bytes
\r
1286 **********************************************/
\r
1288 void EmitInst(void)
\r
1293 U16 i; /* used local to each section if needed */
\r
1298 Instruction prefix: 0 or 1 byte (Lock, Rep, etc.)
\r
1302 if (InstPfx==xLOCK) {
\r
1305 put_hexb(0x0F, lst_fh);
\r
1309 else if ((InstPfx==xREPNE) || (InstPfx==xREPNZ)) {
\r
1312 put_hexb(0xF2, lst_fh);
\r
1316 else { /* Must be REP... */
\r
1319 put_hexb(0xF3, lst_fh);
\r
1324 Column += fprintf(lst_fh, "| ");
\r
1328 Skip Address Size prefix: (67h) cause we aren't
\r
1329 doing USE16, nor do we support 16 bit addressing modes!
\r
1332 /* Operand Size prefix: 0 or 1 (66h) */
\r
1334 if (OpSizeA & fWord) {
\r
1337 put_hexb(0x66, lst_fh);
\r
1338 Column += fprintf(lst_fh, "| ");
\r
1343 /* Segment Override prefix */
\r
1345 switch (OpPrefix) {
\r
1346 case fDSp: oppfx = 0x3e; break;
\r
1347 case fESp: oppfx = 0x26; break;
\r
1348 case fSSp: oppfx = 0x36; break;
\r
1349 case fFSp: oppfx = 0x64; break;
\r
1350 case fGSp: oppfx = 0x65; break;
\r
1351 case fCSp: oppfx = 0x2e; break;
\r
1352 default: oppfx = 0;
\r
1357 put_hexb(oppfx, lst_fh);
\r
1358 Column += fprintf(lst_fh, "| ");
\r
1363 /* OpCode byte 1 (optional)
\r
1364 bOpc1 was setup in EncodeInst (either 0 or 0Fh)
\r
1370 put_hexb(bOpc1, lst_fh);
\r
1371 Column += fprintf(lst_fh, " ");
\r
1376 /* OpCode byte 2 (always sent) */
\r
1380 put_hexb(bOpc2, lst_fh);
\r
1381 Column += fprintf(lst_fh, " ");
\r
1386 /* ModR/M (optional) */
\r
1391 put_hexb(bModRM, lst_fh);
\r
1392 Column += fprintf(lst_fh, " ");
\r
1397 /* SIB (optional) */
\r
1402 put_hexb(bSIB, lst_fh);
\r
1403 Column += fprintf(lst_fh, " ");
\r
1409 Disp: 0, 1, 2 or 4
\r
1410 A Displacement is a memory reference (an offset in a segment)
\r
1411 that is encoded as part of the instruction. The value to encode
\r
1412 is placed in OpDisp when the instruction is parsed and
\r
1416 if (OpMType & fDisp32) {
\r
1420 put_hexd(OpDisp, lst_fh);
\r
1421 if ((nExtRef) || (fForRef))
\r
1422 Column += fprintf(lst_fh, "r ");
\r
1424 Column += fprintf(lst_fh, " ");
\r
1427 ExtRef(CSEGREF, nExtRef);
\r
1429 ForRef(CSEGREF, oNextCode);
\r
1431 FixUp(nFixUp, oNextCode, 0); /* Code ref to data */
\r
1435 if (OpMType & fDisp8) {
\r
1440 put_hexb(sbyte, lst_fh);
\r
1441 Column += fprintf(lst_fh, " ");
\r
1447 Immediate: 0, 1, 2 or 4
\r
1448 The type of instruction operands tell us if we must encode
\r
1449 immediate values as part of the instruction. All instructions
\r
1450 have only one immediate value except ENTER. We make a check here
\r
1451 to determine if it is this instruction.
\r
1453 imm8 = Immediate Byte in OpImm
\r
1454 imm16 = immediate 16 bit value in OpImm
\r
1455 immX = immediate value matching OpSize in OpImm
\r
1456 rel8 = immediate Byte calculated from a label
\r
1457 relW = immediate Word (16 or 32) calculated from a label
\r
1458 iSAD = immediate DWORD:WORD from Far Pointer (OpImm & OpImm2)
\r
1460 immv1 is not encoded (implied by instruction)
\r
1461 immv3 is not encoded (also implied - INT 03 - Debug)
\r
1465 if ((rgINS[iInstEntry][1] == immX) ||
\r
1466 (rgINS[iInstEntry][2] == immX) ||
\r
1467 (rgINS[iInstEntry][3] == immX))
\r
1469 if (OpSizeA & fByte)
\r
1475 put_hexb(sbyte, lst_fh);
\r
1476 Column += fprintf(lst_fh, " ");
\r
1480 else if (OpSizeA & fWord)
\r
1486 put_hexw(sword, lst_fh);
\r
1487 Column += fprintf(lst_fh, " ");
\r
1491 else { /* MUST be a DWord */
\r
1494 put_hexd(OpImm, lst_fh);
\r
1496 Column += fprintf(lst_fh, "r ");
\r
1498 Column += fprintf(lst_fh, " ");
\r
1501 ExtRef(CSEGREF, nExtRef);
\r
1503 ForRef(CSEGREF, oNextCode);
\r
1505 FixUp(nFixUp, oNextCode, 0); /* Code ref to data */
\r
1510 if ((rgINS[iInstEntry][1] == imm16) ||
\r
1511 (rgINS[iInstEntry][2] == imm16) ||
\r
1512 (rgINS[iInstEntry][3] == imm16)) {
\r
1516 put_hexw(sword, lst_fh);
\r
1517 Column += fprintf(lst_fh, " ");
\r
1521 else if ((rgINS[iInstEntry][1] == imm8) ||
\r
1522 (rgINS[iInstEntry][2] == imm8) ||
\r
1523 (rgINS[iInstEntry][3] == imm8) ||
\r
1524 (rgINS[iInstEntry][1] == ims8) ||
\r
1525 (rgINS[iInstEntry][2] == ims8) ||
\r
1526 (rgINS[iInstEntry][3] == ims8))
\r
1531 put_hexb(sbyte, lst_fh);
\r
1532 Column += fprintf(lst_fh, " ");
\r
1537 /* Special check for Enter. It is only instructon with 2 Imms!*/
\r
1539 if (rgINS[iInstEntry][0] == xENTER)
\r
1544 put_hexb(sbyte, lst_fh);
\r
1545 Column += fprintf(lst_fh, " ");
\r
1551 /* With relative values for immediates, OpImm comes in as
\r
1552 the address of the target jump or call. We must take
\r
1553 the current code offset (of the next instruction) and
\r
1554 subtract it from the target (OpImm) to get the relative
\r
1555 jump value. If it is an UNKSYM we will put the value
\r
1556 of the target into the FRT to hold it and
\r
1557 do the math on the second pass of the machine code.
\r
1560 oCode = 100 (next instruction)
\r
1562 Jump = -50 (Target-Current)
\r
1564 oCode = 100 (next instruction)
\r
1566 Jump = 50 (Target-Current)
\r
1568 Relative immediate values found in the GST as EXTERN
\r
1569 require an ERT entry so they can be fixed up when
\r
1570 the final code module is written to the run file.
\r
1572 Relative immediate values found in the GST as PUBLICS
\r
1573 can be fixed up NOW.
\r
1575 Relative immediate values NOT found are assumed local
\r
1576 and an entry is made in the FRT so they can be fixed
\r
1577 up when this code module is written to the main
\r
1581 if (rgINS[iInstEntry][1] == relW) {
\r
1582 if (nExtRef) { /* list external */
\r
1584 ExtRef(CCR32REF, nExtRef);
\r
1586 else if (fForRef) { /* list Forward Relative */
\r
1588 ForRef(CCR32REF, oNextCode);
\r
1590 else { /* Fix known ref */
\r
1591 OpImm = OpImm - (oNextCode + 4);
\r
1596 put_hexd(OpImm, lst_fh);
\r
1597 if ((!fForRef) && (!nExtRef))
\r
1598 Column += fprintf(lst_fh, " ");
\r
1600 Column += fprintf(lst_fh, "R ");
\r
1605 if (rgINS[iInstEntry][1] == rel8) {
\r
1606 if (!fForRef) { /* Fix KNOWN Relative */
\r
1607 OpImm = OpImm - (oNextCode + 1);
\r
1608 if ((OpImm > 127) || (OpImm < -127))
\r
1611 else { /* Else List Unknown */
\r
1612 ForRef(CCR8REF, oNextCode);
\r
1619 put_hexb(sbyte, lst_fh);
\r
1620 if ((!fForRef) && (!nExtRef))
\r
1621 Column += fprintf(lst_fh, " ");
\r
1623 Column += fprintf(lst_fh, "R ");
\r
1628 if (rgINS[iInstEntry][1] == iSAD) {
\r
1632 put_hexw(sword, lst_fh);
\r
1633 Column += fprintf(lst_fh, ":");
\r
1635 put_hexd(OpImm2, lst_fh);
\r
1636 Column += fprintf(lst_fh, " ");
\r
1645 /********************************************
\r
1646 This encodes the instructions into bytes
\r
1647 and calls EmitInst() to put them into the
\r
1648 current code segment. The instruction can
\r
1649 be as long as 16 bytes if all options are used.
\r
1650 The order of the bytes and their possible
\r
1651 sizes are as follows:
\r
1652 Inst Prefix: 0 or 1 (Lock, Rep, etc.)
\r
1653 Address Size prefix: 0 or 1 (67h) - We don't use this
\r
1654 Operand Size prefix: 0 or 1 (66h)
\r
1655 Segment Override: 0 or 1
\r
1659 Disp: 0, 1, 2 or 4
\r
1660 Immediate: 0, 1, 2 or 4
\r
1661 This routine follows the guidance to build
\r
1662 instructions given in the rgINS table
\r
1663 (as bit flags). It calls EmitInst() to
\r
1664 emit the code, list-file information and
\r
1665 fixups to the FUT.
\r
1666 **********************************************/
\r
1667 void EncodeInst(void)
\r
1674 U8 bOpc1; Zero if not used THESE ARE GLOBAL...
\r
1675 U8 bOpc2; Always used
\r
1678 S8 fModRM; Is bModRM set/used?
\r
1679 S8 fSIB; Is bSIB set/used?
\r
1682 fModRM = 0; /* not used by default */
\r
1686 /* SKIP the Address Size Prefix for now because we don't do 16 Bit
\r
1687 Effective addresses
\r
1692 Now we will build the instruction in (up to) 4 temporary bytes.
\r
1693 We do it in temporary byte vars so we can see if an Operand Prefix
\r
1694 and a possible address fixup record is required before we
\r
1695 actually put it into the code segment.
\r
1699 The WORD forms of string instructions require us
\r
1700 to force a WORD size. We set this in the instruction table
\r
1701 as qUW in byte [4],
\r
1704 if (rgINS[iInstEntry][4] & qUW)
\r
1707 /* Put in the first byte of Opcode from table (if required). qP0F is
\r
1708 set in rgINS[iInstEntry][4] if a 0Fh prefix is required for this inst.
\r
1709 A 0 in bObc1 indicates that this byte is NOT to be used.
\r
1712 if (rgINS[iInstEntry][4] & qP0F)
\r
1716 /* Get the Opcode from table into bOpc2 */
\r
1718 bOpc2 = rgINS[iInstEntry][5];
\r
1720 /* The flags zMR1, zMR2, zMOP, zAR1, and zAR2 all indicate that the
\r
1721 ModRM is needed. The following set of if-else statements checks these
\r
1722 flags and sets REG/OP field of MOD/RM byte if required.
\r
1723 OpSize should already be set. We also complete
\r
1724 the instruction encoding (with the exception of any immediate values)
\r
1725 if the other operand is a register.
\r
1728 if (rgINS[iInstEntry][7] & zMR1) {
\r
1729 bModRM = rgINS[iInstEntry][6];
\r
1731 if (is_Reg(rgOpType[0]))
\r
1732 EncodeRegBits(rgOpReg[0], &bModRM, 3);
\r
1733 if (is_Reg(rgOpType[1])) {
\r
1734 EncodeRegBits(rgOpReg[1], &bModRM, 0);
\r
1735 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1738 else if (rgINS[iInstEntry][7] & zMR2) {
\r
1739 bModRM = rgINS[iInstEntry][6];
\r
1741 if (is_Reg(rgOpType[1]))
\r
1742 EncodeRegBits(rgOpReg[1], &bModRM, 3);
\r
1743 if (is_Reg(rgOpType[0])) {
\r
1744 EncodeRegBits(rgOpReg[0], &bModRM, 0);
\r
1745 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1748 else if (rgINS[iInstEntry][7] & zMOP) {
\r
1749 bModRM = rgINS[iInstEntry][6];
\r
1751 if (is_Reg(rgOpType[0])) {
\r
1752 EncodeRegBits(rgOpReg[0], &bModRM, 0);
\r
1753 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1756 else if (rgINS[iInstEntry][7] & zAR1) {
\r
1758 EncodeRegBits(rgOpReg[0], &bTmp, 0);
\r
1761 else if (rgINS[iInstEntry][7] & zAR2) {
\r
1763 EncodeRegBits(rgOpReg[1], &bTmp, 0);
\r
1766 else if ((rgINS[iInstEntry][7] & zRG1) && (rgOpType[0] != mem)) {
\r
1767 bModRM = rgINS[iInstEntry][6];
\r
1769 EncodeRegBits(rgOpReg[0], &bModRM, 3);
\r
1770 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1774 /* OpSize may not be required for many instructions, but we know
\r
1775 for a fact it MUST be known for memory operands!
\r
1778 if ((rgOpType[0] == mem) ||
\r
1779 (rgOpType[1] == mem) ||
\r
1780 (rgOpType[0] == memF)) {
\r
1781 if (!(OpSizeA & (fByte|fWord|fDWord|fFWord))) {
\r
1788 If zORD, see if we have word or dword register and OR the Opcode
\r
1789 (Opc2) with 01 if so.
\r
1792 if (rgINS[iInstEntry][7] & zORD) {
\r
1793 if (OpSizeA & (fWord | fDWord))
\r
1797 /* Perform the following additonal steps if we have a memory reference
\r
1798 as determined by iMemEntry.
\r
1804 /* If SIB is needed (as determined from OpMType), get it and also
\r
1805 OR ModRM by required value from rgM32 table
\r
1808 bModRM |= rgM32[iMemEntry][2]; /* Use ModRM 'OR' value from table */
\r
1809 if (rgM32[iMemEntry][1]) { /* is there an SIB byte? */
\r
1810 bModRM &= 0x38; /* 00111000 leaves Reg bit on */
\r
1811 bModRM |= rgM32[iMemEntry][2]; /* 'OR' ModRM with table value */
\r
1812 bSIB = rgM32[iMemEntry][3];
\r
1817 /* At this point we have our Opcode, ModRM, and SIB (if required).
\r
1818 The MOD and SS bit are already filled in from the table.
\r
1819 This means we just stick the register values or bits for Disp etc
\r
1820 in the correct positions to complete it.
\r
1821 If we didn't have an SIB, we either have a single displacement,
\r
1825 if (!fSIB) { /* only a base, disp, or both */
\r
1826 if (OpMType & fBase)
\r
1827 EncodeRegBits(OpBase, &bModRM, 0);
\r
1829 bModRM |= 0x05; /* only a disp32 */
\r
1832 if (OpMType & fBase)
\r
1833 EncodeRegBits(OpBase, &bSIB, 0);
\r
1834 else bModRM |= 0x20; /* else set [--][--] bits */
\r
1835 if (OpMType & fIndx)
\r
1836 EncodeRegBits(OpIndx, &bSIB, 3);
\r
1845 /********************************************
\r
1846 When the dispatcher detects an Instruction
\r
1847 it calls this code to read in (via parse)
\r
1848 the parametrs for the instruction and to
\r
1849 put together the opcodes. First we loop thru
\r
1850 and get up to 3 operands, then we evaluate
\r
1851 them (classify by type). Next we look up
\r
1852 the instruction and find a match for the
\r
1853 operand types they have specified, and
\r
1854 finally, we encode the instruction into the
\r
1855 code segment updating the code segment offset
\r
1857 *********************************************/
\r
1858 void Instruction(void)
\r
1870 /* If the instruction is a prefix instruction, save it
\r
1871 and Parse again to get the real instruction */
\r
1873 if ((TInst==xREP) || (TInst==xREPE) || (TInst==xREPZ) ||
\r
1874 (TInst==xREPNE) || (TInst==xREPNZ) || (TInst==xLOCK)) {
\r
1877 if (i != INSTRU) {
\r
1881 } else InstPfx = 0;
\r
1883 /* RESET all global instruction variables */
\r
1885 CrntInst = TInst; /* Save the instruction */
\r
1886 nOperands = 0; /* none yet... */
\r
1890 OpMType = 0; /* char - memory type (a byte to compare to rgM32) */
\r
1891 OpSize[0] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1892 OpSize[1] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1893 OpSizeA = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1894 OpSizeTmp = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1895 OpPrefix = 0; /* For Segment register prefix flags */
\r
1896 OpDisp = 0; /* long - Displacement if fDisp8 or fDisp32 is TRUE */
\r
1897 OpBase = 0; /* int - Base register if fBase is true */
\r
1898 OpIndx = 0; /* int - Index register if fIndx is true */
\r
1899 fOpImm = 0; /* No Immediate value yet */
\r
1900 OpImm = 0; /* Default to 0 */
\r
1901 fOpImm2 = 0; /* No second Immediate value yet */
\r
1902 OpImm2 = 0; /* Default to 0 */
\r
1903 nFixUp = 0; /* Fixup type if needed, else 0 */
\r
1904 nExtRef = 0; /* GST entry if external ref was made */
\r
1905 fForRef = 0; /* No Forward Ref in crnt inst yet */
\r
1906 ExpType = 0; /* Type of symbol used in instruction */
\r
1907 ExpType0 = 0; /* Type of symbol used in instruction */
\r
1908 iExpSym = 0; /* Index into symtab for symbol if used */
\r
1909 iExpSym0 = 0; /* Index into symtab for symbol if used */
\r
1913 ExpType0 = ExpType;
\r
1914 iExpSym0 = iExpSym;
\r
1915 if ((Parse()== COMMA)) {
\r
1918 if ((Parse()== COMMA)) {
\r
1932 At this point we have the instruction operands stored in
\r
1933 tokenized form in arrays. We now call EvalOper() which evaluates
\r
1934 the operands and fills in several variables that will assist in
\r
1935 building the instruction. EvalOper() returns 1 if it was a valid
\r
1939 if (nOperands) { /* at least one */
\r
1940 if (EvalOper(0)) {
\r
1941 if (nOperands > 1) { /* a second operand */
\r
1942 if (EvalOper(1)) {
\r
1943 if (nOperands > 2) { /* a third??? - could be... */
\r
1944 if (!(EvalOper(2)))
\r
1954 if (fError) return;
\r
1957 We must check to see what the word size of the instruction is
\r
1958 by looking at register sizes if any are included in the instruction.
\r
1959 If there are memory references or immediates involved, OpSizeA
\r
1960 MUST be set properly else it's an error! When there is a symbol involved
\r
1961 such as a move to a memory variable, we check the variable size and set
\r
1962 the OpSize to the variable size. If it's still not set, the line will
\r
1963 error out when we try to build the instruction because the caller
\r
1964 should have explicitly set the size (e.g., DWORD PTR ...).
\r
1966 If a register is one of the operands in a memory transfer
\r
1967 (e.g., MOV [mem], EAX) then the move obviously defaults to the size
\r
1968 of the register (no ifs, ands, or buts).
\r
1970 If there is no reg involved, we then look at 'OpSize[i]'
\r
1971 which may have been set by the size operators (e.g., DWORD PTR).
\r
1972 If it's zero we look at iExpSym which was set if there was a single
\r
1973 symbol involved in the memory reference. If there was, then we use it.
\r
1974 If it is blank, we error out cause we don't know what size memory
\r
1975 access we are doing!
\r
1976 This is done for each operand then the two are compared. If one is
\r
1977 zero we use the other, if both have something but are different
\r
1981 /* Find the first operand size */
\r
1983 /* First, let's look to see if they forced it! */
\r
1985 if (OpSize[0] & (fByte|fWord|fDWord|fFWord))
\r
1987 { /* do nothing */ }
\r
1989 /* If they didn't force it, we'll look for the register size! */
\r
1991 else if (rgOpType[0] == r32) OpSize[0] |= fDWord;
\r
1992 else if (rgOpType[0] == r16) OpSize[0] |= fWord;
\r
1993 else if (rgOpType[0] == rSEG) OpSize[0] |= fWord;
\r
1994 else if (rgOpType[0] == r8) OpSize[0] |= fByte;
\r
1996 /* Still nothing, so let's at symbols. */
\r
1998 else if (ExpType0 == 1)
\r
1999 { /* Local symbol */
\r
2000 if (lst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;
\r
2001 else if (lst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;
\r
2002 else if (lst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;
\r
2003 else if (lst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;
\r
2005 else if (ExpType0 == 2)
\r
2006 { /* Global Symbol */
\r
2007 if (gst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;
\r
2008 else if (gst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;
\r
2009 else if (gst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;
\r
2010 else if (gst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;
\r
2012 else if (ExpType0 == 3)
\r
2013 OpSize[0] |= fDWord; /* $ defaults to DWord */
\r
2016 /* Find the second operand size. Check "forced fit" first */
\r
2018 if (OpSize[1] & (fByte|fWord|fDWord|fFWord))
\r
2019 { /* do nothing */ }
\r
2021 else if (rgOpType[1] == r32) OpSize[1] |= fDWord;
\r
2022 else if (rgOpType[1] == r16) OpSize[1] |= fWord;
\r
2023 else if (rgOpType[1] == rSEG) OpSize[1] |= fWord;
\r
2024 else if (rgOpType[1] == r8) OpSize[1] |= fByte;
\r
2026 /* No registers, so let's look to see if they forced it! */
\r
2028 /* Still nothing, so let's at symbols. */
\r
2030 else if (ExpType == 1)
\r
2031 { /* Local symbol */
\r
2032 if (lst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;
\r
2033 else if (lst[iExpSym].Type & sWORD) OpSize[1] |= fWord;
\r
2034 else if (lst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;
\r
2035 else if (lst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;
\r
2037 else if (ExpType == 2)
\r
2038 { /* Global Symbol */
\r
2039 if (gst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;
\r
2040 else if (gst[iExpSym].Type & sWORD) OpSize[1] |= fWord;
\r
2041 else if (gst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;
\r
2042 else if (gst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;
\r
2044 else if (ExpType == 3)
\r
2045 OpSize[1] |= fDWord; /* $ defaults to DWord */
\r
2047 /* Special cases for operand size matching. */
\r
2049 if (CrntInst == xOUT)
\r
2050 OpSize[0] = OpSize[1];
\r
2054 Now that have the operands, and we know the TYPE of data (fByte etc.)
\r
2055 we call INSEntry to find the matching
\r
2056 entry in the array that describes each instruction. If we don't
\r
2057 find one that matches we error out telling them they have bad
\r
2061 /* find first matching entry in rgINS */
\r
2063 iInstEntry = INSEntry(CrntInst, nOperands);
\r
2065 if (!iInstEntry) {
\r
2070 /* Now we make sure that we have set all operand sizes
\r
2071 and check for special cases as defined in rgINS.
\r
2074 if (rgINS[iInstEntry][7] & zSIZ)
\r
2075 OpSize[1] = OpSize[0];
\r
2078 OpSize[1] = OpSize[0];
\r
2081 OpSize[0] = OpSize[1];
\r
2083 /* Give them an error if operand sizes don't match */
\r
2085 if (nOperands > 1)
\r
2086 if (OpSize[0] != OpSize[1]) {
\r
2091 OpSizeA = OpSize[0]; /* Set primary operand size */
\r
2093 /* If either the first or second operand was memory, we have to find
\r
2094 which entry in rgM32 it matches before we can encode it. If none
\r
2095 matches it is an invalid memory operand. If neither is a mem operand
\r
2096 we set iMemEntry to zero. There is the special case of moffs type
\r
2097 which is a short form of displacmement when moving data to and from thew
\r
2098 accumulator (e.g., MOV EAX, VAR1). We check for this and skip the
\r
2099 mem check if this is the instruction type we are on.
\r
2102 if ((rgINS[iInstEntry][1] == moff) || (rgINS[iInstEntry][2] == moff))
\r
2104 else if ((rgOpType[0]==mem) ||
\r
2105 (rgOpType[1]==mem) ||
\r
2106 (rgOpType[0]==memF))
\r
2109 for (i=1; i<nrgM32; i++) {
\r
2110 if (OpMType == rgM32[i][0]) break;
\r
2113 /* if i is off the end of the array we
\r
2114 didn't find an entry that matched
\r
2121 else iMemEntry = i;
\r
2123 else iMemEntry = 0;
\r
2126 At this point we should have all information we need to actually
\r
2127 encode the instruction (unless it's a forward ref). So we call EncodeInst.
\r
2136 /********************************************
\r
2137 Create Storage in current segment. At this
\r
2138 point we should see a storage statement as
\r
2139 the current token followed by a number (or
\r
2140 string if DB). If string (DB) we insert
\r
2141 single byte values (one per char) into the
\r
2143 *********************************************/
\r
2144 void Storage(void)
\r
2146 S32 TSave, NSave, nDUP;
\r
2148 S8 fColon, fExpectColon, fComma, fDUP;
\r
2152 nDUP = 1; /* default duplicate value */
\r
2157 if (!fMoreStorage) { /* is it a continuation of previous line? */
\r
2158 switch(Token) { /* parse returns Token */
\r
2175 /* Now we loop thru looking for strings and numbers taking into account
\r
2176 the special case of DF which should be DWORD:WORD, and OFFSET
\r
2177 which will be a DWORD.
\r
2181 if (fMoreStorage) {
\r
2190 if (StoreSize==1) {
\r
2191 for(j=0; j<CBString; j++) {
\r
2193 put_hexb(TString[j], lst_fh);
\r
2195 Column += fprintf(lst_fh, " ");
\r
2196 if (Column > 51) {
\r
2197 fprintf(lst_fh, "\r\n ");
\r
2201 OutByte(TString[j]);
\r
2210 if (StoreSize != 4) {
\r
2214 /* fall thru to evaluate & store value */
\r
2216 case DOLLAR: /* These should all evaluate to a number. */
\r
2217 case OPENRND: /* If it's SYMOFF, we do a fixup or Forward Ref */
\r
2223 if (!(Expression())) /* 0 means error was emmited. */
\r
2226 symtype = 0; /* default to no symbol type */
\r
2227 nExtRef = 0; /* default to no external ref */
\r
2229 if ((Token==SYMOFF) || (Token==NUMOFF))
\r
2231 if (ExpType == 1) /* Local */
\r
2232 symtype = lst[iExpSym].Type;
\r
2233 else if (ExpType == 2) { /* global */
\r
2234 symtype = gst[iExpSym].Type;
\r
2235 if (gst[iExpSym].Type & tEXTRN)
\r
2236 nExtRef = iExpSym;
\r
2243 if (Parse() == rDUP)
\r
2248 if (Token == OPENRND) {
\r
2249 if (!(Expression())) /* 0 means error was emitted.*/
\r
2254 /* TNumber now has (VALUE) from DUP */
\r
2266 fColon=0; /* reset it */
\r
2270 put_hexw(sword, lst_fh);
\r
2271 Column += fprintf(lst_fh, " ");
\r
2279 put_hexd(TNumber, lst_fh);
\r
2280 Column += fprintf(lst_fh, " ");
\r
2282 OutDWord(TNumber);
\r
2285 else if (StoreSize==4) {
\r
2289 if ((Token == SYMOFF) || (Token == NUMOFF))
\r
2290 Column += fprintf(lst_fh, "%08lX * (%08lXr)",nDUP,TNumber);
\r
2292 Column += fprintf(lst_fh, "%08lX * (%08lX)",nDUP,TNumber);
\r
2296 if ((Token==SYMOFF) || (Token==NUMOFF))
\r
2298 if (fDataSeg) { /* Data Seg */
\r
2300 ExtRef(DSEGREF, iExpSym);
\r
2301 else if (!symtype)
\r
2302 ForRef(DSEGREF, oNextData);
\r
2303 else if (symtype & CLABEL)
\r
2304 FixUp(DCFIXTAG, oNextData, 0);
\r
2305 else if (symtype & DLABEL)
\r
2306 FixUp(DDFIXTAG, oNextData, 0);
\r
2308 else { /* Code Seg */
\r
2310 ExtRef(CSEGREF, iExpSym);
\r
2312 ForRef(CSEGREF, oNextCode);
\r
2313 else if (symtype & CLABEL)
\r
2314 FixUp(CCFIXTAG, oNextCode, 0);
\r
2315 else if (symtype & DLABEL)
\r
2316 FixUp(CDFIXTAG, oNextCode, 0);
\r
2319 OutDWord(TNumber);
\r
2325 if ((Token == SYMOFF) || (Token == NUMOFF))
\r
2326 Column += fprintf(lst_fh, " %08lXr", TNumber);
\r
2328 Column += fprintf(lst_fh, " %08lX", TNumber);
\r
2331 /* Fixup & Forref here! */
\r
2332 if ((Token==SYMOFF) || (Token==NUMOFF))
\r
2337 ExtRef(DSEGREF, iExpSym);
\r
2338 else if (!symtype)
\r
2339 ForRef(DSEGREF, oNextData);
\r
2340 else if (symtype & CLABEL)
\r
2341 FixUp(DCFIXTAG, oNextData, 0);
\r
2342 else if (symtype & DLABEL)
\r
2343 FixUp(DDFIXTAG, oNextData, 0);
\r
2348 ExtRef(CSEGREF, iExpSym);
\r
2349 else if (!symtype)
\r
2350 ForRef(CSEGREF, oNextCode);
\r
2351 else if (symtype & CLABEL)
\r
2352 FixUp(CCFIXTAG, oNextCode, 0);
\r
2353 else if (symtype & DLABEL)
\r
2354 FixUp(CDFIXTAG, oNextCode, 0);
\r
2357 OutDWord(TNumber);
\r
2360 else if (StoreSize==2) {
\r
2363 Column += fprintf(lst_fh, "%08lX * (%04lX) ",nDUP,TNumber);
\r
2369 Column += fprintf(lst_fh, "%04lX ", TNumber);
\r
2376 Column += fprintf(lst_fh, "%08lX * (%02lX) ",nDUP,TNumber);
\r
2382 Column += fprintf(lst_fh, "%02lX ", TNumber);
\r
2387 case COMMA: /* Just eat the comma */
\r
2396 if ((StoreSize == 6) && (fExpectColon)) {
\r
2406 if (fComma) fMoreStorage = 1;
\r
2417 /********************************************
\r
2418 Add new GLOBAL symbol to table (TString).
\r
2419 Then parse again to hand off to
\r
2420 proper function. This stores all
\r
2421 Symbols UPPER case.
\r
2422 *********************************************/
\r
2426 S8 fColon, fStorage;
\r
2428 if ((pSymNext + CBString) >= (pSymBuf + SYMBUFMAX))
\r
2429 fatal_error("Symbol buffer overflow...");
\r
2430 if (iSymNext >= SYMSMAX)
\r
2431 fatal_error("Symbol table overflow...");
\r
2433 strncpy(pSymNext, TString, CBString);
\r
2434 gst[iSymNext].Size = CBString;
\r
2435 gst[iSymNext].Type = 0; /* initialize type */
\r
2436 gst[iSymNext].Ptr = pSymNext;
\r
2437 gst[iSymNext].Line = lineno[level];
\r
2438 gst[iSymNext].Offs = 0;
\r
2440 /* All declarations that reach NewSymbol are either at
\r
2441 level 0 or defined as PUBLIC or EXTERN. */
\r
2444 gst[iSymNext].Type |= tEXTRN;
\r
2446 gst[iSymNext].Type |= tPUBLIC;
\r
2448 if (fFarLabel) gst[iSymNext].Type |= tFAR;
\r
2452 gst[iSymNext].Offs = oNextData;
\r
2453 gst[iSymNext].Type |= DLABEL;
\r
2457 gst[iSymNext].Offs = oNextCode;
\r
2458 gst[iSymNext].Type |= CLABEL;
\r
2461 /* update for next symbol */
\r
2462 pSymNext += CBString;
\r
2466 /* Now, parse again and hand off. We have just added a symbol
\r
2467 so expect to see an EQU, COLON or Storage statement.
\r
2468 If we don't see one of these it's an error unless it's an extern.
\r
2469 If we see a COLON we parse again and expect an instruction or EOL!
\r
2485 switch(i) { /* parse returns Token */
\r
2498 gst[iSymNext-1].Type |= sBYTE; /* type */
\r
2502 gst[iSymNext-1].Type |= sWORD; /* type */
\r
2506 gst[iSymNext-1].Type |= sDWORD; /* type */
\r
2510 if ((!fDataSeg) && (!fColon)) {
\r
2514 gst[iSymNext-1].Type |= sFWORD; /* type */
\r
2525 if ((fDataSeg) && (!fExtern))
\r
2533 if (gst[iSymNext-1].Type & tEXTRN)
\r
2540 /********************************************
\r
2541 This changes an EXTRN entry in the gst to
\r
2542 a PUBLIC once we find it. This checks to
\r
2543 make sure the extern declaration was the
\r
2544 same type as this public.
\r
2545 *********************************************/
\r
2547 void MakePublic(void)
\r
2550 S8 fColon, fStorage;
\r
2552 if (gst[TSymnum].Type & tPUBLIC) {
\r
2557 if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {
\r
2562 if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {
\r
2567 gst[TSymnum].Type |= tPUBLIC; /* Turn ON Public */
\r
2568 gst[TSymnum].Type &= ~tEXTRN; /* Turn off EXTERN */
\r
2571 gst[TSymnum].Offs = oNextData;
\r
2573 gst[TSymnum].Offs = oNextCode;
\r
2575 /* Now, parse again and hand off. We have just added a symbol
\r
2576 so expect to see an EQU, COLON or Storage statement.
\r
2577 If we don't see one of these it's an error unless it's an extern.
\r
2578 If we see a COLON we parse again and expect an instruction or EOL!
\r
2594 switch(i) { /* parse returns Token */
\r
2607 gst[TSymnum].Type |= sBYTE; /* type */
\r
2611 gst[TSymnum].Type |= sWORD; /* type */
\r
2615 gst[TSymnum].Type |= sDWORD; /* type */
\r
2619 if ((!fDataSeg) && (!fColon)) {
\r
2623 gst[TSymnum].Type |= sFWORD; /* type */
\r
2642 /********************************************
\r
2643 This checks to ensure multiple externs are
\r
2644 the same type when we run across them, and
\r
2645 also that an extern is the same type if
\r
2646 the public is already declared.
\r
2647 *********************************************/
\r
2648 void CheckExtern(void)
\r
2650 /* Check to make sure new extern and symbol are same type */
\r
2652 if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {
\r
2657 if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {
\r
2664 /********************************************
\r
2665 Add new LOCAL symbol to table (TString).
\r
2666 Then parse again to hand off to
\r
2667 proper function. This stores all
\r
2668 Symbols UPPER case.
\r
2669 *********************************************/
\r
2670 void NewLSymbol(void)
\r
2673 S8 fColon, fStorage;
\r
2675 if ((pLSymNext + CBString) >= (pLSymBuf + LSYMBUFMAX))
\r
2676 fatal_error("Local symbol buffer overflow...");
\r
2677 if (iLSymNext >= LSYMSMAX)
\r
2678 fatal_error("Local symbol table overflow...");
\r
2680 strncpy(pLSymNext, TString, CBString);
\r
2681 lst[iLSymNext].Size = CBString;
\r
2682 lst[iLSymNext].Type = 0; /* initialize type */
\r
2683 lst[iLSymNext].Ptr = pLSymNext;
\r
2684 lst[iLSymNext].Line = lineno[level];
\r
2687 lst[iLSymNext].Offs = oNextData;
\r
2688 lst[iLSymNext].Type |= DLABEL;
\r
2691 lst[iLSymNext].Offs = oNextCode;
\r
2692 lst[iLSymNext].Type |= CLABEL;
\r
2695 /* update for next symbol */
\r
2696 pLSymNext += CBString;
\r
2699 /* Now, parse again and hand off. We have just added a symbol
\r
2700 so expect to see an EQU, COLON or Storage statement.
\r
2701 If we don't see one of these it's an error!
\r
2702 If we see a COLON we parse again and expect an instruction or EOL!
\r
2718 switch(i) { /* parse returns Token */
\r
2731 lst[iLSymNext-1].Type |= sBYTE; /* type */
\r
2735 lst[iLSymNext-1].Type |= sWORD; /* type */
\r
2739 lst[iLSymNext-1].Type |= sDWORD; /* type */
\r
2743 if ((!fDataSeg) && (!fColon)) {
\r
2747 lst[iLSymNext-1].Type |= sFWORD; /* type */
\r
2760 if (lst[iLSymNext-1].Type & tEXTRN)
\r
2768 /*****************************************
\r
2769 After we transition from level 1 back to
\r
2770 level 0 we go back to the point in the
\r
2771 code or data file where we began writing this
\r
2772 section and resolve all forward code
\r
2773 and local data references. These will be
\r
2774 referenced in the module we just finished.
\r
2775 ******************************************/
\r
2777 void Resolve(void)
\r
2786 while (i < iRefNext) /* While there are forward references */
\r
2788 if (pfrt[i].Type == DSEGREF) /* Ref is in DSEG */
\r
2790 fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);
\r
2791 fread(&Partial, 4, 1, ds_fh);
\r
2792 fseek(ds_fh, (pfrt[i].Offs - DataOffset) , SEEK_SET);
\r
2793 AddFix = pfrt[i].Offs - DataOffset;
\r
2795 else /* Ref is in CSEG */
\r
2797 fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);
\r
2799 if (pfrt[i].Type == CSEGREF) /* IT'S ABSOLUTE! */
\r
2801 fread(&Partial, 4, 1, cs_fh);
\r
2802 fseek(cs_fh, (pfrt[i].Offs - CodeOffset) , SEEK_SET);
\r
2803 AddFix = pfrt[i].Offs - CodeOffset;
\r
2806 /* We are where we should write the reference
\r
2807 now we need to find it in the local symbol table
\r
2808 and calculate the proper offset. The calculation
\r
2809 is different for Relative and absolute references.
\r
2810 For Relative, we subtract the address where the correction
\r
2811 is going to be stored from the offset of reference.
\r
2812 For Absolute, we read what was already at the address
\r
2813 and add it to the offset of the referenced item.
\r
2814 Both of these are also adjusted for the Virtual segment offset.
\r
2817 /* Look in the Local Symbol table first! */
\r
2819 isym = findLsymbol(pfrt[i].Ptr, pfrt[i].NameSz);
\r
2821 if (isym) /* we found it! */
\r
2823 if (pfrt[i].Type == CCR8REF) /* 8 bit relative */
\r
2825 Relative = lst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);
\r
2826 OutByteCS(Relative);
\r
2828 else if (pfrt[i].Type == CCR32REF) /* 32 bit relative */
\r
2830 /* Fixed to make relatives ok in Virtual Segs */
\r
2832 Relative = (lst[isym].Offs - CodeOffset) -
\r
2833 (pfrt[i].Offs - CodeOffset + 4);
\r
2834 OutDWordCS(Relative);
\r
2836 else if (pfrt[i].Type == CSEGREF) /* 32 bit absolute */
\r
2838 Partial += lst[isym].Offs;
\r
2840 if (lst[isym].Type & CLABEL)
\r
2841 FixUp(CCFIXTAG, AddFix, 0);
\r
2842 else if (lst[isym].Type & DLABEL)
\r
2843 FixUp(CDFIXTAG, AddFix, 0);
\r
2845 OutDWordCS(Partial);
\r
2847 else if (pfrt[i].Type == DSEGREF)
\r
2849 Partial += lst[isym].Offs; /* RAB was + DataOffset */
\r
2851 if (lst[isym].Type & CLABEL)
\r
2852 FixUp(DCFIXTAG, AddFix, 0);
\r
2853 else if (lst[isym].Type & DLABEL)
\r
2854 FixUp(DDFIXTAG, AddFix, 0);
\r
2856 OutDWordDS(Partial);
\r
2859 else /* Look in Global table */
\r
2862 isym = findGsymbol(pfrt[i].Ptr, pfrt[i].NameSz);
\r
2866 { /* we found it! */
\r
2869 if (pfrt[i].Type == CCR8REF) { /* 8 bit relative */
\r
2870 Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);
\r
2871 OutByteCS(Relative);
\r
2873 else if (pfrt[i].Type == CCR32REF) { /* 32 bit relative */
\r
2874 Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 4);
\r
2875 OutDWordCS(Relative);
\r
2877 else if (pfrt[i].Type == CSEGREF) {
\r
2878 Partial += gst[isym].Offs;
\r
2880 if (gst[isym].Type & CLABEL)
\r
2881 FixUp(CCFIXTAG, AddFix, 0);
\r
2882 else if (gst[isym].Type & DLABEL)
\r
2883 FixUp(CDFIXTAG, AddFix, 0);
\r
2885 OutDWordCS(Partial);
\r
2887 else if (pfrt[i].Type == DSEGREF)
\r
2889 Partial += gst[isym].Offs;
\r
2891 if (gst[isym].Type & CLABEL)
\r
2892 FixUp(DCFIXTAG, AddFix, 0);
\r
2893 else if (gst[isym].Type & DLABEL)
\r
2894 FixUp(DDFIXTAG, AddFix, 0);
\r
2896 OutDWordDS(Partial);
\r
2900 prev_error("Unresolved symbol in current module", pfrt[i].Line);
\r
2905 fseek(cs_fh, 0L, SEEK_END); /* Get back to the end! */
\r
2906 fseek(ds_fh, 0L, SEEK_END);
\r
2910 /*****************************************
\r
2911 When we have processed all the source
\r
2912 we call this to resolve ALL externals.
\r
2913 ******************************************/
\r
2915 void ResolveExt(void)
\r
2928 while (i < iERefNext) { /* While there are unresolved externals */
\r
2930 /* See if ref is in GST as PUBLIC */
\r
2932 isym = ert[i].iSym;
\r
2934 if (gst[isym].Type & tPUBLIC) {
\r
2936 if (ert[i].Type == DSEGREF) { /* Ref is in DSEG */
\r
2938 fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);
\r
2939 fread(&Partial, 4, 1, ds_fh);
\r
2940 fseek(ds_fh, (ert[i].Offs - DataOffset) , SEEK_SET);
\r
2941 AddFix = ert[i].Offs - DataOffset;
\r
2943 else { /* Ref is in CSEG */
\r
2945 fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);
\r
2947 if (ert[i].Type == CSEGREF) { /* and IT'S ABSOLUTE! */
\r
2948 fread(&Partial, 4, 1, cs_fh);
\r
2949 fseek(cs_fh, (ert[i].Offs - CodeOffset) , SEEK_SET);
\r
2950 AddFix = ert[i].Offs - CodeOffset;
\r
2953 /* We are where we should write the reference
\r
2954 now we need to use the index in the external ref
\r
2955 table to see if it has been defined PUBLIC.
\r
2956 If so, we resolve it, else we error out.
\r
2957 To resolve it, the calculation is different for Relative
\r
2958 and absolute references.
\r
2959 For Relative, we subtract the address where the correction
\r
2960 is going to be stored from the offset of reference.
\r
2961 For Absolute, we read what was already at the address
\r
2962 and add it to the offset of the referenced item.
\r
2963 Both of these are also adjusted for the Virtual segment offset.
\r
2966 if (ert[i].Type == CCR32REF) { /* 32 bit relative */
\r
2968 /* Fixed to make relatives ok in Virtual Segs */
\r
2970 Relative = (gst[isym].Offs - CodeOffset) -
\r
2971 (ert[i].Offs - CodeOffset + 4);
\r
2972 OutDWordCS(Relative);
\r
2974 else if (ert[i].Type == CSEGREF) {
\r
2975 Partial += gst[isym].Offs;
\r
2977 if (gst[isym].Type & DLABEL)
\r
2978 FixUp(CDFIXTAG, AddFix, 0);
\r
2979 else if (gst[isym].Type & CLABEL)
\r
2980 FixUp(CCFIXTAG, AddFix, 0);
\r
2982 OutDWordCS(Partial);
\r
2984 else if (ert[i].Type == DSEGREF) {
\r
2985 Partial += gst[isym].Offs;
\r
2987 if (gst[isym].Type & CLABEL)
\r
2988 FixUp(DCFIXTAG, AddFix, 0);
\r
2989 else if (gst[isym].Type & DLABEL)
\r
2990 FixUp(DDFIXTAG, AddFix, 0);
\r
2992 OutDWordDS(Partial);
\r
2996 strncpy(name, gst[isym].Ptr, gst[isym].Size);
\r
2997 name[gst[isym].Size] = '\0';
\r
2998 fprintf(lst_fh, "Unresolved external: %s\n", name);
\r
3003 } /* while more Erefs */
\r
3005 fseek(cs_fh, 0L, SEEK_END); /* Get back to the end! */
\r
3006 fseek(ds_fh, 0L, SEEK_END);
\r
3010 /*****************************************
\r
3011 If there were no errors, and all looks
\r
3012 well, we build the run file. This consists
\r
3013 of building the required tags in order
\r
3014 and writing them to the file with the
\r
3016 ******************************************/
\r
3018 void BuildRunFile(void)
\r
3024 tag.id = IDTAG; /* File type */
\r
3026 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3027 fwrite(&filetype, 1, 1, run_fh); /* Write the filetype */
\r
3029 /* Version tag goes here */
\r
3030 /* DatTime tag goes here */
\r
3031 /* Comment tag(s) goes here */
\r
3033 tag.id = SEGTAG; /* Initial Segment Sizes */
\r
3035 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3036 fwrite(&StackTotal, 4, 1, run_fh); /* Write the Stacktotal */
\r
3037 sdata = oNextCode - CodeOffset; /* Size of CS.TMP */
\r
3038 fwrite(&sdata, 4, 1, run_fh); /* Write the Code Size */
\r
3039 sdata = oNextData - DataOffset; /* Size of DS.TMP */
\r
3040 fwrite(&sdata, 4, 1, run_fh); /* Write the Data Size */
\r
3042 printf("Stack Size: %ld\r\n", StackTotal);
\r
3043 printf("Code Size: %ld\r\n", oNextCode - CodeOffset);
\r
3044 printf("Data Size: %ld\r\n", oNextData - DataOffset);
\r
3046 tag.id = DOFFTAG; /* Assumed Data Offset */
\r
3048 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3049 fwrite(&DataOffset, 4, 1, run_fh); /* Write the data */
\r
3051 tag.id = COFFTAG; /* Assumed Code Offset */
\r
3053 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3054 fwrite(&CodeOffset, 4, 1, run_fh); /* Write the data */
\r
3056 tag.id = STRTTAG; /* Starting Address */
\r
3058 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3059 fwrite(&StartAddr, 4, 1, run_fh); /* Write the data */
\r
3061 tag.id = CODETAG; /* Code Segment */
\r
3062 tag.len = oNextCode - CodeOffset; /* Size of CS.TMP */
\r
3063 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3065 fseek(cs_fh, 0L , SEEK_SET);
\r
3067 while (sdata > 0) {
\r
3068 i = fread(line_buf0, 1, 200, cs_fh);
\r
3071 fwrite(line_buf0, 1, i, run_fh);
\r
3074 tag.id = DATATAG; /* Data Segment */
\r
3075 tag.len = oNextData - DataOffset; /* Size of DS.TMP */
\r
3076 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3078 fseek(ds_fh, 0L , SEEK_SET);
\r
3080 while (sdata > 0) {
\r
3081 i = fread(line_buf0, 1, 200, ds_fh);
\r
3084 fwrite(line_buf0, 1, i, run_fh);
\r
3088 tag.id = CDFIXTAG; /* CSEG Data Fixups */
\r
3089 tag.len = nCDFix * 4; /* Count * 4 of Fixups */
\r
3090 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3092 while (i--) { /* Write CD fixups */
\r
3093 if (pfut[i].type == CDFIXTAG)
\r
3094 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3099 tag.id = CCFIXTAG; /* CSEG Code Fixups */
\r
3100 tag.len = nCCFix * 4; /* Count * 4 of Fixups */
\r
3101 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3103 while (i--) { /* Write CC fixups */
\r
3104 if (pfut[i].type == CCFIXTAG)
\r
3105 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3110 tag.id = DDFIXTAG; /* DESG Data Fixups */
\r
3111 tag.len = nDDFix * 4; /* Count * 4 of Fixups */
\r
3112 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3114 while (i--) { /* Write DD fixups */
\r
3115 if (pfut[i].type == DDFIXTAG)
\r
3116 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3121 tag.id = DCFIXTAG; /* DESG Code Fixups */
\r
3122 tag.len = nDCFix * 4; /* Count * 4 of Fixups */
\r
3123 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3125 while (i--) { /* Write DC fixups */
\r
3126 if (pfut[i].type == DCFIXTAG)
\r
3127 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3131 /* DLL Address fixup tag goes here */
\r
3132 /* DLL Public tag goes here */
\r
3134 tag.id = ENDTAG; /* End Tag */
\r
3135 tag.len = 4; /* Size of CS.TMP */
\r
3136 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3138 fwrite(&sdata, 4, 1, run_fh); /* Write the tag record */
\r
3143 /*****************************************
\r
3144 Reads a whole line into line buffer.
\r
3145 ******************************************/
\r
3147 S16 readline(void)
\r
3152 if (!(fgets(line_ptr = line_buf0, 100, src_fh[level]))) {
\r
3154 if (level) { /* we are in a nested include */
\r
3155 fclose(src_fh[level]);
\r
3157 if (level==0) { /* back up one level */
\r
3159 /* Processes forward references from this module */
\r
3167 /* Clear local symbol, forward refs, & macro tables */
\r
3169 iLSymNext = 1; /* 1st entry. */
\r
3170 pLSymNext = pLSymBuf; /* beginning of buffer */
\r
3172 iRefNext = 0; /* 1st entry. */
\r
3173 pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */
\r
3175 iMacNext = 0; /* 1st entry */
\r
3176 pMacNext = pMacBuf; /* Begining of buffer */
\r
3181 fprintf(lst_fh, "\r\n ");
\r
3182 fprintf(lst_fh, "CONTINUING-> %s, Level:%d\r\n", srcname[level],level);
\r
3183 fprintf(lst_fh, "\r\n");
\r
3185 if (lineno[level]) --lineno[level];
\r
3188 else { /* We are at the end of the ATF file */
\r
3190 /* Processes forward references from Level 0 */
\r
3199 line_error(12); /* Starting address not found */
\r
3204 printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);
\r
3206 if (fListA | fListE)
\r
3207 fprintf(lst_fh,"%d Errors\r\n%d Warnings\r\n",
\r
3208 error_count,warn_count);
\r
3210 if (!error_count) {
\r
3211 printf("Building Run file...\n");
\r
3213 printf("Done.\n");
\r
3220 fclose(src_fh[level]);
\r
3231 while (isspace(*pLine)) pLine++;
\r
3232 while ((*pLine) && (*pLine != ';') && (*pLine != 0x0A))
\r
3233 list_buf[i++] = *pLine++;
\r
3234 while ((i) && (list_buf[i-1] == ' ')) --i; /* eat trailing spaces */
\r
3235 list_buf[i] = 0; /* null terminate */
\r
3236 if (i) fLineIn = 1;
\r
3244 /********************************************
\r
3245 Dispatch calls Parse from the beginning
\r
3246 of a line and calls the proper routine
\r
3247 based on what it finds (from Parse()).
\r
3248 Dispatch calls readline to get a new line
\r
3249 after each of the line-specific modules
\r
3250 gets done with it's line or lines(s).
\r
3251 *********************************************/
\r
3253 void Dispatch(void)
\r
3261 if (fContinue) { /* We have just returned from an include */
\r
3262 fContinue = 0; /* and must reread the line without processing */
\r
3266 if (lineno[level] == 1) {
\r
3268 fprintf(lst_fh, "\r\n ");
\r
3269 fprintf(lst_fh, "PROCESSING-> %s, Level:%d\r\n", srcname[level], level);
\r
3273 Column = fprintf(lst_fh, "%06d ", lineno[level]);
\r
3286 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3305 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3309 else if (j==UNKSYM)
\r
3317 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3321 else if (j==UNKSYM)
\r
3328 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3342 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3352 if ((fLineIn) && (fListA)) {
\r
3353 while (Column < 53) Column += fprintf(lst_fh, " ");
\r
3354 fprintf(lst_fh, "%s", list_buf);
\r
3357 fprintf(lst_fh, "\r\n");
\r
3362 /*********************
\r
3364 **********************/
\r
3366 void main(S16 argc, S8 *argv[])
\r
3371 lst_fh = stdout; /* default the list file */
\r
3373 for(i=1; i < argc; ++i) {
\r
3375 if (*ptr == '/') {
\r
3378 case 'L' : /* List file ON */
\r
3382 case 'S' : /* Dump Symbols */
\r
3386 case 'E' : /* List file ON for errors/warns only */
\r
3390 case 'D' : /* Process as DLL */
\r
3394 case 'V' : /* Process as Devive Driver */
\r
3399 fatal_error("Invalid option\n");
\r
3405 strncpy(srcname, argv[i], 39);
\r
3406 src_fh[0] = fopen(argv[i], "r");
\r
3408 else if(!run_fh) {
\r
3409 strncpy(runname, argv[i], 39);
\r
3410 if(!(run_fh = fopen(argv[i], "wb"))) {
\r
3411 fatal_error("Can't open RUN file\n");
\r
3415 fatal_error("Too many options\n"); /* Too many parameters */
\r
3419 /* Input file not explicitly named errors out */
\r
3421 printf("Usage: ATFfile [RunFile] /L /E /D /V\r\n");
\r
3422 printf("/L = Complete List file generated\r\n");
\r
3423 printf("/S = Include SYMBOLS (only in complete list file)\r\n");
\r
3424 printf("/E = List file for Errors/warnings only\r\n");
\r
3425 printf("/D = Process as Dynamic link library\r\n");
\r
3426 printf("/V = Process as deVice driver\r\n");
\r
3427 fatal_error("Can't open Template file\n"); /* Can't open ATF file */
\r
3430 /* Output file not explicitly named defaults to Source.RUN */
\r
3432 if(!run_fh) { /* default asm name to SourceName.run */
\r
3433 strncpy(runname, srcname, 40);
\r
3435 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
3437 if (filetype == 2) {
\r
3442 else if (filetype == 3) {
\r
3454 if(!(run_fh = fopen(runname, "wb"))) {
\r
3455 fatal_error("Can't open OUTPUT file\n"); /* Can't open RUN file */
\r
3459 /* List file named Source.LIS for fListA and fListE only. */
\r
3461 if (fListA | fListE) {
\r
3462 strncpy(lstname, srcname, 40);
\r
3464 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
3470 if(!(lst_fh = fopen(lstname, "w")))
\r
3471 fatal_error("Can't open list file (source.LIS)\n"); /* Can't open List file */
\r
3476 printf("DASM-DOS Ver 1.6 (c) R.A. Burgess 1992,1993,1994\r\n\r\n");
\r
3478 if (fListA | fListE)
\r
3479 fprintf(lst_fh, "DASM-DOS Ver 1.6 (c) R.A. Burgess 1992, 1993, 1994\r\n\r\n");
\r
3483 "LINE OFFSET ACTION/DATA/CODE SOURCE\r\n\r\n");
\r
3485 pLSymBuf = malloc(LSYMBUFMAX);
\r
3487 fatal_error("Can't Allocate buffer 1\n");
\r
3489 pSymBuf = malloc(SYMBUFMAX);
\r
3491 fatal_error("Can't Allocate buffer 2\n");
\r
3493 pMacBuf = malloc(MACBUFMAX);
\r
3495 fatal_error("Can't Allocate buffer 3\n");
\r
3497 pRefBuf = malloc(FREFBUFMAX);
\r
3499 fatal_error("Can't Allocate buffer 4\n");
\r
3501 pfrt = malloc(FREFTABMAX);
\r
3503 fatal_error("Can't Allocate buffer 5\n");
\r
3505 pfut = malloc(FIXUPBUFMAX);
\r
3507 fatal_error("Can't Allocate buffer 6\n");
\r
3509 pSymNext = pSymBuf; /* Allocate memory - Was SymBuf */
\r
3510 pLSymNext = pLSymBuf; /* Allocate memory - Was LSymBuf */
\r
3511 pMacNext = pMacBuf; /* Allocate memory - Was MacBuf */
\r
3512 pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */
\r
3515 pNextAddr = &oNextData; /* default to DataSeg */
\r
3517 if(!(cs_fh = fopen(csname, "wb+")))
\r
3518 fatal_error("Can't open CS temp file\n");
\r
3520 if(!(ds_fh = fopen(dsname, "wb+")))
\r
3521 fatal_error("Can't open DS temp file\n");
\r
3523 /* We now build a dynamic instruction lookup table which indexes
\r
3524 the first entry of an instruction in the opcode array rgINS.
\r
3525 This is done dynamically because we are still optimizing.
\r
3528 /* i is the instruction we are indexing */
\r
3529 /* j is the position in rgINS */
\r
3531 for (i=1; i<ninst+1; i++) {
\r
3532 for (j=1; j<nrgINS; j++) {
\r
3533 if (rgINS[j][0] == i) {
\r
3534 rgInsLookUp[i] = j;
\r