📄 ccout.c
字号:
{
outstr ("\tEXTERN\t");
outstr (crtsnam[i]);
outnl ();
}
}
outdecl (); /* Output user-defined INTERN and EXTERNs */
/* Finally, output entry vector if any */
makprefile (); /* KAR-2/92, added to output entry pts in .MAC file */
if (module_pragma)
outstr ("\tPRGEND");
else
outstr ("\tEND");
if (mainf)
outstr ("\t<3,,$$STRT>"); /* 3 wds in entry vector */
outnl ();
outnl ();
}
/* OUTDECL - Output assembler external & internal declarations at end
** of compiling a module (translation unit).
*/
static int
outdecl (void)
{
SYMBOL *s = symbol; /* Start of global sym list */
int num = 0;
while ((s = s->Snext) != NULL)
{
switch (s->Sclass)
{
default:
continue;
case SC_EXTDEF: /* External linkage sym defined */
continue;
case SC_EXTREF: /* External linkage sym referenced */
case SC_XEXTREF:
/* Symbol not defined. Ask for it if needed */
if (s->Srefs == 0) /* If never used, don't ask. */
{
if (!delete) /* If keeping asm file, */
outc (';'); /* output it as a comment. */
else
continue; /* Otherwise just ignore */
}
outstr ("\tEXTERN\t");
break;
}
outmiref (s);
outnl ();
}
return num;
}
/* MAKPREFILE - determines whether a prefix assembler file is needed
** and creates it if so. Returns non-zero if one was created.
*/
int
makprefile (void)
{
SYMBOL *sym;
int nexfs = 0;
/* Scan symbol table to see if there are any names
** we should export as library entry points.
*/
for (sym = symbol; (sym = sym->Snext) != NULL;)
if (sym->Sclass == SC_EXTDEF) /* An external definition? */
break; /* Yup */
if (sym == NULL)
return 0; /* If none, just return */
/* OK, now output entry statements for the exportable symbols */
do
{
if (sym->Sclass == SC_EXTDEF) /* For each external def */
{
if ((nexfs % 5) == 0)
outstr ("\n\tENTRY ");
else
outc (',');
outmiref (sym);
++nexfs;
}
sym = sym->Snext;
}
while (sym)
;
outnl ();
return (nexfs);
}
/*
** KCC Assembler Header output
**
** This section contains the code required to generate the assembler header
** text that KCC puts at the beginning of all its assembler
** output files, just after any ENTRY or TITLE statements, and before
** any generated code.
**
** The header for both FAIL and MACRO is identical.
** However, MIDAS requires a somewhat different syntax.
*/
/* OUTASMH - Output assembler header file.
**
** Copy Assembler Header File from its default or user-specified location.
** This should end up in the code segment, and supply macros
** %%CODE and %%DATA for switching between the two.
*/
static
char* asmhdr = NULL;
static
void
outasmh (void)
{
FILE* hdrf;
register
int c;
/* If user explicitly specified an assembler header file, use it. */
if (asmhfile)
{
if ((hdrf = fopen (asmhfile, "r")) == NULL) /* open file */
errfopen ("preamble", asmhfile); /* no luck, give up */
else
{
while ((c = getc (hdrf)) != EOF)
outc (c); /* copy file */
if (ferror (hdrf) || !feof (hdrf))
jerr ("I/O error while reading preamble \"%s\"", asmhfile);
fclose (hdrf);
return;
}
}
/* No file specified, or couldn't open. Use self-generated header. */
outstr (asmhdr ? asmhdr : ahmacs ()); /* Make or use existing */
}
/* Segmentation macros. See codeseg () and dataseg () for more comments. */
static char segfai[] = "\
DEFINE %%CODE <RELOC>\n\
DEFINE %%DATA <RELOC>\n\n\
TWOSEG 400000 \n\
RELOC 0 \n\
RELOC 400000 \n";
static char segkdb[] = "\
DEFINE %%CODE <RELOC>\n\
DEFINE %%DATA <RELOC>\n\n\
EXTERN KD$DLD \n\
TWOSEG 400000 \n\
LOC 041 \n\
PUSHJ 17,KD$DLD\n\
RELOC 0 \n\
RELOC 400000 \n";
static char segfnp[] = "\
DEFINE %%CODE <RELOC>\n\
DEFINE %%DATA <RELOC>\n\n\
EXTERN KD$FPL \n\
TWOSEG 400000 \n\
LOC 041 \n\
PUSHJ 17,KD$FPL\n\
RELOC 0 \n\
RELOC 400000 \n";
static char segsp[] = "\
DEFINE %%CODE <RELOC>\n\
DEFINE %%DATA <RELOC>\n\n\
EXTERN KD$SPL \n\
TWOSEG 400000 \n\
LOC 041 \n\
PUSHJ 17,KD$SPL\n\
RELOC 0 \n\
RELOC 400000 \n";
static char *
ahmacs (void)
{
register char *cp;
char *beg;
int size;
/* To construct the possibly large header string, we steal space
** by re-using the pcode buffer temporarily. Check when done to ensure
** it wasn't overflowed!
*/
beg = cp = (char *)codes;
if (profbliss) /* profiling switch for CSI */
cp = estrcpy (cp, "\t.REQUIRE BLI:PROFIL.REL\n");
/*
* KAR-1/92, advent of library version of KCCDBG.REL caused this code to
* be changed so that any value of debcsi requests KCCDBG.REL.
* I removed the #if __MSDOS__ because the code needs to always execute.
*/
else
switch (abs (debcsi)) /* debugging switch for CSI */
{
case 0 :
break;
case KCC_DBG_SDBG :
case KCC_DBG_FDBG : /* FW 2A (42) PPS4575 */
case KCC_DBG_SPRF :
case KCC_DBG_FPRF :
case KCC_DBG_NULL :
cp = estrcpy (cp, "\t.REQUEST SYS:KCCDBG.REL\n");
break;
default:
int_error ("ahmacs: invalid debcsi %d", debcsi);
}
/*
* Make request for standard C library.
* Eventually flush this request and rely on KCC linker invocation.
*/
cp = estrcpy (fstrcpy (estrcpy (cp, "\t.REQUEST "), libpath, "c"), "\n");
sprintf (cp,"\t$$CVER==:<%o,,%o>\n",
cvercode, cverlib);
cp += strlen (cp); /* Sigh, update ptr */
/* Add machine-dependent macro definitions */
if (profbliss) /* added 09/15/89 by MVS */
cp = estrcpy (cp, "\tOPDEF\tPROF. [37B8]\n");
if (debcsi) /* source debugger UUO's */
{
cp = estrcpy (cp, "\tOPDEF\tDEBUGP [37B8]\n");
cp = estrcpy (cp, "\tOPDEF\tDEBUGS [37B8]\n");
cp = estrcpy (cp, "\tOPDEF\tDEBUGE [37B8]\n");
}
/*
* Try to purge MACRO pseudo-ops that we'll never need and that
* may conflict with user-defined syms.
*/
cp = estrcpy (cp, "\
PURGE IFE,IFN,IFG,IFGE,IFL,IFLE,IFDEF,IFNDEF,IFIDN,IFDIF\n\n");
/* Code and data segmentation setup and %%DATA/%%CODE macro definition */
switch (debcsi)
{
case 0 : /* no debugger or profiler */
default :
cp = estrcpy (cp, segfai);
break;
case KCC_DBG_SDBG : /* source-level debugger */
case KCC_DBG_FDBG : /* FW 2A (42) PPS4575 */
cp = estrcpy (cp, segkdb);
break;
case KCC_DBG_SPRF : /* statement profiler */
cp = estrcpy (cp, segsp);
break;
case KCC_DBG_FPRF : /* function profiler */
cp = estrcpy (cp, segfnp);
break;
}
if (mlist)
cp = estrcpy (cp, "\n\tSP=17");
if ((!delete) || mlist)
cp = estrcpy (cp, "\n;\t*** User code begins here ***\n");
size = strlen (beg) + 1; /* Find size of entire header */
if (size > sizeof (codes)) /* Paranoia check */
fatal ("Assembler header table overflow");
if ((asmhdr = calloc (1, size)) != NULL) /* Now try to relocate it */
{
strcpy (asmhdr, beg); /* Won, copy header to save it! */
return asmhdr;
}
return beg; /* No luck, just re-generate each time */
}
static char *
ahmacdef (char *cp, char **macro)
{
cp = estrcpy (estrcpy (estrcpy (cp,"\tDEFINE "),macro[0]),
" (A,M)\n\t<");
while (*++macro)
cp = estrcpy (estrcpy (estrcpy (cp, "\t"), *macro), "\n");
cp = estrcpy (cp, "\t>\n");
return cp;
}
/*
** Data segmentation.
**
** KCC emits code in two sections: code and data. The header sets things up
** so that code and data are in the high and low segments, which typically
** correspond to the high and low halves of their section but which can be
** rearranged by the appropriate LINK directives.
**
** Code and data are separated in the assembly output by the %%CODE and %%DATA
** macros. %%CODE will never be called from any context other than the data
** segment, and vice versa. KCC expects the header to initially be in code.
**
** During code generation, codeseg () and dataseg () are used to switch
** between the two segments.
*/
/* CODESEG - Start using code (pure) segment
*/
int
codeseg (void)
{
int oseg;
if ((oseg = whichseg) < 0) /* if in data */
{
outstr ("\n\t%%CODE\n"); /* put in code instead */
#if SYS_CSI
if (mlist)
oline += 2;
#endif
whichseg = 1; /* and remember in code */
}
return oseg;
}
/* DATASEG - Start using data (impure) segment
*/
int
dataseg (void)
{
int oseg;
if ((oseg = whichseg) > 0) /* if in code */
{
outstr ("\n\t%%DATA\n"); /* put in data instead */
#if SYS_CSI
if (mlist)
oline += 2;
#endif
whichseg = -1; /* and remember in data */
}
return oseg;
}
/* PREVSEG - restore to previous segment
*/
int
prevseg (int seg)
{
return (seg < 0) ? dataseg () : codeseg ();
}
/* REALCODE (p) - Generate real code for given pseudo-instruction.
** This is the primary assembler output function.
*/
void
realcode (PCODE *p)
{
int i, typ;
typ = (p->Ptype &~ PTF_SKIPPED); /* Get sanitized addressing type */
switch (p->Pop & POF_OPCODE)
{
case P_NOP: /* Ignore deleted pseudo-code */
return;
/* Handle the various simulated ops, which do not correspond
** directly to a real PDP-10 instruction.
*/
case P_PTRCNV:
simptrcnv (p);
return; /* "Pointer Conversion" */
case P_SMOVE:
simsmove (p);
return; /* "Structure Move" */
case P_UFLTR:
simufltr (p);
return; /* "Unsigned Float & Round" */
case P_UIDIV:
simuidiv (p);
return; /* "Unsigned Integer Divide" */
case P_SUBBP:
simsubbp (p);
return; /* "Subtract Byte Pointer" */
case P_DFIX:
simdfix (p);
return; /* "Double Fix" */
case P_DSNGL:
simdsngl (p);
return; /* "Double to Single" */
/* End of simulated ops; switch continued on next page! */
/* Switch continued from previous page! Start of "real" ops. */
/*
** If we are doing a test or comparison with a number, and the number
** is larger than 18 bits, we have to use a literal.
** We also have to perform a similar transformation if we want
** to compare the register with an immediate address.
** This entails changing the opcode from TRN to TDN, CAI to CAM, etc.
** Note this is NOT an optimization -- it is needed to avoid generating
** impossible instructions.
*/
case P_TRN:
if (foldtrna (p))
return;
case P_TRC:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -