624 lines
9.8 KiB
C
624 lines
9.8 KiB
C
/* asmutl.c -- microsoft 80x86 assembler
|
|
**
|
|
** microsoft (r) macro assembler
|
|
** copyright (c) microsoft corp 1986. all rights reserved
|
|
**
|
|
** randy nevin
|
|
**
|
|
** 10/90 - Quick conversion to 32 bit by Jeff Spencer
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "asm86.h"
|
|
#include "asmfcn.h"
|
|
#include "asmctype.h"
|
|
#include "asmindex.h"
|
|
#include "asmmsg.h"
|
|
|
|
extern char *fname;
|
|
extern char hexchar[];
|
|
|
|
/* put a bunch of registers into the symbol table */
|
|
VOID initregs(
|
|
struct mreg *makreg
|
|
){
|
|
register struct mreg *index;
|
|
register char *p;
|
|
char * savelbufp;
|
|
|
|
savelbufp = lbufp;
|
|
|
|
for (index = makreg; *index->nm; index++)
|
|
{
|
|
lbufp = index->nm;
|
|
getatom();
|
|
|
|
if (symsearch())
|
|
/* register already defined */
|
|
errorn(E_RAD);
|
|
|
|
symcreate( M_NOCREF | M_BACKREF | M_DEFINED, REGISTER);
|
|
symptr->offset = index->val;
|
|
symptr->symu.regsym.regtype = index->rt;
|
|
symbolcnt--;
|
|
}
|
|
lbufp = savelbufp;
|
|
}
|
|
|
|
|
|
|
|
/*** scanorder - process symbol list in order
|
|
*
|
|
* scanorder (root, fcn);
|
|
*
|
|
* Entry root = root of symbol list
|
|
* fcn = pointer to function to be executed
|
|
* Exit none
|
|
* Returns none
|
|
* Calls
|
|
*/
|
|
|
|
#if !defined XENIX286 && !defined FLATMODEL
|
|
# pragma alloc_text (FA_TEXT, scanorder)
|
|
#endif
|
|
|
|
VOID PASCAL
|
|
scanorder (
|
|
SYMBOL FARSYM *root,
|
|
SHORT (PASCAL *item) (SYMBOL FARSYM *)
|
|
){
|
|
register SYMBOL FARSYM *p;
|
|
|
|
for (p = root; p; p = p->next) {
|
|
symptr = p;
|
|
(*item) (p);
|
|
}
|
|
}
|
|
|
|
|
|
/*** scanSorted - process symbol sorted order
|
|
*
|
|
* Entry root = root of symbol list
|
|
* fcn = pointer to function to be executed
|
|
* Exit none
|
|
* Returns none
|
|
* Calls
|
|
*/
|
|
|
|
#if !defined XENIX286 && !defined FLATMODEL
|
|
# pragma alloc_text (FA_TEXT, scanSorted)
|
|
#endif
|
|
|
|
VOID PASCAL
|
|
scanSorted (
|
|
SYMBOL FARSYM *root,
|
|
SHORT (PASCAL *item) (SYMBOL FARSYM *)
|
|
){
|
|
register SYMBOL FARSYM *p;
|
|
|
|
for (p = root; p; p = p->alpha) {
|
|
symptr = p;
|
|
if (!(M_PASSED & p->attr))
|
|
(*item) (p);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*** assignemitsylinknum - assign link number
|
|
*
|
|
* assignlinknum (sym);
|
|
*
|
|
* Entry *sym = symbol
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
* Note Turn off BACKREF and PASSED bits in symbol attributes and
|
|
* if symbol is segment, group, public or external give it a
|
|
* link dictionary number
|
|
*/
|
|
|
|
SHORT PASCAL
|
|
assignlinknum (
|
|
register SYMBOL FARSYM *sym
|
|
){
|
|
switch (sym->symkind) {
|
|
|
|
case MACRO: /* make symbol unknown at start of p2 */
|
|
case STRUC:
|
|
case REC:
|
|
sym->attr &= ~M_BACKREF;
|
|
return 0;
|
|
|
|
case SEGMENT:
|
|
|
|
sym->symu.segmnt.lnameIndex = lnameIndex++;
|
|
goto creatLname;
|
|
|
|
case CLASS:
|
|
|
|
sym->symu.ext.extIndex = lnameIndex++;
|
|
goto creatLname;
|
|
|
|
/* group indexs holds lname index temporary */
|
|
|
|
case GROUP:
|
|
sym->symu.grupe.groupIndex = lnameIndex++;
|
|
|
|
creatLname:
|
|
emitlname (sym);
|
|
}
|
|
|
|
if (sym->symkind == REGISTER)
|
|
sym->attr &= ~(M_PASSED);
|
|
else
|
|
sym->attr &= ~(M_PASSED | M_BACKREF);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*** scansegment - output segment names
|
|
*
|
|
* scansegment (sym);
|
|
*
|
|
* Entry *sym = segment symbol chain
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
VOID PASCAL
|
|
scansegment (
|
|
register SYMBOL FARSYM *sym
|
|
){
|
|
|
|
if (sym->symu.segmnt.align == (char)-1)
|
|
/* PARA default */
|
|
sym->symu.segmnt.align = 3;
|
|
|
|
if (sym->symu.segmnt.combine == 7)
|
|
/* Default no combine */
|
|
sym->symu.segmnt.combine = 0;
|
|
|
|
sym->symu.segmnt.lastseg = NULL;
|
|
|
|
/* Output segment def */
|
|
emitsegment (sym);
|
|
|
|
/* Clear Offset( current segment PC ) for pass 2 */
|
|
sym->offset = 0;
|
|
sym->symu.segmnt.seglen = 0;
|
|
}
|
|
|
|
|
|
/*** scangroup - output group names
|
|
*
|
|
* scangroup (sym);
|
|
*
|
|
* Entry *sym = group chain
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
SHORT PASCAL
|
|
scangroup (
|
|
SYMBOL FARSYM *sym
|
|
){
|
|
if (sym->symkind == GROUP)
|
|
emitgroup (sym);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*** scanextern - output external names
|
|
*
|
|
* scanextern (sym);
|
|
*
|
|
* Entry *sym = chain of external names
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
SHORT PASCAL
|
|
scanextern (
|
|
SYMBOL FARSYM *sym
|
|
){
|
|
if (M_XTERN & sym->attr)
|
|
emitextern (sym);
|
|
return 0;
|
|
}
|
|
|
|
/*** scanglobal - output global names
|
|
*
|
|
* scanglobal (sym);
|
|
*
|
|
* Entry *sym = chain of external names
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
SHORT PASCAL
|
|
scanglobal (
|
|
SYMBOL FARSYM *sym
|
|
){
|
|
if (M_GLOBAL & sym->attr)
|
|
emitglobal (sym);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*** dumpname - output module name
|
|
*
|
|
* dumpname ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
VOID PASCAL
|
|
dumpname ()
|
|
{
|
|
moduleflag = TRUE;
|
|
|
|
/* put file name instead of the usual */
|
|
|
|
emodule(createname(fname));
|
|
|
|
}
|
|
|
|
|
|
/*** showresults - display final assembly results
|
|
*
|
|
* showresults (fil, verbose, mbytes);
|
|
*
|
|
* Entry fil = file to print statistics to
|
|
* verbose = TRUE if all statistics to be displayed
|
|
* FALSE if only error messages to be displayed
|
|
* mbytes = number of free bytes in symbol space
|
|
* Exit statistics written to file
|
|
* Returns none
|
|
* Calls fprintf
|
|
*/
|
|
|
|
VOID PASCAL
|
|
showresults (
|
|
FILE *fil,
|
|
char verbose,
|
|
char *pFreeBytes
|
|
){
|
|
if (verbose) {
|
|
fprintf (fil, __NMSG_TEXT(ER_SOU), linessrc, linestot);
|
|
fprintf (fil, __NMSG_TEXT(ER_SY2), symbolcnt);
|
|
}
|
|
fputs (pFreeBytes, fil);
|
|
fprintf (fil, "%7hd%s\n%7hd%s\n",
|
|
warnnum, __NMSG_TEXT(ER_EM1),
|
|
errornum, __NMSG_TEXT(ER_EM2));
|
|
|
|
#ifdef BUF_STATS
|
|
if (verbose) {
|
|
|
|
extern long DEBUGtl, DEBUGlb, DEBUGbp, DEBUGbl, DEBUGcs, DEBUGca;
|
|
|
|
fprintf (fil, "\nTotal lines: %ld\n", DEBUGtl);
|
|
fprintf (fil, "Lines buffered: %ld\n", DEBUGlb);
|
|
fprintf (fil, "Stored as blank: %ld\n", DEBUGbl);
|
|
fprintf (fil, "Bad lbufp: %ld\n", DEBUGbp);
|
|
fprintf (fil, "Total Characters: %ld\n", DEBUGca);
|
|
fprintf (fil, "Characters buffered: %ld\n", DEBUGcs);
|
|
}
|
|
#endif
|
|
|
|
#ifdef EXPR_STATS
|
|
if (verbose) {
|
|
|
|
extern long cExpr, cHardExpr;
|
|
|
|
fprintf(fil, "\nTotal Expressions(%ld), Simple(%ld): %hd%%\n",
|
|
cExpr, cExpr - cHardExpr, (SHORT)((cExpr - cHardExpr)*100 / (cExpr+1)));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*** resetobjidx - reset listindex to correct column
|
|
*
|
|
* resetobjidx ();
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
resetobjidx ()
|
|
{
|
|
|
|
listindex = LSTDATA;
|
|
if (!emittext && duplevel)
|
|
listindex += 3 + ((duplevel <= 8)? duplevel: 8);
|
|
|
|
if (highWord(pcoffset)) /* check for 32 bit listing */
|
|
listindex += 4;
|
|
|
|
#ifdef BCBOPT
|
|
if (fNotStored)
|
|
storelinepb ();
|
|
#endif
|
|
|
|
listline ();
|
|
linebuffer[0] = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** copyascii - copy ASCII into list buffer
|
|
*
|
|
* copyascii ();
|
|
*
|
|
* Entry objectascii = data to be copied
|
|
* listindex = position for copy
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
copyascii ()
|
|
{
|
|
register char *p2;
|
|
register char *p1;
|
|
|
|
if (listindex >= LSTMAX)
|
|
resetobjidx ();
|
|
|
|
if (!fNeedList)
|
|
return;
|
|
|
|
for (p1 = listbuffer + listindex, p2 = objectascii; *p2; )
|
|
*p1++ = *p2++;
|
|
listindex = (char)(p1 - listbuffer);
|
|
}
|
|
|
|
|
|
|
|
/*** copystring - copy ASCII into list buffer
|
|
*
|
|
* copystring ();
|
|
*
|
|
* Entry objectascii = data to be copied
|
|
* listindex = position for copy
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
copystring (
|
|
register char *strng
|
|
){
|
|
register char *p1;
|
|
|
|
if (!fNeedList || fSkipList)
|
|
return;
|
|
|
|
goto firstTime;
|
|
while (*strng) {
|
|
|
|
*p1++ = *strng++;
|
|
|
|
if (*strng && ++listindex > LSTMAX + 2) {
|
|
|
|
resetobjidx ();
|
|
firstTime:
|
|
listindex = 3;
|
|
p1 = listbuffer + 3;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*** copytext - copy two characters to text line
|
|
*
|
|
* copytext (chrs)
|
|
*
|
|
* Entry
|
|
* Exit
|
|
* Returns
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
copytext (
|
|
char *chrs
|
|
){
|
|
if (listindex > LSTMAX+1)
|
|
resetobjidx ();
|
|
|
|
|
|
listbuffer[listindex++] = *chrs++;
|
|
listbuffer[listindex++] = *chrs;
|
|
}
|
|
|
|
|
|
|
|
/*** pcdisplay - display program counter
|
|
*
|
|
* pcdisplay();
|
|
*
|
|
* Entry pcoffset = value to display
|
|
* Exit hex or octal value of pc interted in list buffer
|
|
* Returns none
|
|
* Calls copyascii, wordascii
|
|
*/
|
|
|
|
VOID PASCAL CODESIZE
|
|
pcdisplay ()
|
|
{
|
|
|
|
listindex = 1;
|
|
if (!fNeedList)
|
|
return;
|
|
|
|
offsetAscii (pcoffset);
|
|
|
|
copyascii ();
|
|
listindex = LSTDATA;
|
|
|
|
if (objectascii[4]) /* was a 32bit number */
|
|
listindex += 4;
|
|
}
|
|
|
|
|
|
|
|
/*** opdisplay - display program counter and opcode
|
|
*
|
|
* opdisplay(v);
|
|
*
|
|
* Entry v = opcode to display
|
|
* Exit none
|
|
* Returns none
|
|
* Calls
|
|
*/
|
|
|
|
|
|
VOID PASCAL CODESIZE
|
|
opdisplay (
|
|
UCHAR v
|
|
){
|
|
if (!fNeedList)
|
|
return;
|
|
|
|
if (listindex == 1)
|
|
pcdisplay ();
|
|
|
|
objectascii[1] = hexchar[v & 0xf];
|
|
objectascii[0] = hexchar[v >> 4];
|
|
objectascii[2] = 0;
|
|
|
|
copyascii ();
|
|
|
|
listindex++;
|
|
}
|
|
|
|
|
|
#ifndef M8086OPT
|
|
|
|
/*** inset - check for value in a set of values
|
|
*
|
|
* flag = inset (val, set);
|
|
*
|
|
* Entry val = value to check
|
|
* set = array of values to check for
|
|
* set[0] = number of entries in set
|
|
* Exit none
|
|
* Returns TRUE if val is in set
|
|
* FALSE if val is not in set
|
|
* Calls
|
|
*/
|
|
|
|
char CODESIZE
|
|
inset (
|
|
register char v,
|
|
char *s
|
|
){
|
|
register USHORT i;
|
|
register char *p;
|
|
|
|
for (i = *s, p = ++s; i; i--)
|
|
if (v == *p++)
|
|
return (TRUE);
|
|
return (FALSE);
|
|
}
|
|
|
|
#endif /* M8086OPT */
|
|
|
|
|
|
/*** outofmem - issue an out of memory error message
|
|
*
|
|
* outofmem (text);
|
|
*
|
|
* Entry *text = text to append to message
|
|
* Exit doesn't
|
|
* Returns none
|
|
* Calls endblk, parse
|
|
* Note if not end of PROC, parse line as normal. Otherwise,
|
|
* terminate block.
|
|
*/
|
|
|
|
VOID PASCAL
|
|
outofmem ()
|
|
{
|
|
closeOpenFiles();
|
|
terminate((SHORT)((EX_MEME<<12) | ER_MEM), pFCBCur->fname, (char *)errorlineno, NULL );
|
|
}
|
|
|
|
SHORT PASCAL CODESIZE
|
|
tokenIS(
|
|
char *pLiteral
|
|
){
|
|
return(_stricmp(naim.pszName, pLiteral) == 0);
|
|
}
|
|
|
|
#ifdef M8086
|
|
|
|
/*** strnfcpy - copy string to near buffer
|
|
*
|
|
* strnfcpy (dest, src);
|
|
*
|
|
* Entry dest = pointer to near buffer
|
|
* src = pointer to far source buffer
|
|
* Exit source copied to destination
|
|
* Returns none
|
|
* Calls none
|
|
*/
|
|
|
|
VOID PASCAL
|
|
strnfcpy (
|
|
register char *dest,
|
|
register char FAR *src
|
|
){
|
|
while(*src)
|
|
*dest++ = *src++;
|
|
|
|
*dest = NULL;
|
|
|
|
}
|
|
|
|
|
|
/*** strflen - compute length of far buffer
|
|
*
|
|
* strnflen (s1);
|
|
*
|
|
* Entry s1 = pointer to far buffer
|
|
* Exit none
|
|
* Returns number of characters in buffer
|
|
* Calls none
|
|
*/
|
|
|
|
USHORT PASCAL
|
|
strflen (
|
|
register char FAR *s1
|
|
){
|
|
register USHORT i = 0;
|
|
|
|
while (*s1++)
|
|
i++;
|
|
return(i);
|
|
}
|
|
|
|
#endif /* M8086 */
|