Windows-Server-2003/sdktools/masm/asmlst.c

1212 lines
20 KiB
C

/* asmlst.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 "asmmsg.h"
#define setpassed(sym) (sym)->attr |= (M_PASSED)
VOID PASCAL CODESIZE listPuts(char *);
#ifdef BCBOPT
extern UCHAR fNoCompact;
#endif
char fBigNum;
/* size names */
static char byte[] = "BYTE";
static char word[] = "WORD";
static char dword[] = "DWORD";
static char none[] = "NONE";
char hexchar[] = "0123456789ABCDEF";
char *siznm[] = {
0,
byte,
word,
0,
dword,
0,
"FWORD",
0,
"QWORD",
0,
"TBYTE",
"NEAR",
"FAR",
};
char *alignName[] = {
"AT",
byte,
word,
"PARA",
"PAGE",
dword
};
char *combineName[] = {
none,
"MEMORY", /* Memory is mapped to PUBLIC in fnspar */
"PUBLIC",
0,
0,
"STACK",
"COMMON",
none
};
char headSegment[] = "Segments and Groups:";
static char *head1[] = {
headSegment,
"Symbols: ",
headSegment
};
char headSeg[] = "\tSize\tLength\t Align\tCombine Class";
static char *head2[] = {
&headSeg[5],
"\tType\t Value\t Attr",
headSeg
};
/*** offsetAscii - display dword in hex
*
* offsetAscii(v);
*
* Entry v = dword to be displayed
* Exit objectascii = converted value of v zero terminated
* Returns none
* Calls
*/
VOID PASCAL
offsetAscii (
OFFSET v
){
register USHORT t;
register char *p = objectascii;
#ifdef V386
if (highWord(v)) {
t = highWord(v);
p[3] = hexchar[t & 15];
t >>= 4;
p[2] = hexchar[t & 15];
t >>= 4;
p[1] = hexchar[t & 15];
t >>= 4;
p[0] = hexchar[t & 15];
p += 4;
}
#endif
p[4] = 0;
t = (USHORT)v;
p[3] = hexchar[t & 15];
t >>= 4;
p[2] = hexchar[t & 15];
t >>= 4;
p[1] = hexchar[t & 15];
p[0] = hexchar[(t >> 4) & 15];
}
/*** dispsym - display symbol
*
* routine ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
dispsym (
USHORT indent,
SYMBOL FARSYM *sym
){
register char *p = listbuffer;
strcpy (p, " . . . . . . . . . . . . . . . . \t");
while (indent--)
*p++ = ' ';
if (caseflag == CASEX && (sym->attr & (M_GLOBAL | M_XTERN)))
strcpy (p, sym->lcnamp->id);
else
STRNFCPY (p, sym->nampnt->id);
p[STRFLEN (sym->nampnt->id)] = ' ';
listPuts (listbuffer);
}
/*** dispword - display word value in current radix
*
* dispword (v);
*
* Entry v = value to display
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
dispword (
OFFSET v
){
/* Convert value to text */
offsetAscii (v);
if (symptr->symkind == EQU && symptr->symu.equ.equrec.expr.esign)
listPuts ("-");
listPuts(objectascii);
fBigNum = objectascii[4]; /* remember if you put a 8 digit # */
}
/*** chkheading - display heading if needed
*
* chkheading (code);
*
* Entry code = index to heading to be printed
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
chkheading (
USHORT code
){
if (!listed && lsting) {
if (pagelength - pageline < 8)
pageheader ();
else
skipline ();
listPuts (head1[code]);
skipline ();
skipline ();
listPuts(" N a m e ");
listPuts(head2[code]);
skipline ();
skipline ();
listed = TRUE;
}
}
/*** disptab - output tab character to listing
*
* disptab ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
disptab ()
{
putc ((fBigNum)? ' ': '\t', lst.fil);
fBigNum = FALSE;
}
/*** skipline - output blank line
*
* skipline ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
skipline ()
{
fputs(NLINE, lst.fil);
bumpline ();
}
/*** bumpline - bump line count
*
* bumpline ();
*
* Entry pageline = current line number
* pagelength = number of lines per page
* Exit pageline incremented
* new page started if pageline > pagelength
* Returns none
* Calls pageheader
*/
VOID PASCAL
bumpline ()
{
pageline++;
if (pagelength <= pageline)
pageheader ();
}
/*** newpage - start newpage
*
* newpage ();
*
* Entry none
* Exit pagemajor incremented
* pageminor = 0
* pageline set to pagelength - 1
* Returns none
* Calls none
*/
VOID PASCAL
newpage ()
{
pagemajor++;
pageminor = 0;
pageline = pagelength - 1;
}
/*** pageheader - output page header
*
* pageheader ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL
pageheader ()
{
if (lsting) {
pageminor++;
pageline = 4;
#if defined MSDOS && !defined FLATMODEL
atime[20] = '\0'; /* get rid of '\n' */
#else
atime[24] = '\0'; /* get rid of '\n' */
#endif
fprintf (lst.fil, "\f\b%s%s" NLINE "%s", titlefn, atime + 4, titlebuf);
if (pagemajor == 0)
listPuts("Symbols");
else {
fprintf (lst.fil, "Page %5hd", pagemajor);
}
if (pageminor)
fprintf (lst.fil, "-%hd", pageminor);
fprintf (lst.fil, NLINE "%s" NLINE NLINE, subttlbuf);
}
}
/*** testlist - test for listing of line
*
* testlist ()
*
* Entry
* Exit
* Returns
* Calls
*/
UCHAR PASCAL CODESIZE
testlist ()
{
if (fPass1Err)
/* list pass 1 errors regardless of listing status */
return (TRUE);
if (pass2 || debug) {
if (errorcode)
/* list error in pass 2 regardless of listing status */
return (TRUE);
if (fSkipList) {
fSkipList = FALSE;
return (FALSE);
}
if (loption)
return (TRUE);
/* list line in pass 1 or pass 2 if listing enabled */
if (listflag &&
(generate || condflag) &&
(!macrolevel ||
expandflag == LIST ||
!(expandflag == SUPPRESS ||
expandflag == LISTGEN &&
(listbuffer[1] == '=' || listbuffer[1] == ' ') &&
handler != HSTRUC)) )
return (TRUE);
}
return (FALSE);
}
/*** listline - list line on device for user
*
* listline ();
*
* Entry listbuffer = object part of line
* linebuffer = source line
* crefcount = cross reference line count
* Exit crefcount incremented
* Returns none
* Calls
*/
VOID PASCAL
listline ()
{
register char *p;
char *q;
char *r;
register SHORT i;
register SHORT j;
register SHORT k;
#ifdef BCBOPT
if (errorcode)
goodlbufp = FALSE;
#endif
crefline ();
if (testlist ()) {
if (listconsole || lsting) {
p = listbuffer + LISTMAX - 3;
#ifdef FEATURE
#ifdef BCBOPT
if (fNoCompact)
#endif
*p++ = '\\';
else {
if (pFCBCur->pFCBParent)
*p++ = 'C';
if (macrolevel)
*p = (macrolevel > 9)? '+': '0' + macrolevel;
}
#else
if (pFCBCur->pFCBParent)
p[0] = 'C';
#ifdef BCBOPT
if (fNoCompact && *linebuffer)
#else
if (*linebuffer)
#endif
p[1] = '\\';
else if (macrolevel)
p[1] = (macrolevel > 9)? '+': '0' + macrolevel;
#endif
listbuffer [LISTMAX] = 0;
}
if (lsting) {
bumpline ();
k = LISTMAX;
/** Put out line # * */
if (pass2 && crefing == CREF_SINGLE) {
fprintf (lst.fil, "%8hd", crefcount+crefinc);
k += 8;
}
p = listbuffer;
while (!memcmp(p," ",8)) { /* leading tabs */
putc('\t',lst.fil);
p += 8;
}
q = r = p + strlen(p) - 1; /* last char of p */
if (q >= p && *q == ' ') {
/* coalesce end spaces to tabs */
while (q != p && *(q - 1) == ' ')
/* gather spaces */
q--;
/* now q points at the first trailing space and
* r points at the last trailing space */
*q = '\0';
listPuts(p);
*q = ' ';
i = (short)((q - p) & 7); /* residual = strlen MOD 8 */
j = 8 - i; /* filler to next tab stop */
if (j != 8 && j <= (r - q + 1)) {
putc('\t',lst.fil);
q += j;
}
while (r >= q + 7) {
putc('\t',lst.fil);
q += 8;
}
while (r >= q++)
putc(' ',lst.fil);
}
else
listPuts(p);
p = linebuffer;
i = k; /* number of columns already put out */
while (*p) {
while (*p && i < pagewidth) {
if (*p == '\t') {
if ((i = (((i+8)>>3)<<3))
>= pagewidth)
/* won't fit */
break;
}
else
i++;
putc(*p, lst.fil );
p++;
}
if (*p) {
skipline ();
listPuts ( pass2 && crefing == CREF_SINGLE ?
"\t\t\t\t\t" : "\t\t\t\t");
i = k;
}
}
fputs(NLINE, lst.fil);
}
crefinc++;
if (errorcode) {
if (listconsole)
/* display line */
fprintf (ERRFILE,"%s%s\n", listbuffer, linebuffer);
errordisplay ();
}
}
if (fNeedList)
memset(listbuffer, ' ', LISTMAX);
errorcode = 0;
fPass1Err = 0;
}
/*** storetitle - copy text of line to title buffer
*
* storetitle (buf)
*
* Entry buf = pointer to buffer to hold title
* Exit up to TITLEWIDTH - 1 characters move to *buf* and *buf* blank
* filled and zero terminated
* Returns none
* Calls none
*/
VOID PASCAL
storetitle (
register char *buf
){
register SHORT L_count = 0;
for (; (L_count < TITLEWIDTH - 1); L_count++) {
if (PEEKC () == 0)
break;
else
*buf++ = NEXTC ();
}
/* skip to end of title */
while (PEEKC ())
SKIPC ();
/* blank fill buffer */
for (; L_count < TITLEWIDTH - 1; L_count++)
*buf++ = ' ';
*buf = 0;
}
/*** displength - display value as LENGTH = value
*
* displength (v);
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
displength (
OFFSET v
){
offsetAscii (v);
listPuts("\tLength = ");
listPuts(objectascii);
}
/*** dispdatasize - display data size
*
* dispdatasize (sym);
*
* Entry *sym = symbol
* Exit
* Returns
* Calls
*/
VOID PASCAL
dispdatasize (
SYMBOL FARSYM *sym
){
register USHORT idx;
idx = sym->symtype;
if (idx == CLABEL && sym->symu.clabel.type > 514)
dispword((OFFSET) idx);
else{
if (idx == CSFAR)
idx = 12;
else if (idx == CSNEAR)
idx = 11;
else if (idx > 10 || siznm[idx] == NULL){
return;
}
listPuts(siznm[idx]);
}
}
/*** listopen - list blocks open at end of pass
*
* listopen ();
*
* Entry
* Exit
* Returns
* Calls
* Note Format is:
* Open segments: <list>
* Open procedures: <list>
* Open conditionals: <n>
*/
VOID PASCAL
listopen ()
{
SYMBOL FARSYM *sym;
if (pcsegment) {
if (!listquiet)
fprintf (ERRFILE,"%s:", __NMSG_TEXT(ER_SEG));
if (lsting) {
fprintf (lst.fil, "%s:", __NMSG_TEXT(ER_SEG));
bumpline ();
skipline ();
}
sym = pcsegment;
while (sym) {
/* Count as an error */
if (pass2)
errornum++;
if (lsting) {
dispsym (0, sym);
skipline ();
}
if (!listquiet) {
STRNFCPY (save, sym->nampnt->id);
fprintf (ERRFILE," %s", save);
}
/* Point to previous seg */
sym = sym->symu.segmnt.lastseg;
}
if (!listquiet)
fprintf (ERRFILE,"\n");
}
if (iProcStack > 0) {
if (!listquiet)
fprintf (ERRFILE,"%s:", __NMSG_TEXT(ER_PRO));
if (lsting) {
fprintf (lst.fil, "%s:", __NMSG_TEXT(ER_PRO));
bumpline ();
skipline ();
}
while (iProcStack > 0) {
sym = procStack[iProcStack--];
/* Count as an error */
if (pass2)
errornum++;
if (lsting) {
dispsym (0, sym);
skipline ();
}
if (!listquiet) {
STRNFCPY (save, sym->nampnt->id);
fprintf (ERRFILE," %s", save);
}
}
if (!listquiet)
fprintf (ERRFILE,"\n");
}
if (condlevel) {
/* Count as an error */
if (pass2)
errornum++;
if (!listquiet)
fprintf (ERRFILE,"%s%hd\n", __NMSG_TEXT(ER_CON), condlevel);
if (lsting) {
fprintf (lst.fil, "%s%hd" NLINE, __NMSG_TEXT(ER_CON), condlevel);
bumpline ();
}
}
}
/*** symbollist - list symbol
*
* symbollist (sym)
*
* Entry *sym = symbol
* Exit count = number of symbols listed
* Returns
* Calls
*/
VOID PASCAL
symbollist ()
{
SYMBOL FARSYM *sym;
SHORT i;
listed = FALSE;
for (i = 0; i < MAXCHR; i++) {
count = 0;
for(sym = symroot[i]; sym; sym = sym->alpha)
if (!((M_NOCREF|M_PASSED) & sym->attr)) {
symptr = sym;
count++;
chkheading (1);
setpassed (sym);
dispsym (0, sym);
dispstandard (sym);
if (sym->symkind == PROC)
displength ((OFFSET) sym->symu.plabel.proclen);
else if (sym->length != 1 &&
(sym->symkind == DVAR || sym->symkind == CLABEL))
displength ((OFFSET) sym->length);
skipline ();
}
if (count)
skipline ();
}
}
/*** dispstandard - display standard
*
* dispstandard ();
*
* Entry
* Exit
* Returns
* Calls
* Note Format is:
* PROC: N/F PROC offset Segment
* CLABEL L NEAR|FAR offset Segment
* DVAR V SIZE offset Segment
* REGISTR REG name
*/
VOID PASCAL CODESIZE
dispstandard (
SYMBOL FARSYM *sym
){
NAME FAR *tp;
register SHORT width;
SHORT cbTM;
switch (sym->symkind) {
case PROC:
if (sym->symtype == CSNEAR)
listPuts("N PROC");
else
listPuts("F PROC");
break;
case CLABEL:
if (sym->symtype == CSNEAR)
listPuts("L NEAR");
else if (sym->symtype == CSFAR)
listPuts("L FAR ");
else {
fprintf (lst.fil, "L ");
dispdatasize (sym);
}
break;
case DVAR:
/* Data associated label */
listPuts("V ");
/**Display keyword or size * */
dispdatasize (sym);
break;
case REGISTER:
listPuts("REG ");
break;
case EQU:
if (sym->symu.equ.equtyp == EXPR)
if (sym->symtype == 0)
listPuts("NUMBER");
else
dispdatasize (sym);
else if (sym->symu.equ.equtyp == ALIAS) {
if (sym->symu.equ.equrec.alias.equptr)
tp = sym->symu.equ.equrec.alias.equptr->nampnt;
else
tp = NULL;
listPuts("ALIAS\t ");
if (tp) {
STRNFCPY (save, tp->id);
listPuts(save);
}
} else {
listPuts("TEXT ");
cbTM = (SHORT) strlen(sym->symu.equ.equrec.txtmacro.equtext);
width = pagewidth - 46;
while (cbTM > width) {
memcpy(save, sym->symu.equ.equrec.txtmacro.equtext,
width);
save[width] = 0;
listPuts(save);
skipline ();
listPuts("\t\t\t\t\t ");
sym->symu.equ.equrec.txtmacro.equtext += width;
cbTM -= width;
}
listPuts(sym->symu.equ.equrec.txtmacro.equtext);
}
break;
}
disptab ();
if ((sym->symkind != EQU) || (sym->symu.equ.equtyp == EXPR))
if (sym->symkind != REGISTER)
dispword (((sym->attr & M_XTERN) && sym->offset)?
(OFFSET) sym->length * sym->symtype:
sym->offset);
else {
STRNFCPY (save, sym->nampnt->id);
listPuts(save);
}
disptab ();
if (sym->symsegptr) {
STRNFCPY (save, sym->symsegptr->nampnt->id);
listPuts(save);
}
if (M_XTERN & sym->attr)
listPuts((sym->symu.ext.commFlag)? "\tCommunal": "\tExternal");
if (M_GLOBAL & sym->attr)
listPuts("\tGlobal");
}
/*** macrolist - list macro names and lengths
*
* macrolist (sym);
*
* Entry *sym = macro symbol entry
* Exit
* Returns
* Calls
*/
SHORT PASCAL
macrolist (
SYMBOL FARSYM *sym
){
SHORT i;
TEXTSTR FAR *p;
if (!(M_NOCREF & sym->attr)) {
if (!listed) {
listed = TRUE;
/* # on line is 1 */
skipline ();
listPuts("Macros:");
/** Display header * */
skipline ();
skipline ();
listPuts("\t\tN a m e\t\t\tLines");
skipline ();
skipline ();
}
/* Display name of macro */
dispsym (0, sym);
for (i = 0, p = sym->symu.rsmsym.rsmtype.rsmmac.macrotext; p; p = p->strnext, i++)
;
fprintf (lst.fil, "%4hd", i);
skipline ();
setpassed (sym);
}
return 0;
}
/*** struclist - display structure and record names
*
* struclist (sym);
*
* Entry *sym = symbol
* Exit
* Returns
* Calls
* Note Format is:
* <structure name> <length> <# fields>
* <field name> <offset>
* Or
* <Record name> <width> <# fields>
* <Field name> <offset> <width> <mask> <init>
*/
SHORT PASCAL
struclist (
SYMBOL FARSYM *sym
){
char f32bit;
if (!(M_NOCREF & sym->attr)) {
if (!listed) {
listed = TRUE;
if (pagelength - pageline < 8)
pageheader ();
else
skipline ();
listPuts("Structures and Records:");
skipline ();
skipline ();
listPuts(" N a m e Width # fields");
skipline ();
listPuts(" Shift Width Mask Initial");
skipline ();
skipline ();
}
setpassed (sym);
/* Display name */
dispsym (0, sym);
if (sym->symkind == REC) {
/* # bits in record */
dispword ((OFFSET) sym->length);
disptab ();
/* # of fields */
dispword ((OFFSET) sym->symu.rsmsym.rsmtype.rsmrec.recfldnum);
}
else {
/* Length of structure */
dispword ((OFFSET) sym->symtype);
disptab ();
/* # of fields */
dispword ((OFFSET) sym->symu.rsmsym.rsmtype.rsmstruc.strucfldnum);
}
skipline ();
if (sym->symkind == REC) {
#ifdef V386
f32bit = (symptr->length > 16);
#endif
/* Point to 1st rec */
symptr = symptr->symu.rsmsym.rsmtype.rsmrec.reclist;
while (symptr) {
dispsym (2, symptr);
/* Shift count */
dispword (symptr->offset);
disptab ();
/* Width */
dispword ((OFFSET) symptr->symu.rec.recwid);
disptab ();
/* Mask */
#ifdef V386
if (f32bit && symptr->symu.rec.recmsk <= 0xffff)
dispword((OFFSET) 0);
#endif
dispword (symptr->symu.rec.recmsk);
disptab ();
/* Initial value */
#ifdef V386
if (f32bit && symptr->symu.rec.recinit <= 0xffff)
dispword((OFFSET) 0);
#endif
dispword (symptr->symu.rec.recinit);
skipline ();
setpassed (sym);
symptr = symptr->symu.rec.recnxt;
}
}
else {
/* Point to 1st field */
symptr = symptr->symu.rsmsym.rsmtype.rsmstruc.struclist;
while (symptr) {
dispsym (2, symptr);
/* offset from start */
dispword (symptr->offset);
skipline ();
setpassed (symptr);
symptr = symptr->symu.struk.strucnxt;
}
}
}
return 0;
}
/* output a string to the listing file */
VOID PASCAL CODESIZE
listPuts(
char *pString
){
fputs(pString, lst.fil);
}
/*** segdisplay - display segment name, size, align, combine and class
*
* segdisplay ();
*
* Entry
* Exit
* Returns
* Calls
*/
VOID PASCAL CODESIZE
segdisplay (
USHORT indent,
SYMBOL FARSYM *sym
){
dispsym (indent, sym);
#ifdef V386
if (f386already){
listPuts((sym->symu.segmnt.use32 == 4)? "32": "16");
listPuts(" Bit\t");
}
#endif
/* Length of segment */
dispword (sym->symu.segmnt.seglen);
disptab ();
listPuts (alignName[sym->symu.segmnt.align]);
disptab ();
if (sym->symu.segmnt.align == 0 && sym->symu.segmnt.combine == 0)
dispword ((OFFSET) sym->symu.segmnt.locate);
else
listPuts (combineName[sym->symu.segmnt.combine]);
disptab ();
if (sym->symu.segmnt.classptr) {
/* Have class name */
setpassed (sym->symu.segmnt.classptr);
#ifdef XENIX286
fputc('\'', lst.fil);
farPuts(lst.fil, sym->symu.segmnt.classptr->nampnt->id);
fputc('\'', lst.fil);
#else
# ifdef FLATMODEL
fprintf (lst.fil, "\'%s\'",
# else
fprintf (lst.fil, "\'%Fs\'",
# endif
sym->symu.segmnt.classptr->nampnt->id);
#endif
}
setpassed (sym);
skipline ();
}
/*** seglist - list segment
*
* seglist (sym);
*
* Entry
* Exit
* Returns
* Calls
* Note Format is:
* <Group name> <# segments>
* <segment> <size> <align> <combine> <class>
* Or
* <segment> <size> <align> <combine> <class>
*/
VOID PASCAL
seglist ()
{
SYMBOL FARSYM *sym;
SHORT i;
listed = FALSE;
for (i = 0; i < MAXCHR; i++) {
for(sym = symroot[i]; sym; sym = sym->alpha)
if (1 << sym->symkind & (M_SEGMENT | M_GROUP) &&
!((M_NOCREF|M_PASSED) & sym->attr)) {
#ifdef V386
chkheading ((USHORT) ((f386already)? 2: 0) );
#else
chkheading (0);
#endif
symptr = sym;
setpassed (sym);
if (sym->symkind == SEGMENT) {
if (!sym->symu.segmnt.grouptr)
/*Display segment */
segdisplay (0, sym);
}
else {
/* Display group name */
dispsym (0, sym);
listPuts ("GROUP" NLINE);
bumpline ();
bumpline ();
/* Point to 1st seg */
symptr = sym->symu.grupe.segptr;
while (symptr) {
segdisplay (2, symptr);
symptr = symptr->symu.segmnt.nxtseg;
}
}
}
}
}