2 * Assembler for MMURTL (MMURTL Version).
\r
4 * Copyright 1991,1992,1993,1994,1995 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
15 Version 1.7M 1/1/95 - V1.6 ported to MMURTL. Changed memory allocation
\r
16 use AllocPage and also created internal buffers
\r
17 instead of using tmp files. Also use an internal
\r
18 read buffer of 4K to make better use of Readbytes().
\r
19 OutWord, OutDWord, and OutByte had to be renamed
\r
20 so they would not conflict with MMURTL publics of
\r
25 #define U32 unsigned long
\r
27 #define U16 unsigned int
\r
29 #define U8 unsigned char
\r
39 #include "runfile.h"
\r
40 #include "\OSSource\MMemory.h"
\r
41 #include "\OSSource\MFiles.h"
\r
46 U32 level = 0; /* current include level */
\r
47 U32 lineno[LEVELS]; /* line number being parsed */
\r
48 U8 fContinue = 0; /* True if just returned from include */
\r
50 char srcname[LEVELS][40]; /* also active include filenames */
\r
54 /* File handles for all files */
\r
56 FILE *src_fh[5] = {0,0,0,0,0}; /* Current source file */
\r
57 FILE *run_fh = 0; /* Current .RUN, .DLL, or .DDR (output) */
\r
59 FILE *lst_fh = 0; /* List file */
\r
60 FILE *sym_fh = 0; /* Symbol file for debugger */
\r
62 #define STMPBUFS 512000
\r
64 U8 *pcsbuf, *pdsbuf; /* half meg allocated buffers for code & data */
\r
65 U32 ics, ids; /* current index into tmp code & data buffers */
\r
67 U8 filetype = 1; /* 1 = RUN, 2 = DLL, 3 = DDR */
\r
69 U8 fListA = 0; /* True if detailed list file */
\r
70 U8 fListE = 0; /* True if Error only list file */
\r
71 U8 fSymDump = 0; /* True if we add symbols to the list file */
\r
72 U8 Column = 0; /* where are we on the LIST line */
\r
73 U32 error_count = 0;
\r
76 /* Max input line is 132, but 200 allows plenty for macro subs */
\r
77 S8 line_buf0[200]; /* Two buffers are swapped during macro substitution */
\r
79 S8 *line_ptr; /* pointer to next char on line */
\r
81 S8 list_buf[200]; /* Used to hold line string for list file */
\r
82 S8 fLineIn =0; /* TRUE is list_buf has something to list */
\r
84 S8 TString[133]; /* all parsed tokens are placed here in text form */
\r
85 S32 CBString; /* size of parsed token */
\r
86 S32 TSymnum; /* Symbol table entry number, else 0 */
\r
87 U32 TNumber; /* value of numeric token */
\r
88 S32 TInst; /* Instruction number, else 0 */
\r
89 S32 TReg; /* Register number, else 0 */
\r
90 S32 Token; /* Token type (also returned from parse) */
\r
91 S8 fPutBack = 0; /* TRUE (non=zero) if last token was not used */
\r
93 S8 LTString[133]; /* Duplicates of Token storage for ReturnToken(); */
\r
101 S8 UString[31]; /* Place to save unknown labels for Forward Reference */
\r
102 S32 UCBString; /* Size of Unknown label */
\r
104 /* The two Symbol tables have 5 entries; Type, Size, Pointer to Name,
\r
105 Segment Offset, and Line.
\r
106 As each symbol is found, it's identifed by type, and the name
\r
107 is moved to the packed symbol buffer. A pointer is added to the
\r
108 table to point to the name in the buffer, while it's size, type,
\r
109 segment offset, and line number are added to the table.
\r
110 Macro names are also stored in the symbol table, but offset entry
\r
111 for a macro indicates it's offset in the Macro buffer.
\r
114 /* Variables for symbol tables */
\r
116 /* Global Symbol Table */
\r
118 #define SYMSMAX 700
\r
119 #define SYMBUFMAX 16384 /* Avg of 10 byte per name, 700 Max */
\r
122 U32 Type; /* Token (e.g, CLabel) */
\r
123 U32 Line; /* Line symbol was declared on */
\r
124 U32 Size; /* Size of symbol name */
\r
125 S8 *Ptr; /* Pointer to name in packed buffer */
\r
126 U32 Offs; /* Offset in segment */
\r
129 struct symtab gst[SYMSMAX]; /* storage for the GST */
\r
131 /* S8 SymBuf[SYMBUFMAX]; */ /* Where names are stored. Will be Alloced */
\r
132 S8 *pSymBuf; /* ptr to allocated buffer */
\r
134 S8 *pSymNext; /* ptr to next new entry in symbol buffer */
\r
135 S32 iSymNext = 1; /* index to next new symbol table entry. */
\r
136 /* Starts at 1 - zero it reserved because */
\r
137 /* Parse returns 0 for EOL */
\r
143 /*********** Local Symbol Table *************/
\r
145 /* This is cleared after each include file from level 1 is closed */
\r
146 /* Clearing means we reset *pLSymNext to begining of buffer */
\r
147 /* and reset iLSymNext to 1. This "hides" local symbols. */
\r
149 #define LSYMSMAX 1800
\r
150 #define LSYMBUFMAX 32768 /* Avg of 7 bytes per name */
\r
152 struct symtab lst[LSYMSMAX]; /* storage for the LST */
\r
154 /* S8 LSymBuf[LSYMBUFMAX]; */ /* Where names are stored.*/
\r
155 S8 *pLSymBuf; /* for allocated buffer */
\r
157 S8 *pLSymNext; /* ptr to next new entry in symbol buffer */
\r
158 S32 iLSymNext = 1; /* index to next new symbol table entry. */
\r
159 /* Starts at 1 - zero it reserved because */
\r
160 /* Parse returns 0 for EOL */
\r
162 /************* Forward Ref Table *********************************/
\r
164 Labels that are encountered as forward references are
\r
165 stored in this table. When we run across a forward, we do
\r
166 not know what segment they are refering to unless it is from
\r
167 a jump, call, or loop instruction. We will NOT know for many
\r
168 items until they are actually declared. After all the code
\r
169 and data has been processed, we go through this table
\r
170 and fix all the unknown references using the relative
\r
171 The type of forward references are:
\r
173 1) DSEG DWORD item refers to UNK item (?Seg MemRef)
\r
174 2) CSEG DWORD item refers to UNK item (?Seg MemRef)
\r
175 3) CSEG to CSEG relative 8 (Jump, Jc, or Loop)
\r
176 4) CSEG to CSEG relative 32 (Jump or Call)
\r
178 MOTE: If a calculation is made with the unknown reference, 0
\r
179 is used in the calculation. We ALWAYS ADD the value we stored
\r
180 with what is found when the reference is resolved.
\r
184 #define FREFTABMAX 32768
\r
185 #define FREFSMAX 32768/14
\r
186 #define FREFBUFMAX 16384
\r
188 /* Types of forward references. */
\r
190 #define DSEGREF 1 /* 32 bit Abs Ref in DSeg, to what is unknown! */
\r
191 #define CSEGREF 2 /* 32 bit Abs Ref in CSeg, to what is unknown! */
\r
192 #define CCR32REF 3 /* 32 bit Relative in CSeg */
\r
193 #define CCR8REF 4 /* 8 bit Relative in CSeg */
\r
196 U8 Type; /* 1, 2, 3, or 4 */
\r
197 U8 NameSz; /* Size of ref name */
\r
198 U32 Line; /* Line reference was made on (for error if not found) */
\r
199 S8 *Ptr; /* Pointer to name in packed buffer */
\r
200 S32 Offs; /* Offset in segment were it should go */
\r
203 struct forreftab *pfrt; /* pointer to allocated table */
\r
206 S8 *pRefNext; /* ptr to next new entry in symbol buffer */
\r
207 S32 iRefNext = 0; /* index to next new forward ref table entry. */
\r
209 /************ External Reference table ************/
\r
211 /* External definitions that are encountered in a module are
\r
212 first entered in the Global Symbol Table (GST) as externals
\r
213 if they haven't already been defined (public) by the module
\r
215 When a reference is made to an external, we see if the public has
\r
216 already been defined. If so, we resolve it immediately. If not,
\r
217 we make an entry in the External Reference Table (ERT). The
\r
218 entry has the following 4 pieces of information:
\r
219 - Line where reference was made.
\r
220 - Index to place holder entry in GST.
\r
221 - Segment where reference was made (boolean - TRUE for code seg).
\r
222 - Offset in that segment where the resolution will be made.
\r
223 With this information we can reslove all the external references
\r
224 before we write the code segment to the run file.
\r
227 #define EREFSMAX 400
\r
230 U8 Type; /* Type of reference so we know how to apply it */
\r
231 U32 iSym; /* Index of gst entry. Hi bit set if CSeg ref */
\r
232 U32 Offs; /* Offset in segment were ref needs 32 bit fixing */
\r
235 struct extreftab ert[FREFSMAX];
\r
237 S32 iERefNext = 0; /* index to next external ref table entry. */
\r
241 /*********** Fix Up Table *********************/
\r
243 /* This table holds 6 types of fixups along with the offset
\r
244 in the segment to be fixed up, and if applicable, an index
\r
245 to the DLL public name in the GST (which should be defined
\r
248 - Ref in CSEG to address in DSEG
\r
249 - Ref in CSEG to address in CSEG
\r
250 - Ref in DSEG to address in DSEG
\r
251 - Ref in DSEG to address in CSEG
\r
252 - CSEG DLL near 32 bit call used
\r
253 - CSEG DLL near 32 bit call defined
\r
254 - Offset of 32 bit reference to be resolved
\r
255 - Index to DLL public name in GST (if applicable)
\r
257 With this information we can supply the loader with the TAG entries
\r
258 in the RUN file needed to resolve them. Most of these entries will
\r
259 be made as we parse the code, but many will also be added after
\r
260 we fix the forward references because we won't know what segment
\r
261 the reference is made to until then.
\r
264 #define FIXUPSMAX 32768/7
\r
265 #define FIXUPBUFMAX 32768
\r
269 U8 type; /* Type of fixup C0, C1, C2, C3, C5, or C8 */
\r
270 U32 Offs; /* Offset in segment for 32 bit fixup */
\r
271 U32 iSym; /* index of DLL entry in gst, else 0 */
\r
274 struct futab *pfut; /* pointer to allocated Fix Up Table */
\r
276 S32 iFUNext = 0; /* index to next fix up table entry. */
\r
284 /********* Macro variables *******************/
\r
286 #define MACSMAX 300
\r
287 #define MACBUFMAX 4096
\r
289 S8 *rgMacPtr[MACSMAX]; /* pointer to simple macros */
\r
291 S8 *pMacNext; /* ptr to next new entry in macro buffer */
\r
292 S32 iMacNext = 0; /* index to next new symbol entry */
\r
294 /* Variables for current segment address offset tracking */
\r
296 S8 fStart = 0; /* True if they gave a start address */
\r
297 S32 StartAddr = 0; /* Filled in when .START is encountered */
\r
298 S32 oNextData = 0; /* Tracks current DSEG offset */
\r
299 S32 oNextCode = 0; /* Tracks current CSEG offset */
\r
300 S32 CodeOffset = 0; /* From Virtual Command */
\r
301 S32 DataOffset = 0; /* From Virtual Command */
\r
302 S32 *pNextAddr = 0; /* Points to current segment offset counter */
\r
303 S8 fDataSeg = 0; /* True if parsing DSEG, else parsing CSEG */
\r
304 S32 StackTotal = 0; /* Total Stack Specified in Code segs */
\r
306 /******************************************************************
\r
307 Variables for RAW operands in an instruction.
\r
308 These are used when we read in and separate each part of the
\r
309 operands so it can be evaluated.
\r
312 S32 rgToken[3][20]; /* Raw tokens in the operand (as many as 20) */
\r
313 S32 rgVal[3][20]; /* value if token is number/displacement */
\r
314 S32 rgTID[3][20]; /* Register ID if token is a register */
\r
315 S32 rgTCnt[3]; /* total count of tokens in raw operand */
\r
317 /******************************************************************
\r
318 These variables are filled in while parsing and evaluating
\r
319 instructions that have been read in.
\r
320 They have all the info needed to
\r
321 encode the instruction into the object module and
\r
322 produce FixUp Records if needed.
\r
325 /* These are used in the description of all OPERANDS for the current
\r
326 instruction we are working on.
\r
328 S32 rgOpType[3]; /* Operand type for compare to instruction */
\r
329 S32 rgOpReg[3]; /* If reg only, this which one */
\r
330 S8 OpSize[3]; /* Operand size for first two (fByte, fWord, fFar etc.) */
\r
331 S8 OpSizeA; /* Overall operand size for instruction */
\r
332 S8 OpPrefix; /* Bit set for a segment prefix (fESp etc.) */
\r
333 S32 iInstEntry; /* Which entry is it in rgINS */
\r
334 S32 CrntInst; /* instruction we are working on */
\r
335 S32 InstPfx; /* Special Insturction prefix for crnt inst */
\r
336 S32 nOperands; /* number of operands we found */
\r
337 S8 fForRef; /* Crnt inst makes a Forward Reference */
\r
339 /* The following vars are used if we have a memory reference that is
\r
340 encoded as part of the instruction.
\r
342 S8 OpMType; /* Mem type (compared to rgM32). 0 if not mem type */
\r
343 S32 OpBase; /* Base register if fBase is true */
\r
344 S32 OpIndx; /* Index register if fIndx is true */
\r
345 S32 OpDisp; /* Displacement if fDisp8 or fDisp32 is TRUE */
\r
346 S32 iMemEntry; /* If mem operand, which entry in rgM32 */
\r
348 /* The following are used if we have immediate values to be encoded as
\r
349 part of the instruction. Immediates can also be addresses such as
\r
350 those in Direct and Relative Jumps and Calls!
\r
352 S32 OpImm; /* Immediate value if fOpImm is true */
\r
353 S8 fOpImm; /* If OpImm has a value */
\r
354 S32 OpImm2; /* Second Imm value for iSAD and other multi-Imm types */
\r
355 S8 fOpImm2; /* If OpImm2 has a value */
\r
357 /* This is set for each type of fixup required after an instruction
\r
358 line. Data fixups are done directly in the code that generates
\r
359 storage in DSeg. */
\r
361 U8 nFixUp; /* Fixup number (Cx) */
\r
363 /*************************************************************************/
\r
365 /* In the final stages of building an instruction, these contain the
\r
366 fragment bytes of encoded instructions (along with flags for
\r
367 optional parts used).
\r
370 U8 bOpc1; /* Zero if not used */
\r
371 U8 bOpc2; /* Always used */
\r
372 U8 bModRM; /* ModRM byte value if used */
\r
373 U8 bSIB; /* SIB value if used */
\r
374 S8 fModRM; /* True if bModRM is used */
\r
375 S8 fSIB; /* True if bSIB is used */
\r
377 /*** These are used in the expression parser ******/
\r
379 U8 ExpType; /* 0 = Forward, 1 = Local, 2 = Global, 3 = Current Addr */
\r
381 S32 nExpSyms; /* Used by the numeric expression evaluator */
\r
382 S32 iExpSym, iExpSym0; /* if a symbol value translates to a SYMOFF,
\r
383 this holds the symbol table index. */
\r
384 S8 fOffset; /* True if derived from an Offset */
\r
386 /* Variables for Storage allocation */
\r
389 S8 fMoreStorage = 0; /* True when storage continues to next line */
\r
392 /**** Variables for building the RUN File (DLL or Device Driver) ********/
\r
394 /* Once we have the CS and DS tmp files run through to correct any external
\r
395 variables or forward labels, we build the run file. This is done
\r
396 by building the tag records, sending them followed by the proper data
\r
400 struct tagtype tag;
\r
403 /******************* END VARIABLES - BEGIN CODE ********************/
\r
405 /* ANSI prototypes for all functions are in DProtos.h */
\r
407 #include "DProtos.h"
\r
410 /***************************************************************/
\r
411 /* Write a DWord to the current segment and update the counter */
\r
412 /***************************************************************/
\r
414 void OutDWordX(unsigned long Data)
\r
416 unsigned char *pOut, b;
\r
420 for (i=0; i<4; i++) {
\r
422 pdsbuf[ids++] = b; /* fputc(b , ds_fh); */
\r
427 for (i=0; i<4; i++) {
\r
429 pcsbuf[ics++] = b; /* fputc(b , cs_fh); */
\r
435 /******************************************************************/
\r
436 /* Write a DWord to the code segment and DO NOT update counter */
\r
437 /******************************************************************/
\r
439 void OutDWordCS(unsigned long Data)
\r
441 unsigned char *pOut, b;
\r
444 for (i=0; i<4; i++) {
\r
446 pcsbuf[ics++] = b; /* fputc(b , cs_fh); */
\r
450 /******************************************************************/
\r
451 /* Read n bytes from the code segment */
\r
452 /******************************************************************/
\r
454 void readCS(U8 *pDataRet, long cbData)
\r
457 *pDataRet++ = pcsbuf[ics++];
\r
461 /******************************************************************/
\r
462 /* Write n bytes to the code segment and DO NOT update counter */
\r
463 /******************************************************************/
\r
465 void writeCS(U8 *pData, long cbData)
\r
468 pcsbuf[ics++] = *pData++;
\r
472 /****************************************************************
\r
473 Set index into code buffer
\r
474 *****************************************************************/
\r
476 void seekCS(long offset)
\r
482 /******************************************************************/
\r
483 /* Write a DWord to the current segment and DO NOT update counter */
\r
484 /******************************************************************/
\r
486 void OutDWordDS(unsigned long Data)
\r
488 unsigned char *pOut, b;
\r
491 for (i=0; i<4; i++) {
\r
493 pdsbuf[ids++] = b; /* fputc(b , ds_fh); */
\r
497 /******************************************************************/
\r
498 /* Read n bytes from the code segment */
\r
499 /******************************************************************/
\r
501 void readDS(U8 *pDataRet, long cbData)
\r
504 *pDataRet++ = pdsbuf[ids++];
\r
507 /******************************************************************/
\r
508 /* Write n bytes to the data segment and DO NOT update counter */
\r
509 /******************************************************************/
\r
511 void writeDS(U8 *pData, long cbData)
\r
514 pdsbuf[ids++] = *pData++;
\r
517 /****************************************************************
\r
518 Set index into data buffer
\r
519 *****************************************************************/
\r
521 void seekDS(long offset)
\r
526 /**************************************************************/
\r
527 /* Write a Word to the current segment and update the counter */
\r
528 /**************************************************************/
\r
530 void OutWordX(unsigned long Data)
\r
532 unsigned char *pOut, b;
\r
537 pdsbuf[ids++] = b; /* fputc(b , ds_fh); */
\r
539 pdsbuf[ids++] = b; /* fputc(b , ds_fh); */
\r
543 pcsbuf[ics++] = b; /* fputc(b , cs_fh); */
\r
545 pcsbuf[ics++] = b; /* fputc(b , cs_fh); */
\r
550 /**************************************************************/
\r
551 /* Write a BYTE to the current segment and update the counter */
\r
552 /**************************************************************/
\r
554 void OutByteX(unsigned char Data)
\r
557 pdsbuf[ids++] = Data; /* fputc(Data , ds_fh); */
\r
561 pcsbuf[ics++] = Data; /* fputc(b , cs_fh); */
\r
566 /*****************************************************************/
\r
567 /* Write a BYTE to the current segment and DO NOT update counter */
\r
568 /*****************************************************************/
\r
570 void OutByteCS(unsigned long Data)
\r
574 pcsbuf[ics++] = b; /* fputc(b , cs_fh); */
\r
577 /* All the "grunt work" functions are in dasmq.c */
\r
581 /*********************************************
\r
582 This searches the Reference table for the name
\r
583 described by pb, cb. It only compares items that
\r
584 are the same length (cb == TRefSize[x]).
\r
585 It returns the number or 0 if not found.
\r
586 **********************************************/
\r
588 S32 findref(S8 *pb, S32 cb) /* pointer to, and size of string */
\r
593 strncpy(name, pb, cb); /* move name local */
\r
594 name[cb] = 0; /* null terminate */
\r
597 while (i>0) { /* backwards through forward ref table */
\r
599 /* Only compare if same size */
\r
600 if (pfrt[i].NameSz == cb) {
\r
601 if (strncmp(name, pfrt[i].Ptr, cb) == 0) return(i);
\r
608 /*****************************************************
\r
609 Evaluates only single token operands and sets up
\r
610 globals so EvalOper can finish the job.
\r
611 The actual value or register is left in
\r
612 rgToken[op][0], and the type is placed
\r
613 in rgTempl[op][0] for a memory operand.
\r
614 *****************************************************/
\r
615 S32 EvalOper1(S32 op)
\r
620 /* Set up symtype up front in case it's needed */
\r
622 if (ExpType == 1) /* Local */
\r
623 symtype = lst[iExpSym].Type;
\r
624 else if (ExpType == 2) { /* global */
\r
625 if (gst[iExpSym].Type & tEXTRN)
\r
627 symtype = gst[iExpSym].Type;
\r
631 switch (rgToken[op][0]) {
\r
633 if (is_r32(rgTID[op][0])) rgOpType[op] = r32;
\r
634 else if (is_r16(rgTID[op][0])) rgOpType[op] = r16;
\r
635 else if (is_r8(rgTID[op][0])) rgOpType[op] = r8;
\r
636 else if (is_rCRG(rgTID[op][0])) rgOpType[op] = rCRG;
\r
637 else if (is_rDRG(rgTID[op][0])) rgOpType[op] = rDRG;
\r
638 else if (is_rTRG(rgTID[op][0])) rgOpType[op] = rTRG;
\r
639 else if (is_rSEG(rgTID[op][0])) rgOpType[op] = rSEG;
\r
640 rgOpReg[op] = rgTID[op][0];
\r
643 if ((rgVal[op][0] >= -128) && (rgVal[op][0] <= 127))
\r
644 rgOpType[op] = val8;
\r
645 else if ((rgVal[op][0] >= -32768) && (rgVal[op][0] <= 32767))
\r
646 rgOpType[op] = val16;
\r
647 else rgOpType[op] = val32;
\r
649 OpImm = rgVal[op][0];
\r
653 OpImm2 = rgVal[op][0];
\r
657 case NUMOFF: /* OFFSET var name. IMMEDIATE VALUE. */
\r
658 OpSize[op] = fDWord;
\r
659 rgOpType[op] = val32;
\r
660 OpImm = rgVal[op][0];
\r
662 if (symtype & CLABEL)
\r
664 else if (symtype & DLABEL)
\r
669 case SYMOFF: /* Check for ALL jump, call & Loop instructions */
\r
671 if (ExpType == 1) /* Local */
\r
672 symtype = lst[iExpSym].Type;
\r
673 else if (ExpType == 2) { /* global */
\r
674 if (gst[iExpSym].Type & tEXTRN)
\r
676 symtype = gst[iExpSym].Type;
\r
678 else /* Unknown - Forward */
\r
681 if (((CrntInst >= xJA) &&
\r
682 (CrntInst <= xJZ)) ||
\r
683 (CrntInst == xCALL)) {
\r
685 if (OpSize[op] & fShort)
\r
686 rgOpType[op] = rel8;
\r
688 rgOpType[op] = relW;
\r
689 OpImm = rgVal[op][0];
\r
693 else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ)) {
\r
694 rgOpType[op] = rel8;
\r
695 OpImm = rgVal[op][0];
\r
699 rgOpType[op] = mem;
\r
700 OpMType |= fDisp32;
\r
701 OpDisp = rgVal[op][0];
\r
702 if (symtype & CLABEL)
\r
704 else if (symtype & DLABEL)
\r
715 /* print_Oper(op); Testing only... */
\r
720 /*********** EvalOper *******************************
\r
721 Evaluates the array of reserved words, registers,
\r
722 numbers, etc. that should make up an operand.
\r
723 For single token operands it's easy! BUT for memory
\r
724 operands it gets a little more complicated.
\r
725 For memory operands we look for key sequences of
\r
726 tokens that make up the "effective address" as
\r
727 described in the Intel documentation, then see if
\r
728 we have all the pieces to make one (EA).
\r
729 This returns 1 if we can classify the operand and
\r
730 there were no errors. The type of operand we find
\r
731 (e.g., r8, r16, r32, val8, val16, val32, mem,
\r
732 relW, etc.) is placed in rgOpType[op].
\r
733 This calls EvalOper1() to handle single token
\r
734 oprerands and evaluates multiple token operands
\r
735 internally. The reason we break single token operands
\r
736 out in a separate call is for speed and clarity
\r
738 Special handling is required for for JMP, Jcond,
\r
739 and CALL instructions because they may be using
\r
740 a forward reference not yet defined. This is the
\r
741 only case where such a reference is allowed.
\r
742 *****************************************************/
\r
744 S32 EvalOper(S32 op)
\r
747 S8 fDone, fOpenSQ, fError;
\r
750 These are the Raw operands:
\r
751 S32 rgToken[3][20]; Raw tokens in the operand
\r
752 S32 rgVal[3][20]; value if token is number/displacement
\r
753 S32 rgTID[3][20]; Register ID if token is a register
\r
754 S32 rgTCnt[3]; total count of tokens in raw operand
\r
756 This is what is produced:
\r
759 rgOpType[op] = 0; /* int - Operand type for compare to instruction */
\r
760 rgOpReg[op] = 0; /* If reg only, this which one */
\r
762 i = 0; /* index into raw tokens */
\r
763 fError = 0; /* set true for invalid operand error */
\r
764 fDone = 0; /* Set when no more tokens are expected in operand */
\r
765 fOpenSQ = 0; /* keep track of [] */
\r
767 /* flags for segment instruction prefix - NONE unless otherwise set */
\r
768 /* If it's a single token operand, take the fast, easy way out! */
\r
770 if (rgTCnt[op] == 1) {
\r
771 return (EvalOper1(op));
\r
774 else { /* multiple tokens in operand */
\r
776 /* with more than 1 token it is usually a memory reference
\r
777 but not always. We will default to mem and change those we
\r
778 find that aren't. */
\r
780 rgOpType[op] = mem;
\r
782 /* Segment prefix? If so, set flag and eat 2 tokens */
\r
784 if ((rgToken[op][0]==REGIST) && (is_rSEG(rgTID[op][0]))) {
\r
785 if (rgToken[op][1] == COLON) {
\r
786 switch (rgToken[op][0]) {
\r
787 case rDS: OpPrefix |= fDSp; break;
\r
788 case rES: OpPrefix |= fESp; break;
\r
789 case rSS: OpPrefix |= fSSp; break;
\r
790 case rFS: OpPrefix |= fFSp; break;
\r
791 case rGS: OpPrefix |= fGSp; break;
\r
792 case rCS: OpPrefix |= fCSp; break;
\r
795 i += 2; /* skip rSEG and colon */
\r
803 /* Loop through the raw tokens looking for Base Reg, Index Reg,
\r
804 Scale value, or displacement and setting varaibles as needed.
\r
807 while ((i < rgTCnt[op]) &&
\r
810 switch (rgToken[op][i]) {
\r
813 if (is_r32(rgTID[op][i])) { /* check for Indx & Base Reg */
\r
814 if (rgToken[op][i+1] == STAR) { /* Index w/Scale */
\r
815 if (!(OpMType & fIndx)) { /* still OK */
\r
817 OpIndx = rgTID[op][i];
\r
818 if (rgToken[op][i+2] == NUMBER) {
\r
819 switch (rgVal[op][i+2]) {
\r
820 case 2: OpMType |= fScale2; break;
\r
821 case 4: OpMType |= fScale4; break;
\r
822 case 8: OpMType |= fScale8; break;
\r
837 i+=3; /* get past *NUMBER */
\r
839 /* Must be base, unless fBase true, then try Index */
\r
841 if (!(OpMType & fBase)) { /* Base for sure */
\r
843 OpBase = rgTID[op][i];
\r
846 else { /* try Index */
\r
847 if (!(OpMType & fIndx)) { /* It's free, use it */
\r
849 OpIndx = rgTID[op][i];
\r
855 else { /* must be 32 bit general purpose register */
\r
862 case SYMOFF: /* One symbol was used by itself or in an expression */
\r
863 if (ExpType == 1) /* Local */
\r
864 symtype = lst[iExpSym].Type;
\r
865 else if (ExpType == 2) { /* global */
\r
866 if (gst[iExpSym].Type & tEXTRN)
\r
868 symtype = gst[iExpSym].Type;
\r
870 else /* Unknown - Forward */
\r
873 if (OpMType & (fDisp32|fDisp8)) { /* Already a disp! */
\r
878 /* Check for conditional jumps. */
\r
880 else if ((CrntInst >= xJA) &&
\r
881 (CrntInst <= xJZ) &&
\r
882 (CrntInst != xJMP) &&
\r
885 if (OpSize[op] & fShort)
\r
886 rgOpType[op] = rel8;
\r
887 else rgOpType[op] = relW;
\r
889 OpImm2 = rgVal[op][i];
\r
893 OpImm = rgVal[op][i];
\r
900 /* Check for JMP */
\r
902 else if (CrntInst == xJMP) /* && (!(fOpenSQ))) */
\r
904 if ((OpSize[op] & fFar) || (symtype & tFAR)) {
\r
905 rgOpType[op] = iSAD;
\r
907 OpImm2 = rgVal[op][i];
\r
911 OpImm = rgVal[op][i];
\r
915 else if (OpSize[op] & fShort) {
\r
916 rgOpType[op] = rel8;
\r
917 OpImm = rgVal[op][i];
\r
922 else if (OpSize[op] & fFWord) {
\r
923 rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */
\r
924 OpMType |= fDisp32;
\r
925 OpDisp = rgVal[op][i];
\r
926 if (symtype & CLABEL)
\r
928 else if (symtype & DLABEL)
\r
934 rgOpType[op] = relW;
\r
935 OpImm = rgVal[op][i];
\r
942 /* Check for CALL */
\r
944 else if ((CrntInst == xCALL) && (!(fOpenSQ)))
\r
946 if ((OpSize[op] & fFar) || (symtype & tFAR)) {
\r
947 rgOpType[op] = iSAD;
\r
949 OpImm2 = rgVal[op][i];
\r
953 OpImm = rgVal[op][i];
\r
957 else if (OpSize[op] & fFWord) {
\r
958 rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */
\r
959 OpMType |= fDisp32;
\r
960 OpDisp = rgVal[op][i];
\r
961 if (symtype & CLABEL)
\r
963 else if (symtype & DLABEL)
\r
968 else { /* Relative call */
\r
969 rgOpType[op] = relW;
\r
975 /* Check for SGDT SIDT */
\r
977 else if ((CrntInst == xSGDT) || (CrntInst == xSIDT))
\r
979 if (OpSize[op] & fFWord) {
\r
980 rgOpType[op] = memF; /* memF = 32 disp which has 16:32 */
\r
981 OpMType |= fDisp32;
\r
982 OpDisp = rgVal[op][i];
\r
983 if (symtype & CLABEL)
\r
985 else if (symtype & DLABEL)
\r
992 /* Check for Loop */
\r
994 else if ((CrntInst >= xLOOP) && (CrntInst <= xLOOPZ))
\r
996 rgOpType[op] = rel8;
\r
997 OpImm = rgVal[op][0];
\r
1003 OpDisp = rgVal[op][i];
\r
1004 OpMType |= fDisp32;
\r
1005 if (symtype & CLABEL)
\r
1006 nFixUp = CCFIXTAG;
\r
1007 else if (symtype & DLABEL)
\r
1008 nFixUp = CDFIXTAG;
\r
1015 case NUMBER: /* can be 8 or 32 bit disp, or hard address */
\r
1016 OpDisp = rgVal[op][i];
\r
1017 if ((rgVal[op][i] >= -128) && (rgVal[op][i] <= 127))
\r
1018 OpMType |= fDisp8;
\r
1020 OpMType |= fDisp32;
\r
1040 case COLON: /* for far addresses */
\r
1047 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1048 OpSize[op] |= fByte;
\r
1057 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1058 OpSize[op] |= fWord;
\r
1067 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1068 OpSize[op] |= fDWord;
\r
1077 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1078 OpSize[op] |= fFWord;
\r
1087 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1088 OpSize[op] |= fNear;
\r
1097 if ((!OpSize[op]) && (rgToken[op][i+1] == rPTR)) {
\r
1098 OpSize[op] |= fFar;
\r
1107 if (!OpSize[op]) {
\r
1108 OpSize[op] |= fShort;
\r
1118 fprintf(lst_fh, " %d ", rgToken[op][i]); /* TESTING */
\r
1125 if (fError) return(0);
\r
1126 if ((fDone) && (i< rgTCnt[op])) {
\r
1135 /********************************************
\r
1136 Adds ALL forward reference to the Ref table.
\r
1137 This holds references to all foward addresses
\r
1138 (unknown) in the current module.
\r
1139 This stores all Refs UPPER case.
\r
1140 *********************************************/
\r
1141 void ForRef(U8 type, S32 Offset)
\r
1145 if (pRefNext >= (pRefBuf + FREFBUFMAX))
\r
1146 fatal_error("Forward Reference buffer overflow...");
\r
1147 if (iRefNext >= FREFSMAX)
\r
1148 fatal_error("Forward Reference table overflow...");
\r
1150 /* Make a forward reference table entry */
\r
1152 strncpy(pRefNext, UString, UCBString);
\r
1153 pfrt[iRefNext].NameSz = UCBString; /* size of name */
\r
1154 pfrt[iRefNext].Ptr = pRefNext;
\r
1155 pfrt[iRefNext].Line = lineno[level]; /* for error reporting */
\r
1156 pfrt[iRefNext].Type = type; /* type of ref */
\r
1159 pfrt[iRefNext].Offs = Offset; /* Offset to correction in CS or DS */
\r
1161 /* update for next symbol */
\r
1163 pRefNext += UCBString;
\r
1168 /********************************************
\r
1169 Adds fixup table entries to be placed in
\r
1170 the run file. This includes DLL entries.
\r
1171 *********************************************/
\r
1173 void FixUp(U8 typef, S32 Offset, S32 iSymbol)
\r
1176 if (typef == CDFIXTAG)
\r
1178 else if (typef == DDFIXTAG)
\r
1180 else if (typef == DCFIXTAG)
\r
1182 else if (typef == CCFIXTAG)
\r
1186 if (iFUNext >= FIXUPSMAX)
\r
1187 fatal_error("Fixup Table overflow...");
\r
1188 pfut[iFUNext].type = typef;
\r
1189 pfut[iFUNext].Offs = Offset;
\r
1190 pfut[iFUNext].iSym = iSymbol; /* global symbol entry for DLL */
\r
1196 /********************************************
\r
1197 Adds External Reference to table.
\r
1198 This DOES NOT includes DLL Refs.
\r
1199 ETypes are the same as ForRef types
\r
1200 except there and no 8 bit externals.
\r
1201 *********************************************/
\r
1203 void ExtRef(U8 EType, S32 iSymbol)
\r
1206 if (iERefNext >= EREFSMAX)
\r
1207 fatal_error("External Reference Table overflow...");
\r
1210 ert[iERefNext].Offs = oNextData;
\r
1212 ert[iERefNext].Offs = oNextCode;
\r
1214 ert[iERefNext].iSym = iSymbol; /* global symbol entry for external */
\r
1215 ert[iERefNext].Type = EType; /* global symbol entry for external */
\r
1220 /*****************************************************
\r
1221 Reads in all of the reserved words, numbers, math
\r
1222 operators, etc. that make up one operand. They are
\r
1223 read into one of 3 2D arrays as indicated by "op".
\r
1224 Integer rgTCnt[op] is number if items. A special
\r
1225 case for jump and call instructions is tested if
\r
1226 we end up with an Unknown Symbol as and operand.
\r
1227 We Error out if we have an UNKSYM without a
\r
1229 *****************************************************/
\r
1231 S32 GetOper(S32 op)
\r
1244 rgTID[op][i] = TReg;
\r
1245 rgToken[op][i] = T;
\r
1247 case NUMBER: /* check for special case of REG*2,*4,*8 */
\r
1249 (rgToken[op][i-1] == STAR) &&
\r
1250 (rgToken[op][i-2] == REGIST)) {
\r
1251 rgVal[op][i] = TNumber;
\r
1252 rgToken[op][i] = T;
\r
1253 break; /* only break here if we find special case */
\r
1254 } /* Else fall thru to Expression */
\r
1257 case DOLLAR: /* These should all evaluate to a number!! */
\r
1262 if (Expression()) {
\r
1263 rgVal[op][i] = TNumber;
\r
1264 rgToken[op][i] = Token; /* Token instead of T (From Expr)*/
\r
1294 rgToken[op][i] = T;
\r
1304 /********************************************
\r
1305 This finds the first matching entry in rgINS
\r
1306 by first matching the instruction number,
\r
1307 then matching operands. The table is indexed
\r
1308 with an array providing the first entry for
\r
1309 the instruction. This speed things up a bit.
\r
1310 *********************************************/
\r
1312 S32 INSEntry(S32 InsNum, S32 nOpers)
\r
1316 i = rgInsLookUp[InsNum];
\r
1317 while (i <= nrgINS) {
\r
1319 /* instruction entries of the same type
\r
1320 are all kept together. This is an early out.
\r
1323 if (rgINS[i][0] != InsNum)
\r
1324 return(0); /* couldn't find a match at all... */
\r
1326 /* See if all the operators match by calling is_Comp for each.
\r
1329 if ((is_Comp(i,0)) &&
\r
1333 return(i); /* yes, they all match! */
\r
1335 i++; /* No, goto next entry */
\r
1340 /********************************************
\r
1341 EmitInst spits out the instruction bytes that
\r
1342 were encoded into variables by EncodeInst.
\r
1343 This handles output to the code segment
\r
1344 file as well as the text to the list file.
\r
1345 It updates the code segment address and
\r
1346 also adds fixup records as they are needed.
\r
1348 The instruction (up to 16 bytes) is ordered
\r
1350 Instruction Prefix 0 or 1 byte
\r
1351 Address Size Prefix 0 or 1 byte
\r
1352 Operand Prefix 0 or 1 byte
\r
1353 Segment Override 0 or 1 bytes
\r
1354 Opcode 1 or 2 bytes
\r
1355 MODR/M 0 or 1 bytes
\r
1357 Displacement 0,1,2 or 4 bytes
\r
1358 Immediate 0,1,2, or 4 bytes
\r
1359 **********************************************/
\r
1361 void EmitInst(void)
\r
1366 U32 i; /* used local to each section if needed */
\r
1371 Instruction prefix: 0 or 1 byte (Lock, Rep, etc.)
\r
1375 if (InstPfx==xLOCK) {
\r
1378 put_hexb(0x0F, lst_fh);
\r
1382 else if ((InstPfx==xREPNE) || (InstPfx==xREPNZ)) {
\r
1385 put_hexb(0xF2, lst_fh);
\r
1389 else { /* Must be REP... */
\r
1392 put_hexb(0xF3, lst_fh);
\r
1397 Column += fprintf(lst_fh, "| ");
\r
1401 Skip Address Size prefix: (67h) cause we aren't
\r
1402 doing USE16, nor do we support 16 bit addressing modes!
\r
1405 /* Operand Size prefix: 0 or 1 (66h) */
\r
1407 if (OpSizeA & fWord) {
\r
1410 put_hexb(0x66, lst_fh);
\r
1411 Column += fprintf(lst_fh, "| ");
\r
1416 /* Segment Override prefix */
\r
1418 switch (OpPrefix) {
\r
1419 case fDSp: oppfx = 0x3e; break;
\r
1420 case fESp: oppfx = 0x26; break;
\r
1421 case fSSp: oppfx = 0x36; break;
\r
1422 case fFSp: oppfx = 0x64; break;
\r
1423 case fGSp: oppfx = 0x65; break;
\r
1424 case fCSp: oppfx = 0x2e; break;
\r
1425 default: oppfx = 0;
\r
1430 put_hexb(oppfx, lst_fh);
\r
1431 Column += fprintf(lst_fh, "| ");
\r
1436 /* OpCode byte 1 (optional)
\r
1437 bOpc1 was setup in EncodeInst (either 0 or 0Fh)
\r
1443 put_hexb(bOpc1, lst_fh);
\r
1444 Column += fprintf(lst_fh, " ");
\r
1449 /* OpCode byte 2 (always sent) */
\r
1453 put_hexb(bOpc2, lst_fh);
\r
1454 Column += fprintf(lst_fh, " ");
\r
1459 /* ModR/M (optional) */
\r
1464 put_hexb(bModRM, lst_fh);
\r
1465 Column += fprintf(lst_fh, " ");
\r
1470 /* SIB (optional) */
\r
1475 put_hexb(bSIB, lst_fh);
\r
1476 Column += fprintf(lst_fh, " ");
\r
1482 Disp: 0, 1, 2 or 4
\r
1483 A Displacement is a memory reference (an offset in a segment)
\r
1484 that is encoded as part of the instruction. The value to encode
\r
1485 is placed in OpDisp when the instruction is parsed and
\r
1489 if (OpMType & fDisp32) {
\r
1493 put_hexd(OpDisp, lst_fh);
\r
1494 if ((nExtRef) || (fForRef))
\r
1495 Column += fprintf(lst_fh, "r ");
\r
1497 Column += fprintf(lst_fh, " ");
\r
1500 ExtRef(CSEGREF, nExtRef);
\r
1502 ForRef(CSEGREF, oNextCode);
\r
1504 FixUp(nFixUp, oNextCode, 0); /* Code ref to data */
\r
1505 OutDWordX(OpDisp);
\r
1508 if (OpMType & fDisp8) {
\r
1513 put_hexb(sbyte, lst_fh);
\r
1514 Column += fprintf(lst_fh, " ");
\r
1520 Immediate: 0, 1, 2 or 4
\r
1521 The type of instruction operands tell us if we must encode
\r
1522 immediate values as part of the instruction. All instructions
\r
1523 have only one immediate value except ENTER. We make a check here
\r
1524 to determine if it is this instruction.
\r
1526 imm8 = Immediate Byte in OpImm
\r
1527 imm16 = immediate 16 bit value in OpImm
\r
1528 immX = immediate value matching OpSize in OpImm
\r
1529 rel8 = immediate Byte calculated from a label
\r
1530 relW = immediate Word (16 or 32) calculated from a label
\r
1531 iSAD = immediate DWORD:WORD from Far Pointer (OpImm & OpImm2)
\r
1533 immv1 is not encoded (implied by instruction)
\r
1534 immv3 is not encoded (also implied - INT 03 - Debug)
\r
1538 if ((rgINS[iInstEntry][1] == immX) ||
\r
1539 (rgINS[iInstEntry][2] == immX) ||
\r
1540 (rgINS[iInstEntry][3] == immX))
\r
1542 if (OpSizeA & fByte)
\r
1548 put_hexb(sbyte, lst_fh);
\r
1549 Column += fprintf(lst_fh, " ");
\r
1553 else if (OpSizeA & fWord)
\r
1559 put_hexw(sword, lst_fh);
\r
1560 Column += fprintf(lst_fh, " ");
\r
1564 else { /* MUST be a DWord */
\r
1567 put_hexd(OpImm, lst_fh);
\r
1569 Column += fprintf(lst_fh, "r ");
\r
1571 Column += fprintf(lst_fh, " ");
\r
1574 ExtRef(CSEGREF, nExtRef);
\r
1576 ForRef(CSEGREF, oNextCode);
\r
1578 FixUp(nFixUp, oNextCode, 0); /* Code ref to data */
\r
1583 if ((rgINS[iInstEntry][1] == imm16) ||
\r
1584 (rgINS[iInstEntry][2] == imm16) ||
\r
1585 (rgINS[iInstEntry][3] == imm16)) {
\r
1589 put_hexw(sword, lst_fh);
\r
1590 Column += fprintf(lst_fh, " ");
\r
1594 else if ((rgINS[iInstEntry][1] == imm8) ||
\r
1595 (rgINS[iInstEntry][2] == imm8) ||
\r
1596 (rgINS[iInstEntry][3] == imm8) ||
\r
1597 (rgINS[iInstEntry][1] == ims8) ||
\r
1598 (rgINS[iInstEntry][2] == ims8) ||
\r
1599 (rgINS[iInstEntry][3] == ims8))
\r
1604 put_hexb(sbyte, lst_fh);
\r
1605 Column += fprintf(lst_fh, " ");
\r
1610 /* Special check for Enter. It is only instructon with 2 Imms!*/
\r
1612 if (rgINS[iInstEntry][0] == xENTER)
\r
1617 put_hexb(sbyte, lst_fh);
\r
1618 Column += fprintf(lst_fh, " ");
\r
1624 /* With relative values for immediates, OpImm comes in as
\r
1625 the address of the target jump or call. We must take
\r
1626 the current code offset (of the next instruction) and
\r
1627 subtract it from the target (OpImm) to get the relative
\r
1628 jump value. If it is an UNKSYM we will put the value
\r
1629 of the target into the FRT to hold it and
\r
1630 do the math on the second pass of the machine code.
\r
1633 oCode = 100 (next instruction)
\r
1635 Jump = -50 (Target-Current)
\r
1637 oCode = 100 (next instruction)
\r
1639 Jump = 50 (Target-Current)
\r
1641 Relative immediate values found in the GST as EXTERN
\r
1642 require an ERT entry so they can be fixed up when
\r
1643 the final code module is written to the run file.
\r
1645 Relative immediate values found in the GST as PUBLICS
\r
1646 can be fixed up NOW.
\r
1648 Relative immediate values NOT found are assumed local
\r
1649 and an entry is made in the FRT so they can be fixed
\r
1650 up when this code module is written to the main
\r
1654 if (rgINS[iInstEntry][1] == relW) {
\r
1655 if (nExtRef) { /* list external */
\r
1657 ExtRef(CCR32REF, nExtRef);
\r
1659 else if (fForRef) { /* list Forward Relative */
\r
1661 ForRef(CCR32REF, oNextCode);
\r
1663 else { /* Fix known ref */
\r
1664 OpImm = OpImm - (oNextCode + 4);
\r
1669 put_hexd(OpImm, lst_fh);
\r
1670 if ((!fForRef) && (!nExtRef))
\r
1671 Column += fprintf(lst_fh, " ");
\r
1673 Column += fprintf(lst_fh, "R ");
\r
1678 if (rgINS[iInstEntry][1] == rel8) {
\r
1679 if (!fForRef) { /* Fix KNOWN Relative */
\r
1680 OpImm = OpImm - (oNextCode + 1);
\r
1681 if ((OpImm > 127) || (OpImm < -127))
\r
1684 else { /* Else List Unknown */
\r
1685 ForRef(CCR8REF, oNextCode);
\r
1692 put_hexb(sbyte, lst_fh);
\r
1693 if ((!fForRef) && (!nExtRef))
\r
1694 Column += fprintf(lst_fh, " ");
\r
1696 Column += fprintf(lst_fh, "R ");
\r
1701 if (rgINS[iInstEntry][1] == iSAD) {
\r
1705 put_hexw(sword, lst_fh);
\r
1706 Column += fprintf(lst_fh, ":");
\r
1708 put_hexd(OpImm2, lst_fh);
\r
1709 Column += fprintf(lst_fh, " ");
\r
1712 OutDWordX(OpImm2);
\r
1718 /********************************************
\r
1719 This encodes the instructions into bytes
\r
1720 and calls EmitInst() to put them into the
\r
1721 current code segment. The instruction can
\r
1722 be as long as 16 bytes if all options are used.
\r
1723 The order of the bytes and their possible
\r
1724 sizes are as follows:
\r
1725 Inst Prefix: 0 or 1 (Lock, Rep, etc.)
\r
1726 Address Size prefix: 0 or 1 (67h) - We don't use this
\r
1727 Operand Size prefix: 0 or 1 (66h)
\r
1728 Segment Override: 0 or 1
\r
1732 Disp: 0, 1, 2 or 4
\r
1733 Immediate: 0, 1, 2 or 4
\r
1734 This routine follows the guidance to build
\r
1735 instructions given in the rgINS table
\r
1736 (as bit flags). It calls EmitInst() to
\r
1737 emit the code, list-file information and
\r
1738 fixups to the FUT.
\r
1739 **********************************************/
\r
1740 void EncodeInst(void)
\r
1747 U8 bOpc1; Zero if not used THESE ARE GLOBAL...
\r
1748 U8 bOpc2; Always used
\r
1751 S8 fModRM; Is bModRM set/used?
\r
1752 S8 fSIB; Is bSIB set/used?
\r
1755 fModRM = 0; /* not used by default */
\r
1759 /* SKIP the Address Size Prefix for now because we don't do 16 Bit
\r
1760 Effective addresses
\r
1765 Now we will build the instruction in (up to) 4 temporary bytes.
\r
1766 We do it in temporary byte vars so we can see if an Operand Prefix
\r
1767 and a possible address fixup record is required before we
\r
1768 actually put it into the code segment.
\r
1772 The WORD forms of string instructions require us
\r
1773 to force a WORD size. We set this in the instruction table
\r
1774 as qUW in byte [4],
\r
1777 if (rgINS[iInstEntry][4] & qUW)
\r
1780 /* Put in the first byte of Opcode from table (if required). qP0F is
\r
1781 set in rgINS[iInstEntry][4] if a 0Fh prefix is required for this inst.
\r
1782 A 0 in bObc1 indicates that this byte is NOT to be used.
\r
1785 if (rgINS[iInstEntry][4] & qP0F)
\r
1789 /* Get the Opcode from table into bOpc2 */
\r
1791 bOpc2 = rgINS[iInstEntry][5];
\r
1793 /* The flags zMR1, zMR2, zMOP, zAR1, and zAR2 all indicate that the
\r
1794 ModRM is needed. The following set of if-else statements checks these
\r
1795 flags and sets REG/OP field of MOD/RM byte if required.
\r
1796 OpSize should already be set. We also complete
\r
1797 the instruction encoding (with the exception of any immediate values)
\r
1798 if the other operand is a register.
\r
1801 if (rgINS[iInstEntry][7] & zMR1) {
\r
1802 bModRM = rgINS[iInstEntry][6];
\r
1804 if (is_Reg(rgOpType[0]))
\r
1805 EncodeRegBits(rgOpReg[0], &bModRM, 3);
\r
1806 if (is_Reg(rgOpType[1])) {
\r
1807 EncodeRegBits(rgOpReg[1], &bModRM, 0);
\r
1808 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1811 else if (rgINS[iInstEntry][7] & zMR2) {
\r
1812 bModRM = rgINS[iInstEntry][6];
\r
1814 if (is_Reg(rgOpType[1]))
\r
1815 EncodeRegBits(rgOpReg[1], &bModRM, 3);
\r
1816 if (is_Reg(rgOpType[0])) {
\r
1817 EncodeRegBits(rgOpReg[0], &bModRM, 0);
\r
1818 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1821 else if (rgINS[iInstEntry][7] & zMOP) {
\r
1822 bModRM = rgINS[iInstEntry][6];
\r
1824 if (is_Reg(rgOpType[0])) {
\r
1825 EncodeRegBits(rgOpReg[0], &bModRM, 0);
\r
1826 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1829 else if (rgINS[iInstEntry][7] & zAR1) {
\r
1831 EncodeRegBits(rgOpReg[0], &bTmp, 0);
\r
1834 else if (rgINS[iInstEntry][7] & zAR2) {
\r
1836 EncodeRegBits(rgOpReg[1], &bTmp, 0);
\r
1839 else if ((rgINS[iInstEntry][7] & zRG1) && (rgOpType[0] != mem)) {
\r
1840 bModRM = rgINS[iInstEntry][6];
\r
1842 EncodeRegBits(rgOpReg[0], &bModRM, 3);
\r
1843 bModRM |= 0xC0; /* indictes REG in RM field */
\r
1847 /* OpSize may not be required for many instructions, but we know
\r
1848 for a fact it MUST be known for memory operands!
\r
1851 if ((rgOpType[0] == mem) ||
\r
1852 (rgOpType[1] == mem) ||
\r
1853 (rgOpType[0] == memF)) {
\r
1854 if (!(OpSizeA & (fByte|fWord|fDWord|fFWord))) {
\r
1861 If zORD, see if we have word or dword register and OR the Opcode
\r
1862 (Opc2) with 01 if so.
\r
1865 if (rgINS[iInstEntry][7] & zORD) {
\r
1866 if (OpSizeA & (fWord | fDWord))
\r
1870 /* Perform the following additonal steps if we have a memory reference
\r
1871 as determined by iMemEntry.
\r
1877 /* If SIB is needed (as determined from OpMType), get it and also
\r
1878 OR ModRM by required value from rgM32 table
\r
1881 bModRM |= rgM32[iMemEntry][2]; /* Use ModRM 'OR' value from table */
\r
1882 if (rgM32[iMemEntry][1]) { /* is there an SIB byte? */
\r
1883 bModRM &= 0x38; /* 00111000 leaves Reg bit on */
\r
1884 bModRM |= rgM32[iMemEntry][2]; /* 'OR' ModRM with table value */
\r
1885 bSIB = rgM32[iMemEntry][3];
\r
1890 /* At this point we have our Opcode, ModRM, and SIB (if required).
\r
1891 The MOD and SS bit are already filled in from the table.
\r
1892 This means we just stick the register values or bits for Disp etc
\r
1893 in the correct positions to complete it.
\r
1894 If we didn't have an SIB, we either have a single displacement,
\r
1898 if (!fSIB) { /* only a base, disp, or both */
\r
1899 if (OpMType & fBase)
\r
1900 EncodeRegBits(OpBase, &bModRM, 0);
\r
1902 bModRM |= 0x05; /* only a disp32 */
\r
1905 if (OpMType & fBase)
\r
1906 EncodeRegBits(OpBase, &bSIB, 0);
\r
1907 else bModRM |= 0x20; /* else set [--][--] bits */
\r
1908 if (OpMType & fIndx)
\r
1909 EncodeRegBits(OpIndx, &bSIB, 3);
\r
1918 /********************************************
\r
1919 When the dispatcher detects an Instruction
\r
1920 it calls this code to read in (via parse)
\r
1921 the parametrs for the instruction and to
\r
1922 put together the opcodes. First we loop thru
\r
1923 and get up to 3 operands, then we evaluate
\r
1924 them (classify by type). Next we look up
\r
1925 the instruction and find a match for the
\r
1926 operand types they have specified, and
\r
1927 finally, we encode the instruction into the
\r
1928 code segment updating the code segment offset
\r
1930 *********************************************/
\r
1931 void Instruction(void)
\r
1943 /* If the instruction is a prefix instruction, save it
\r
1944 and Parse again to get the real instruction */
\r
1946 if ((TInst==xREP) || (TInst==xREPE) || (TInst==xREPZ) ||
\r
1947 (TInst==xREPNE) || (TInst==xREPNZ) || (TInst==xLOCK)) {
\r
1950 if (i != INSTRU) {
\r
1954 } else InstPfx = 0;
\r
1956 /* RESET all global instruction variables */
\r
1958 CrntInst = TInst; /* Save the instruction */
\r
1959 nOperands = 0; /* none yet... */
\r
1963 OpMType = 0; /* char - memory type (a byte to compare to rgM32) */
\r
1964 OpSize[0] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1965 OpSize[1] = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1966 OpSizeA = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1967 OpSizeTmp = 0; /* char - Mem op size (fByte, fWord, fDword, fFword) */
\r
1968 OpPrefix = 0; /* For Segment register prefix flags */
\r
1969 OpDisp = 0; /* long - Displacement if fDisp8 or fDisp32 is TRUE */
\r
1970 OpBase = 0; /* int - Base register if fBase is true */
\r
1971 OpIndx = 0; /* int - Index register if fIndx is true */
\r
1972 fOpImm = 0; /* No Immediate value yet */
\r
1973 OpImm = 0; /* Default to 0 */
\r
1974 fOpImm2 = 0; /* No second Immediate value yet */
\r
1975 OpImm2 = 0; /* Default to 0 */
\r
1976 nFixUp = 0; /* Fixup type if needed, else 0 */
\r
1977 nExtRef = 0; /* GST entry if external ref was made */
\r
1978 fForRef = 0; /* No Forward Ref in crnt inst yet */
\r
1979 ExpType = 0; /* Type of symbol used in instruction */
\r
1980 ExpType0 = 0; /* Type of symbol used in instruction */
\r
1981 iExpSym = 0; /* Index into symtab for symbol if used */
\r
1982 iExpSym0 = 0; /* Index into symtab for symbol if used */
\r
1986 ExpType0 = ExpType;
\r
1987 iExpSym0 = iExpSym;
\r
1988 if ((Parse()== COMMA)) {
\r
1991 if ((Parse()== COMMA)) {
\r
2005 At this point we have the instruction operands stored in
\r
2006 tokenized form in arrays. We now call EvalOper() which evaluates
\r
2007 the operands and fills in several variables that will assist in
\r
2008 building the instruction. EvalOper() returns 1 if it was a valid
\r
2012 if (nOperands) { /* at least one */
\r
2013 if (EvalOper(0)) {
\r
2014 if (nOperands > 1) { /* a second operand */
\r
2015 if (EvalOper(1)) {
\r
2016 if (nOperands > 2) { /* a third??? - could be... */
\r
2017 if (!(EvalOper(2)))
\r
2027 if (fError) return;
\r
2030 We must check to see what the word size of the instruction is
\r
2031 by looking at register sizes if any are included in the instruction.
\r
2032 If there are memory references or immediates involved, OpSizeA
\r
2033 MUST be set properly else it's an error! When there is a symbol involved
\r
2034 such as a move to a memory variable, we check the variable size and set
\r
2035 the OpSize to the variable size. If it's still not set, the line will
\r
2036 error out when we try to build the instruction because the caller
\r
2037 should have explicitly set the size (e.g., DWORD PTR ...).
\r
2039 If a register is one of the operands in a memory transfer
\r
2040 (e.g., MOV [mem], EAX) then the move obviously defaults to the size
\r
2041 of the register (no ifs, ands, or buts).
\r
2043 If there is no reg involved, we then look at 'OpSize[i]'
\r
2044 which may have been set by the size operators (e.g., DWORD PTR).
\r
2045 If it's zero we look at iExpSym which was set if there was a single
\r
2046 symbol involved in the memory reference. If there was, then we use it.
\r
2047 If it is blank, we error out cause we don't know what size memory
\r
2048 access we are doing!
\r
2049 This is done for each operand then the two are compared. If one is
\r
2050 zero we use the other, if both have something but are different
\r
2054 /* Find the first operand size */
\r
2056 /* First, let's look to see if they forced it! */
\r
2058 if (OpSize[0] & (fByte|fWord|fDWord|fFWord))
\r
2060 { /* do nothing */ }
\r
2062 /* If they didn't force it, we'll look for the register size! */
\r
2064 else if (rgOpType[0] == r32) OpSize[0] |= fDWord;
\r
2065 else if (rgOpType[0] == r16) OpSize[0] |= fWord;
\r
2066 else if (rgOpType[0] == rSEG) OpSize[0] |= fWord;
\r
2067 else if (rgOpType[0] == r8) OpSize[0] |= fByte;
\r
2069 /* Still nothing, so let's at symbols. */
\r
2071 else if (ExpType0 == 1)
\r
2072 { /* Local symbol */
\r
2073 if (lst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;
\r
2074 else if (lst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;
\r
2075 else if (lst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;
\r
2076 else if (lst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;
\r
2078 else if (ExpType0 == 2)
\r
2079 { /* Global Symbol */
\r
2080 if (gst[iExpSym0].Type & sBYTE) OpSize[0] |= fByte;
\r
2081 else if (gst[iExpSym0].Type & sWORD) OpSize[0] |= fWord;
\r
2082 else if (gst[iExpSym0].Type & sDWORD) OpSize[0] |= fDWord;
\r
2083 else if (gst[iExpSym0].Type & sFWORD) OpSize[0] |= fFWord;
\r
2085 else if (ExpType0 == 3)
\r
2086 OpSize[0] |= fDWord; /* $ defaults to DWord */
\r
2089 /* Find the second operand size. Check "forced fit" first */
\r
2091 if (OpSize[1] & (fByte|fWord|fDWord|fFWord))
\r
2092 { /* do nothing */ }
\r
2094 else if (rgOpType[1] == r32) OpSize[1] |= fDWord;
\r
2095 else if (rgOpType[1] == r16) OpSize[1] |= fWord;
\r
2096 else if (rgOpType[1] == rSEG) OpSize[1] |= fWord;
\r
2097 else if (rgOpType[1] == r8) OpSize[1] |= fByte;
\r
2099 /* No registers, so let's look to see if they forced it! */
\r
2101 /* Still nothing, so let's at symbols. */
\r
2103 else if (ExpType == 1)
\r
2104 { /* Local symbol */
\r
2105 if (lst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;
\r
2106 else if (lst[iExpSym].Type & sWORD) OpSize[1] |= fWord;
\r
2107 else if (lst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;
\r
2108 else if (lst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;
\r
2110 else if (ExpType == 2)
\r
2111 { /* Global Symbol */
\r
2112 if (gst[iExpSym].Type & sBYTE) OpSize[1] |= fByte;
\r
2113 else if (gst[iExpSym].Type & sWORD) OpSize[1] |= fWord;
\r
2114 else if (gst[iExpSym].Type & sDWORD) OpSize[1] |= fDWord;
\r
2115 else if (gst[iExpSym].Type & sFWORD) OpSize[1] |= fFWord;
\r
2117 else if (ExpType == 3)
\r
2118 OpSize[1] |= fDWord; /* $ defaults to DWord */
\r
2120 /* Special cases for operand size matching. */
\r
2122 if (CrntInst == xOUT)
\r
2123 OpSize[0] = OpSize[1];
\r
2127 Now that have the operands, and we know the TYPE of data (fByte etc.)
\r
2128 we call INSEntry to find the matching
\r
2129 entry in the array that describes each instruction. If we don't
\r
2130 find one that matches we error out telling them they have bad
\r
2134 /* find first matching entry in rgINS */
\r
2136 iInstEntry = INSEntry(CrntInst, nOperands);
\r
2138 if (!iInstEntry) {
\r
2143 /* Now we make sure that we have set all operand sizes
\r
2144 and check for special cases as defined in rgINS.
\r
2147 if (rgINS[iInstEntry][7] & zSIZ)
\r
2148 OpSize[1] = OpSize[0];
\r
2151 OpSize[1] = OpSize[0];
\r
2154 OpSize[0] = OpSize[1];
\r
2156 /* Give them an error if operand sizes don't match */
\r
2158 if (nOperands > 1)
\r
2159 if (OpSize[0] != OpSize[1]) {
\r
2164 OpSizeA = OpSize[0]; /* Set primary operand size */
\r
2166 /* If either the first or second operand was memory, we have to find
\r
2167 which entry in rgM32 it matches before we can encode it. If none
\r
2168 matches it is an invalid memory operand. If neither is a mem operand
\r
2169 we set iMemEntry to zero. There is the special case of moffs type
\r
2170 which is a short form of displacmement when moving data to and from thew
\r
2171 accumulator (e.g., MOV EAX, VAR1). We check for this and skip the
\r
2172 mem check if this is the instruction type we are on.
\r
2175 if ((rgINS[iInstEntry][1] == moff) || (rgINS[iInstEntry][2] == moff))
\r
2177 else if ((rgOpType[0]==mem) ||
\r
2178 (rgOpType[1]==mem) ||
\r
2179 (rgOpType[0]==memF))
\r
2182 for (i=1; i<nrgM32; i++) {
\r
2183 if (OpMType == rgM32[i][0]) break;
\r
2186 /* if i is off the end of the array we
\r
2187 didn't find an entry that matched
\r
2194 else iMemEntry = i;
\r
2196 else iMemEntry = 0;
\r
2199 At this point we should have all information we need to actually
\r
2200 encode the instruction (unless it's a forward ref). So we call EncodeInst.
\r
2209 /********************************************
\r
2210 Create Storage in current segment. At this
\r
2211 point we should see a storage statement as
\r
2212 the current token followed by a number (or
\r
2213 string if DB). If string (DB) we insert
\r
2214 single byte values (one per char) into the
\r
2216 *********************************************/
\r
2217 void Storage(void)
\r
2219 S32 TSave, NSave, nDUP;
\r
2221 S8 fColon, fExpectColon, fComma, fDUP;
\r
2225 nDUP = 1; /* default duplicate value */
\r
2230 if (!fMoreStorage) { /* is it a continuation of previous line? */
\r
2231 switch(Token) { /* parse returns Token */
\r
2248 /* Now we loop thru looking for strings and numbers taking into account
\r
2249 the special case of DF which should be DWORD:WORD, and OFFSET
\r
2250 which will be a DWORD.
\r
2254 if (fMoreStorage) {
\r
2263 if (StoreSize==1) {
\r
2264 for(j=0; j<CBString; j++) {
\r
2266 put_hexb(TString[j], lst_fh);
\r
2268 Column += fprintf(lst_fh, " ");
\r
2269 if (Column > 51) {
\r
2270 fprintf(lst_fh, "\r\n ");
\r
2274 OutByteX(TString[j]);
\r
2283 if (StoreSize != 4) {
\r
2287 /* fall thru to evaluate & store value */
\r
2289 case DOLLAR: /* These should all evaluate to a number. */
\r
2290 case OPENRND: /* If it's SYMOFF, we do a fixup or Forward Ref */
\r
2296 if (!(Expression())) /* 0 means error was emmited. */
\r
2299 symtype = 0; /* default to no symbol type */
\r
2300 nExtRef = 0; /* default to no external ref */
\r
2302 if ((Token==SYMOFF) || (Token==NUMOFF))
\r
2304 if (ExpType == 1) /* Local */
\r
2305 symtype = lst[iExpSym].Type;
\r
2306 else if (ExpType == 2) { /* global */
\r
2307 symtype = gst[iExpSym].Type;
\r
2308 if (gst[iExpSym].Type & tEXTRN)
\r
2309 nExtRef = iExpSym;
\r
2316 if (Parse() == rDUP)
\r
2321 if (Token == OPENRND) {
\r
2322 if (!(Expression())) /* 0 means error was emitted.*/
\r
2327 /* TNumber now has (VALUE) from DUP */
\r
2339 fColon=0; /* reset it */
\r
2343 put_hexw(sword, lst_fh);
\r
2344 Column += fprintf(lst_fh, " ");
\r
2346 OutWordX(TNumber);
\r
2352 put_hexd(TNumber, lst_fh);
\r
2353 Column += fprintf(lst_fh, " ");
\r
2355 OutDWordX(TNumber);
\r
2358 else if (StoreSize==4) {
\r
2362 if ((Token == SYMOFF) || (Token == NUMOFF))
\r
2363 Column += fprintf(lst_fh, "%08lX * (%08lXr)",nDUP,TNumber);
\r
2365 Column += fprintf(lst_fh, "%08lX * (%08lX)",nDUP,TNumber);
\r
2369 if ((Token==SYMOFF) || (Token==NUMOFF))
\r
2371 if (fDataSeg) { /* Data Seg */
\r
2373 ExtRef(DSEGREF, iExpSym);
\r
2374 else if (!symtype)
\r
2375 ForRef(DSEGREF, oNextData);
\r
2376 else if (symtype & CLABEL)
\r
2377 FixUp(DCFIXTAG, oNextData, 0);
\r
2378 else if (symtype & DLABEL)
\r
2379 FixUp(DDFIXTAG, oNextData, 0);
\r
2381 else { /* Code Seg */
\r
2383 ExtRef(CSEGREF, iExpSym);
\r
2385 ForRef(CSEGREF, oNextCode);
\r
2386 else if (symtype & CLABEL)
\r
2387 FixUp(CCFIXTAG, oNextCode, 0);
\r
2388 else if (symtype & DLABEL)
\r
2389 FixUp(CDFIXTAG, oNextCode, 0);
\r
2392 OutDWordX(TNumber);
\r
2398 if ((Token == SYMOFF) || (Token == NUMOFF))
\r
2399 Column += fprintf(lst_fh, " %08lXr", TNumber);
\r
2401 Column += fprintf(lst_fh, " %08lX", TNumber);
\r
2404 /* Fixup & Forref here! */
\r
2405 if ((Token==SYMOFF) || (Token==NUMOFF))
\r
2410 ExtRef(DSEGREF, iExpSym);
\r
2411 else if (!symtype)
\r
2412 ForRef(DSEGREF, oNextData);
\r
2413 else if (symtype & CLABEL)
\r
2414 FixUp(DCFIXTAG, oNextData, 0);
\r
2415 else if (symtype & DLABEL)
\r
2416 FixUp(DDFIXTAG, oNextData, 0);
\r
2421 ExtRef(CSEGREF, iExpSym);
\r
2422 else if (!symtype)
\r
2423 ForRef(CSEGREF, oNextCode);
\r
2424 else if (symtype & CLABEL)
\r
2425 FixUp(CCFIXTAG, oNextCode, 0);
\r
2426 else if (symtype & DLABEL)
\r
2427 FixUp(CDFIXTAG, oNextCode, 0);
\r
2430 OutDWordX(TNumber);
\r
2433 else if (StoreSize==2) {
\r
2436 Column += fprintf(lst_fh, "%08lX * (%04lX) ",nDUP,TNumber);
\r
2438 OutWordX(TNumber);
\r
2442 Column += fprintf(lst_fh, "%04lX ", TNumber);
\r
2443 OutWordX(TNumber);
\r
2449 Column += fprintf(lst_fh, "%08lX * (%02lX) ",nDUP,TNumber);
\r
2451 OutByteX(TNumber);
\r
2455 Column += fprintf(lst_fh, "%02lX ", TNumber);
\r
2456 OutByteX(TNumber);
\r
2460 case COMMA: /* Just eat the comma */
\r
2469 if ((StoreSize == 6) && (fExpectColon)) {
\r
2479 if (fComma) fMoreStorage = 1;
\r
2490 /********************************************
\r
2491 Add new GLOBAL symbol to table (TString).
\r
2492 Then parse again to hand off to
\r
2493 proper function. This stores all
\r
2494 Symbols UPPER case.
\r
2495 *********************************************/
\r
2499 S8 fColon, fStorage;
\r
2501 if ((pSymNext + CBString) >= (pSymBuf + SYMBUFMAX))
\r
2502 fatal_error("Symbol buffer overflow...");
\r
2503 if (iSymNext >= SYMSMAX)
\r
2504 fatal_error("Symbol table overflow...");
\r
2506 strncpy(pSymNext, TString, CBString);
\r
2507 gst[iSymNext].Size = CBString;
\r
2508 gst[iSymNext].Type = 0; /* initialize type */
\r
2509 gst[iSymNext].Ptr = pSymNext;
\r
2510 gst[iSymNext].Line = lineno[level];
\r
2511 gst[iSymNext].Offs = 0;
\r
2513 /* All declarations that reach NewSymbol are either at
\r
2514 level 0 or defined as PUBLIC or EXTERN.
\r
2518 gst[iSymNext].Type |= tEXTRN;
\r
2520 gst[iSymNext].Type |= tPUBLIC;
\r
2522 if (fFarLabel) gst[iSymNext].Type |= tFAR;
\r
2526 gst[iSymNext].Offs = oNextData;
\r
2527 gst[iSymNext].Type |= DLABEL;
\r
2531 gst[iSymNext].Offs = oNextCode;
\r
2532 gst[iSymNext].Type |= CLABEL;
\r
2535 /* update for next symbol */
\r
2536 pSymNext += CBString;
\r
2540 /* Now, parse again and hand off. We have just added a symbol
\r
2541 so expect to see an EQU, COLON or Storage statement.
\r
2542 If we don't see one of these it's an error unless it's an extern.
\r
2543 If we see a COLON we parse again and expect an instruction or EOL!
\r
2559 switch(i) { /* parse returns Token */
\r
2572 gst[iSymNext-1].Type |= sBYTE; /* type */
\r
2576 gst[iSymNext-1].Type |= sWORD; /* type */
\r
2580 gst[iSymNext-1].Type |= sDWORD; /* type */
\r
2584 if ((!fDataSeg) && (!fColon)) {
\r
2588 gst[iSymNext-1].Type |= sFWORD; /* type */
\r
2599 if ((fDataSeg) && (!fExtern))
\r
2607 if (gst[iSymNext-1].Type & tEXTRN)
\r
2614 /********************************************
\r
2615 This changes an EXTRN entry in the gst to
\r
2616 a PUBLIC once we find it. This checks to
\r
2617 make sure the extern declaration was the
\r
2618 same type as this public.
\r
2619 *********************************************/
\r
2621 void MakePublic(void)
\r
2624 S8 fColon, fStorage;
\r
2626 if (gst[TSymnum].Type & tPUBLIC) {
\r
2631 if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {
\r
2636 if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {
\r
2641 gst[TSymnum].Type |= tPUBLIC; /* Turn ON Public */
\r
2642 gst[TSymnum].Type &= ~tEXTRN; /* Turn off EXTERN */
\r
2645 gst[TSymnum].Offs = oNextData;
\r
2647 gst[TSymnum].Offs = oNextCode;
\r
2649 /* Now, parse again and hand off. We have just added a symbol
\r
2650 so expect to see an EQU, COLON or Storage statement.
\r
2651 If we don't see one of these it's an error unless it's an extern.
\r
2652 If we see a COLON we parse again and expect an instruction or EOL!
\r
2668 switch(i) { /* parse returns Token */
\r
2681 gst[TSymnum].Type |= sBYTE; /* type */
\r
2685 gst[TSymnum].Type |= sWORD; /* type */
\r
2689 gst[TSymnum].Type |= sDWORD; /* type */
\r
2693 if ((!fDataSeg) && (!fColon)) {
\r
2697 gst[TSymnum].Type |= sFWORD; /* type */
\r
2716 /********************************************
\r
2717 This checks to ensure multiple externs are
\r
2718 the same type when we run across them, and
\r
2719 also that an extern is the same type if
\r
2720 the public is already declared.
\r
2721 *********************************************/
\r
2722 void CheckExtern(void)
\r
2724 /* Check to make sure new extern and symbol are same type */
\r
2726 if ((fDataSeg) && (!(gst[TSymnum].Type & DLABEL))) {
\r
2731 if ((!fDataSeg) && (!(gst[TSymnum].Type & CLABEL))) {
\r
2738 /********************************************
\r
2739 Add new LOCAL symbol to table (TString).
\r
2740 Then parse again to hand off to
\r
2741 proper function. This stores all
\r
2742 Symbols UPPER case.
\r
2743 *********************************************/
\r
2744 void NewLSymbol(void)
\r
2747 S8 fColon, fStorage;
\r
2749 if ((pLSymNext + CBString) >= (pLSymBuf + LSYMBUFMAX))
\r
2750 fatal_error("Local symbol buffer overflow...");
\r
2751 if (iLSymNext >= LSYMSMAX)
\r
2752 fatal_error("Local symbol table overflow...");
\r
2754 strncpy(pLSymNext, TString, CBString);
\r
2755 lst[iLSymNext].Size = CBString;
\r
2756 lst[iLSymNext].Type = 0; /* initialize type */
\r
2757 lst[iLSymNext].Ptr = pLSymNext;
\r
2758 lst[iLSymNext].Line = lineno[level];
\r
2761 lst[iLSymNext].Offs = oNextData;
\r
2762 lst[iLSymNext].Type |= DLABEL;
\r
2765 lst[iLSymNext].Offs = oNextCode;
\r
2766 lst[iLSymNext].Type |= CLABEL;
\r
2769 /* update for next symbol */
\r
2770 pLSymNext += CBString;
\r
2773 /* Now, parse again and hand off. We have just added a symbol
\r
2774 so expect to see an EQU, COLON or Storage statement.
\r
2775 If we don't see one of these it's an error!
\r
2776 If we see a COLON we parse again and expect an instruction or EOL!
\r
2792 switch(i) { /* parse returns Token */
\r
2805 lst[iLSymNext-1].Type |= sBYTE; /* type */
\r
2809 lst[iLSymNext-1].Type |= sWORD; /* type */
\r
2813 lst[iLSymNext-1].Type |= sDWORD; /* type */
\r
2817 if ((!fDataSeg) && (!fColon)) {
\r
2821 lst[iLSymNext-1].Type |= sFWORD; /* type */
\r
2834 if (lst[iLSymNext-1].Type & tEXTRN)
\r
2842 /*****************************************
\r
2843 After we transition from level 1 back to
\r
2844 level 0 we go back to the point in the
\r
2845 code or data file where we began writing this
\r
2846 section and resolve all forward code
\r
2847 and local data references. These will be
\r
2848 referenced in the module we just finished.
\r
2849 ******************************************/
\r
2851 void Resolve(void)
\r
2860 while (i < iRefNext) /* While there are forward references */
\r
2862 if (pfrt[i].Type == DSEGREF) /* Ref is in DSEG */
\r
2864 seekDS(pfrt[i].Offs - DataOffset);
\r
2865 readDS(&Partial, 4);
\r
2866 seekDS(pfrt[i].Offs - DataOffset);
\r
2867 AddFix = pfrt[i].Offs - DataOffset;
\r
2869 else /* Ref is in CSEG */
\r
2871 seekCS(pfrt[i].Offs - CodeOffset);
\r
2873 if (pfrt[i].Type == CSEGREF) /* IT'S ABSOLUTE! */
\r
2875 readCS(&Partial, 4);
\r
2876 seekCS(pfrt[i].Offs - CodeOffset);
\r
2877 AddFix = pfrt[i].Offs - CodeOffset;
\r
2880 /* We are where we should write the reference
\r
2881 now we need to find it in the local symbol table
\r
2882 and calculate the proper offset. The calculation
\r
2883 is different for Relative and absolute references.
\r
2884 For Relative, we subtract the address where the correction
\r
2885 is going to be stored from the offset of reference.
\r
2886 For Absolute, we read what was already at the address
\r
2887 and add it to the offset of the referenced item.
\r
2888 Both of these are also adjusted for the Virtual segment offset.
\r
2891 /* Look in the Local Symbol table first! */
\r
2893 isym = findLsymbol(pfrt[i].Ptr, pfrt[i].NameSz);
\r
2895 if (isym) /* we found it! */
\r
2897 if (pfrt[i].Type == CCR8REF) /* 8 bit relative */
\r
2899 Relative = lst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);
\r
2900 OutByteCS(Relative);
\r
2902 else if (pfrt[i].Type == CCR32REF) /* 32 bit relative */
\r
2904 /* Fixed to make relatives ok in Virtual Segs */
\r
2906 Relative = (lst[isym].Offs - CodeOffset) -
\r
2907 (pfrt[i].Offs - CodeOffset + 4);
\r
2908 OutDWordCS(Relative);
\r
2910 else if (pfrt[i].Type == CSEGREF) /* 32 bit absolute */
\r
2912 Partial += lst[isym].Offs;
\r
2914 if (lst[isym].Type & CLABEL)
\r
2915 FixUp(CCFIXTAG, AddFix, 0);
\r
2916 else if (lst[isym].Type & DLABEL)
\r
2917 FixUp(CDFIXTAG, AddFix, 0);
\r
2919 OutDWordCS(Partial);
\r
2921 else if (pfrt[i].Type == DSEGREF)
\r
2923 Partial += lst[isym].Offs; /* RAB was + DataOffset */
\r
2925 if (lst[isym].Type & CLABEL)
\r
2926 FixUp(DCFIXTAG, AddFix, 0);
\r
2927 else if (lst[isym].Type & DLABEL)
\r
2928 FixUp(DDFIXTAG, AddFix, 0);
\r
2930 OutDWordDS(Partial);
\r
2933 else /* Look in Global table */
\r
2936 isym = findGsymbol(pfrt[i].Ptr, pfrt[i].NameSz);
\r
2940 { /* we found it! */
\r
2943 if (pfrt[i].Type == CCR8REF) { /* 8 bit relative */
\r
2944 Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 1);
\r
2945 OutByteCS(Relative);
\r
2947 else if (pfrt[i].Type == CCR32REF) { /* 32 bit relative */
\r
2948 Relative = gst[isym].Offs - (pfrt[i].Offs - CodeOffset + 4);
\r
2949 OutDWordCS(Relative);
\r
2951 else if (pfrt[i].Type == CSEGREF) {
\r
2952 Partial += gst[isym].Offs;
\r
2954 if (gst[isym].Type & CLABEL)
\r
2955 FixUp(CCFIXTAG, AddFix, 0);
\r
2956 else if (gst[isym].Type & DLABEL)
\r
2957 FixUp(CDFIXTAG, AddFix, 0);
\r
2959 OutDWordCS(Partial);
\r
2961 else if (pfrt[i].Type == DSEGREF)
\r
2963 Partial += gst[isym].Offs;
\r
2965 if (gst[isym].Type & CLABEL)
\r
2966 FixUp(DCFIXTAG, AddFix, 0);
\r
2967 else if (gst[isym].Type & DLABEL)
\r
2968 FixUp(DDFIXTAG, AddFix, 0);
\r
2970 OutDWordDS(Partial);
\r
2974 prev_error("Unresolved symbol in current module", pfrt[i].Line);
\r
2979 ics = oNextCode - CodeOffset;
\r
2980 ids = oNextData - DataOffset;
\r
2984 /*****************************************
\r
2985 When we have processed all the source
\r
2986 we call this to resolve ALL externals.
\r
2987 ******************************************/
\r
2989 void ResolveExt(void)
\r
3002 while (i < iERefNext) { /* While there are unresolved externals */
\r
3004 /* See if ref is in GST as PUBLIC */
\r
3006 isym = ert[i].iSym;
\r
3008 if (gst[isym].Type & tPUBLIC) {
\r
3010 if (ert[i].Type == DSEGREF) { /* Ref is in DSEG */
\r
3012 seekDS(ert[i].Offs - DataOffset);
\r
3013 readDS(&Partial, 4);
\r
3014 seekDS(ert[i].Offs - DataOffset);
\r
3015 AddFix = ert[i].Offs - DataOffset;
\r
3017 else { /* Ref is in CSEG */
\r
3019 seekCS(ert[i].Offs - CodeOffset);
\r
3021 if (ert[i].Type == CSEGREF) { /* and IT'S ABSOLUTE! */
\r
3022 readCS(&Partial, 4);
\r
3023 seekCS(ert[i].Offs - CodeOffset);
\r
3024 AddFix = ert[i].Offs - CodeOffset;
\r
3027 /* We are where we should write the reference
\r
3028 now we need to use the index in the external ref
\r
3029 table to see if it has been defined PUBLIC.
\r
3030 If so, we resolve it, else we error out.
\r
3031 To resolve it, the calculation is different for Relative
\r
3032 and absolute references.
\r
3033 For Relative, we subtract the address where the correction
\r
3034 is going to be stored from the offset of reference.
\r
3035 For Absolute, we read what was already at the address
\r
3036 and add it to the offset of the referenced item.
\r
3037 Both of these are also adjusted for the Virtual segment offset.
\r
3040 if (ert[i].Type == CCR32REF) { /* 32 bit relative */
\r
3042 /* Fixed to make relatives ok in Virtual Segs */
\r
3044 Relative = (gst[isym].Offs - CodeOffset) -
\r
3045 (ert[i].Offs - CodeOffset + 4);
\r
3046 OutDWordCS(Relative);
\r
3048 else if (ert[i].Type == CSEGREF) {
\r
3049 Partial += gst[isym].Offs;
\r
3051 if (gst[isym].Type & DLABEL)
\r
3052 FixUp(CDFIXTAG, AddFix, 0);
\r
3053 else if (gst[isym].Type & CLABEL)
\r
3054 FixUp(CCFIXTAG, AddFix, 0);
\r
3056 OutDWordCS(Partial);
\r
3058 else if (ert[i].Type == DSEGREF) {
\r
3059 Partial += gst[isym].Offs;
\r
3061 if (gst[isym].Type & CLABEL)
\r
3062 FixUp(DCFIXTAG, AddFix, 0);
\r
3063 else if (gst[isym].Type & DLABEL)
\r
3064 FixUp(DDFIXTAG, AddFix, 0);
\r
3066 OutDWordDS(Partial);
\r
3070 strncpy(name, gst[isym].Ptr, gst[isym].Size);
\r
3071 name[gst[isym].Size] = '\0';
\r
3072 fprintf(lst_fh, "Unresolved external: %s\n", name);
\r
3077 } /* while more Erefs */
\r
3079 ics = oNextCode - CodeOffset;
\r
3080 ids = oNextData - DataOffset;
\r
3084 /*****************************************
\r
3085 If there were no errors, and all looks
\r
3086 well, we build the run file. This consists
\r
3087 of building the required tags in order
\r
3088 and writing them to the file with the
\r
3090 ******************************************/
\r
3092 void BuildRunFile(void)
\r
3098 tag.id = IDTAG; /* File type */
\r
3100 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3101 fwrite(&filetype, 1, 1, run_fh); /* Write the filetype */
\r
3103 /* Version tag goes here */
\r
3104 /* DatTime tag goes here */
\r
3105 /* Comment tag(s) goes here */
\r
3107 tag.id = SEGTAG; /* Initial Segment Sizes */
\r
3109 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3110 fwrite(&StackTotal, 4, 1, run_fh); /* Write the Stacktotal */
\r
3111 sdata = oNextCode - CodeOffset; /* Size of CS.TMP */
\r
3112 fwrite(&sdata, 4, 1, run_fh); /* Write the Code Size */
\r
3113 sdata = oNextData - DataOffset; /* Size of DS.TMP */
\r
3114 fwrite(&sdata, 4, 1, run_fh); /* Write the Data Size */
\r
3116 printf("Stack Size: %ld\r\n", StackTotal);
\r
3117 printf("Code Size: %ld\r\n", oNextCode - CodeOffset);
\r
3118 printf("Data Size: %ld\r\n", oNextData - DataOffset);
\r
3120 tag.id = DOFFTAG; /* Assumed Data Offset */
\r
3122 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3123 fwrite(&DataOffset, 4, 1, run_fh); /* Write the data */
\r
3125 tag.id = COFFTAG; /* Assumed Code Offset */
\r
3127 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3128 fwrite(&CodeOffset, 4, 1, run_fh); /* Write the data */
\r
3130 tag.id = STRTTAG; /* Starting Address */
\r
3132 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3133 fwrite(&StartAddr, 4, 1, run_fh); /* Write the data */
\r
3135 tag.id = CODETAG; /* Code Segment */
\r
3136 tag.len = oNextCode - CodeOffset; /* Size of CS.TMP */
\r
3137 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3139 sdata = tag.len; /* WRITE the Code seg */
\r
3140 fwrite(pcsbuf, 1, sdata, run_fh);
\r
3142 tag.id = DATATAG; /* Data Segment */
\r
3143 tag.len = oNextData - DataOffset; /* Size of DS.TMP */
\r
3144 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3146 sdata = tag.len; /* WRITE the Data seg */
\r
3147 fwrite(pdsbuf, 1, sdata, run_fh);
\r
3150 tag.id = CDFIXTAG; /* CSEG Data Fixups */
\r
3151 tag.len = nCDFix * 4; /* Count * 4 of Fixups */
\r
3152 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3154 while (i--) { /* Write CD fixups */
\r
3155 if (pfut[i].type == CDFIXTAG)
\r
3156 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3161 tag.id = CCFIXTAG; /* CSEG Code Fixups */
\r
3162 tag.len = nCCFix * 4; /* Count * 4 of Fixups */
\r
3163 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3165 while (i--) { /* Write CC fixups */
\r
3166 if (pfut[i].type == CCFIXTAG)
\r
3167 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3172 tag.id = DDFIXTAG; /* DESG Data Fixups */
\r
3173 tag.len = nDDFix * 4; /* Count * 4 of Fixups */
\r
3174 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3176 while (i--) { /* Write DD fixups */
\r
3177 if (pfut[i].type == DDFIXTAG)
\r
3178 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3183 tag.id = DCFIXTAG; /* DESG Code Fixups */
\r
3184 tag.len = nDCFix * 4; /* Count * 4 of Fixups */
\r
3185 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3187 while (i--) { /* Write DC fixups */
\r
3188 if (pfut[i].type == DCFIXTAG)
\r
3189 fwrite(&pfut[i].Offs, 1, 4, run_fh);
\r
3193 /* DLL Address fixup tag goes here */
\r
3194 /* DLL Public tag goes here */
\r
3196 tag.id = ENDTAG; /* End Tag */
\r
3197 tag.len = 4; /* Size of CS.TMP */
\r
3198 fwrite(&tag, 5, 1, run_fh); /* Write the tag record */
\r
3200 fwrite(&sdata, 4, 1, run_fh); /* Write the tag record */
\r
3205 /*****************************************
\r
3206 Reads a whole line into line buffer.
\r
3207 ******************************************/
\r
3209 S32 readline(void)
\r
3214 if (!(fgets(line_ptr = line_buf0, 100, src_fh[level])))
\r
3217 if (level) { /* we are in a nested include */
\r
3218 fclose(src_fh[level]);
\r
3220 if (level==0) { /* back up one level */
\r
3222 /* Processes forward references from this module */
\r
3230 /* Clear local symbol, forward refs, & macro tables */
\r
3232 iLSymNext = 1; /* 1st entry. */
\r
3233 pLSymNext = pLSymBuf; /* beginning of buffer */
\r
3235 iRefNext = 0; /* 1st entry. */
\r
3236 pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */
\r
3238 iMacNext = 0; /* 1st entry */
\r
3239 pMacNext = pMacBuf; /* Begining of buffer */
\r
3244 fprintf(lst_fh, "\r\n ");
\r
3245 fprintf(lst_fh, "CONTINUING-> %s, Level:%d\r\n", srcname[level],level);
\r
3246 fprintf(lst_fh, "\r\n");
\r
3248 if (lineno[level]) --lineno[level];
\r
3252 { /* We are at the end of the ATF file */
\r
3254 /* Processes forward references from Level 0 */
\r
3264 line_error(12); /* Starting address not found */
\r
3269 printf("%d Errors\r\n%d Warnings\r\n", error_count, warn_count);
\r
3271 if (fListA | fListE)
\r
3272 fprintf(lst_fh,"%d Errors\r\n%d Warnings\r\n",
\r
3273 error_count,warn_count);
\r
3277 printf("Building Run file...\r\n");
\r
3279 printf(" Done.\r\n");
\r
3283 fclose(src_fh[level]);
\r
3292 while (isspace(*pLine)) pLine++;
\r
3293 while ((*pLine) && (*pLine != ';') && (*pLine != 0x0A))
\r
3294 list_buf[i++] = *pLine++;
\r
3295 while ((i) && (list_buf[i-1] == ' ')) --i; /* eat trailing spaces */
\r
3296 list_buf[i] = 0; /* null terminate */
\r
3297 if (i) fLineIn = 1;
\r
3305 /********************************************
\r
3306 Dispatch calls Parse from the beginning
\r
3307 of a line and calls the proper routine
\r
3308 based on what it finds (from Parse()).
\r
3309 Dispatch calls readline to get a new line
\r
3310 after each of the line-specific modules
\r
3311 gets done with it's line or lines(s).
\r
3312 *********************************************/
\r
3314 void Dispatch(void)
\r
3322 if (fContinue) { /* We have just returned from an include */
\r
3323 fContinue = 0; /* and must reread the line without processing */
\r
3327 if (lineno[level] == 1) {
\r
3329 fprintf(lst_fh, "\r\n ");
\r
3330 fprintf(lst_fh, "PROCESSING-> %s, Level:%d\r\n", srcname[level], level);
\r
3334 Column = fprintf(lst_fh, "%06d ", lineno[level]);
\r
3347 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3366 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3370 else if (j==UNKSYM)
\r
3378 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3382 else if (j==UNKSYM)
\r
3389 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3403 Column += fprintf(lst_fh, "%08lX ", *pNextAddr);
\r
3413 if ((fLineIn) && (fListA)) {
\r
3414 while (Column < 53) Column += fprintf(lst_fh, " ");
\r
3415 fprintf(lst_fh, "%s", list_buf);
\r
3418 fprintf(lst_fh, "\r\n");
\r
3423 /*********************
\r
3425 **********************/
\r
3427 void main(S32 argc, S8 *argv[])
\r
3433 lst_fh = stdout; /* default the list file */
\r
3435 for(i=1; i < argc; ++i) {
\r
3437 if (*ptr == '/') {
\r
3440 case 'L' : /* List file ON */
\r
3444 case 'S' : /* Dump Symbols */
\r
3448 case 'E' : /* List file ON for errors/warns only */
\r
3452 case 'D' : /* Process as DLL */
\r
3456 case 'V' : /* Process as Devive Driver */
\r
3461 fatal_error("Invalid option\n");
\r
3467 strncpy(srcname, argv[i], 39);
\r
3468 src_fh[0] = fopen(argv[i], "r");
\r
3470 else if(!run_fh) {
\r
3471 strncpy(runname, argv[i], 39);
\r
3472 if(!(run_fh = fopen(argv[i], "wb"))) {
\r
3473 fatal_error("Can't open RUN file\n");
\r
3477 fatal_error("Too many options\n"); /* Too many parameters */
\r
3481 /* Input file not explicitly named errors out */
\r
3483 printf("Usage: ATFfile [RunFile] /L /E /D /V\r\n");
\r
3484 printf("/L = Complete List file generated\r\n");
\r
3485 printf("/S = Include SYMBOLS (only in complete list file)\r\n");
\r
3486 printf("/E = List file for Errors/warnings only\r\n");
\r
3487 printf("/D = Process as Dynamic link library\r\n");
\r
3488 printf("/V = Process as deVice driver\r\n");
\r
3489 fatal_error("Can't open Template file\n"); /* Can't open ATF file */
\r
3492 /* Output file not explicitly named defaults to Source.RUN */
\r
3494 if(!run_fh) { /* default asm name to SourceName.run */
\r
3495 strncpy(runname, srcname, 40);
\r
3497 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
3499 if (filetype == 2) {
\r
3504 else if (filetype == 3) {
\r
3516 if(!(run_fh = fopen(runname, "wb"))) {
\r
3517 fatal_error("Can't open OUTPUT file\n"); /* Can't open RUN file */
\r
3521 /* List file named Source.LIS for fListA and fListE only. */
\r
3523 if (fListA | fListE) {
\r
3524 strncpy(lstname, srcname, 40);
\r
3526 while ((*pname != '.') && (*pname!= '\0')) pname++;
\r
3532 if(!(lst_fh = fopen(lstname, "w")))
\r
3533 fatal_error("Can't open list file (source.LIS)\n"); /* Can't open List file */
\r
3538 printf("DASM Ver 1.7M (c) R.A. Burgess 1992,1993,1994,1995\r\n\r\n");
\r
3540 if (fListA | fListE)
\r
3541 fprintf(lst_fh, "DASM Ver 1.7M (c) R.A. Burgess 1992,1993,1994,1995\r\n\r\n");
\r
3545 "LINE OFFSET ACTION/DATA/CODE SOURCE\r\n\r\n");
\r
3547 erc = AllocPage(LSYMBUFMAX/4096, &pLSymBuf);
\r
3549 fatal_error("Can't Allocate buffer 1\n");
\r
3551 erc = AllocPage(SYMBUFMAX/4096, &pSymBuf);
\r
3553 fatal_error("Can't Allocate buffer 2\n");
\r
3555 erc = AllocPage(MACBUFMAX/4096, &pMacBuf);
\r
3557 fatal_error("Can't Allocate buffer 3\n");
\r
3559 erc = AllocPage(FREFBUFMAX/4096, &pRefBuf);
\r
3561 fatal_error("Can't Allocate buffer 4\n");
\r
3563 erc = AllocPage(FREFTABMAX/4096, &pfrt);
\r
3565 fatal_error("Can't Allocate buffer 5\n");
\r
3567 erc = AllocPage(FIXUPBUFMAX/4096, &pfut);
\r
3569 fatal_error("Can't Allocate buffer 6\n");
\r
3572 pSymNext = pSymBuf; /* Allocate memory - Was SymBuf */
\r
3573 pLSymNext = pLSymBuf; /* Allocate memory - Was LSymBuf */
\r
3574 pMacNext = pMacBuf; /* Allocate memory - Was MacBuf */
\r
3575 pRefNext = pRefBuf; /* Allocate memory - Was RefBuf */
\r
3577 pNextAddr = &oNextData; /* default to DataSeg */
\r
3579 erc = AllocPage(STMPBUFS/4096, &pcsbuf);
\r
3581 fatal_error("Can't Allocate CS buffer \n");
\r
3583 erc = AllocPage(STMPBUFS/4096, &pdsbuf);
\r
3585 fatal_error("Can't Allocate DS buffer \n");
\r
3587 ics = 0; /* current index into tmp buffers */
\r
3590 /* We now build a dynamic instruction lookup table which indexes
\r
3591 the first entry of an instruction in the opcode array 'rgINS'.
\r
3592 This is done dynamically because we are still optimizing.
\r
3595 /* i is the instruction we are indexing */
\r
3596 /* j is the position in rgINS */
\r
3598 for (i=1; i<ninst+1; i++) {
\r
3599 for (j=1; j<nrgINS; j++) {
\r
3600 if (rgINS[j][0] == i) {
\r
3601 rgInsLookUp[i] = j;
\r