📄 pc3.c
字号:
/*- * Copyright (c) 1980, 1982, 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1980, 1982, 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)pc3.c 8.1 (Berkeley) 6/6/93";#endif /* not lint */ /* * Pc3 is a pass in the Berkeley Pascal compilation * process that is performed just prior to linking Pascal * object files. Its purpose is to enforce the rules of * separate compilation for Berkeley Pascal. Pc3 is called * with the same argument list of object files that is sent to * the loader. These checks are performed by pc3 by examining * the symbol tables of the object files: * (1) All .o files must be up to date with respect to the * runtime libraries. * (2) Each global Pascal symbol (label, constant, type, * variable, procedure, or function name) must be uniquely * declared, i.e. declared in only one included file or * source file. * (3) Each external function (or procedure) may be resolved * at most once in a source file which included the * external declaration of the function. * * The symbol table of each object file is scanned and * each global Pascal symbol is placed in a hashed symbol * table. The Pascal compiler has been modified to emit all * Pascal global symbols to the object file symbol table. The * information stored in the symbol table for each such symbol * is: * * - the name of the symbol; * - a subtype descriptor; * - the file which logically contains the declaration of * the symbol or which caused the inclusion of an include file. * - for included files: * - a checksum; * - for symbols: * - the file which textually contains the declaration of * the symbol (possibly an include file); * - the line number at which the symbol is declared; * - the file which contains the resolution of the symbol. * - the line number at which the symbol is resolved; * * If a symbol has been previously entered into the symbol * table, a check is made that the current declaration is of * the same type and from the same include file as the previous * one. Except for files and functions and procedures, it is * an error for a symbol declaration to be encountered more * than once, unless the re-declarations come from the same * included file as the original. * * As an include file symbol is encountered in a source * file, the symbol table entry of each symbol declared in that * include file is modified to reflect its new logical * inclusion in the source file. File symbols are also * encountered as an included file ends, signaling the * continuation of the enclosing file. * * Functions and procedures which have been declared * external may be resolved by declarations from source files * which included the external declaration of the function. * Functions and procedures may be resolved at most once across * a set of object files. The loader will complain if a * function is not resolved at least once. */char program[] = "pc";#include <sys/types.h>#include <sys/stat.h>#include <ar.h>#include <stdio.h>#include <ctype.h>#include <a.out.h>#include <stab.h>#include "pstab.h"#include "pc3.h"int errors = NONE;BOOL wflag = FALSE; /* * check each of the argument .o files (or archives of .o files). */main( argc , argv ) int argc; char **argv; { struct fileinfo ofile; for ( argv++ ; *argv != 0 && **argv == '-' ; argv++ ) { (*argv)++; switch ( **argv ) { default: error( FATAL , "pc3: bad flag -%c\n" , **argv ); case 'w': wflag = TRUE; break; } } for ( /* void */ ; *argv != 0 ; argv++ ) {# ifdef DEBUG fprintf( stderr , "[main] *argv = %s\n" , *argv );# endif DEBUG ofile.name = *argv; checkfile( &ofile ); } exit( errors ); } /* * check the namelist of a file, or all namelists of an archive. */checkfile( ofilep ) struct fileinfo *ofilep; { union { char mag_armag[ SARMAG + 1 ]; struct exec mag_exec; } mag_un; int red; struct stat filestat; ofilep -> file = fopen( ofilep -> name , "r" ); if ( ofilep -> file == NULL ) { error( ERROR , "cannot open: %s" , ofilep -> name ); return; } fstat( fileno( ofilep -> file ) , &filestat ); red = fread( (char *) &mag_un , 1 , sizeof mag_un , ofilep -> file ); if ( red != sizeof mag_un ) { error( ERROR , "cannot read header: %s" , ofilep -> name ); return; } if ( mag_un.mag_exec.a_magic == OARMAG ) { error( WARNING , "old archive: %s" , ofilep -> name ); return; } if ( strncmp( mag_un.mag_armag , ARMAG , SARMAG ) == 0 ) { /* archive, iterate through elements */# ifdef DEBUG fprintf( stderr , "[checkfile] archive %s\n" , ofilep -> name );# endif DEBUG ofilep -> nextoffset = SARMAG; while ( nextelement( ofilep ) ) { checknl( ofilep ); } } else if ( N_BADMAG( mag_un.mag_exec ) ) { /* not a file.o */ error( ERROR , "bad format: %s" , ofilep -> name ); return; } else { /* a file.o */# ifdef DEBUG fprintf( stderr , "[checkfile] .o file %s\n" , ofilep -> name );# endif DEBUG fseek( ofilep -> file , 0L , 0 ); ofilep -> nextoffset = filestat.st_size; checknl( ofilep ); } fclose( ofilep -> file ); } /* * check the namelist of this file for conflicts with * previously entered symbols. */checknl( ofilep ) register struct fileinfo *ofilep; { long red; struct exec oexec; off_t symoff; long numsyms; register struct nlist *nlp; register char *stringp; long strsize; long sym; red = fread( (char *) &oexec , 1 , sizeof oexec , ofilep -> file ); if ( red != sizeof oexec ) { error( ERROR , "error reading struct exec: %s" , ofilep -> name ); return; } if ( N_BADMAG( oexec ) ) { return; } symoff = N_SYMOFF( oexec ) - sizeof oexec; fseek( ofilep -> file , symoff , 1 ); numsyms = oexec.a_syms / sizeof ( struct nlist ); if ( numsyms == 0 ) { error( WARNING , "no name list: %s" , ofilep -> name ); return; } nlp = (struct nlist *) calloc( numsyms , sizeof ( struct nlist ) ); if ( nlp == 0 ) { error( FATAL , "no room for %d nlists" , numsyms ); } red = fread( ( char * ) nlp , numsyms , sizeof ( struct nlist ) , ofilep -> file ); if ( ftell( ofilep -> file ) + sizeof ( off_t ) >= ofilep -> nextoffset ) { error( WARNING , "no string table (old format .o?)" , ofilep -> name ); return; } red = fread( (char *) &strsize , sizeof strsize , 1 , ofilep -> file ); if ( red != 1 ) { error( WARNING , "no string table (old format .o?)" , ofilep -> name ); return; } stringp = ( char * ) malloc( strsize ); if ( stringp == 0 ) { error( FATAL , "no room for %d bytes of strings" , strsize ); } red = fread( stringp + sizeof strsize , strsize - sizeof ( strsize ) , 1 , ofilep -> file ); if ( red != 1 ) { error( WARNING , "error reading string table: %s" , ofilep -> name ); }# ifdef DEBUG fprintf( stderr , "[checknl] %s: %d symbols\n" , ofilep -> name , numsyms );# endif DEBUG for ( sym = 0 ; sym < numsyms ; sym++) { if ( nlp[ sym ].n_un.n_strx ) { nlp[ sym ].n_un.n_name = stringp + nlp[ sym ].n_un.n_strx; } else { nlp[ sym ].n_un.n_name = ""; } checksymbol( &nlp[ sym ] , ofilep ); } if ( nlp ) { free( nlp ); } if ( stringp ) { free( stringp ); } } /* * check a symbol. * look it up in the hashed symbol table, * entering it if necessary. * this maintains a state of which .p and .i files * it is currently in the midst from the nlist entries * for source and included files. * if we are inside a .p but not a .i, pfilep == ifilep. */checksymbol( nlp , ofilep ) struct nlist *nlp; struct fileinfo *ofilep; { static struct symbol *pfilep = NIL; static struct symbol *ifilep = NIL; register struct symbol *symbolp; int errtype;# ifdef DEBUG if ( pfilep && ifilep ) { fprintf( stderr , "[checksymbol] pfile %s ifile %s\n" , pfilep -> name , ifilep -> name ); } fprintf( stderr , "[checksymbol] ->name %s ->n_desc %x (%s)\n" , nlp -> n_un.n_name , nlp -> n_desc , classify( nlp -> n_desc ) );# endif DEBUG if ( nlp -> n_type != N_PC ) { /* don't care about the others */ return; } symbolp = entersymbol( nlp -> n_un.n_name ); if ( symbolp -> lookup == NEW ) {# ifdef DEBUG fprintf( stderr , "[checksymbol] ->name %s is NEW\n" , symbolp -> name );# endif DEBUG symbolp -> desc = nlp -> n_desc; symbolp -> fromp = pfilep; switch ( symbolp -> desc ) { default: error( FATAL , "panic: [checksymbol] NEW" ); case N_PGLABEL: case N_PGCONST: case N_PGTYPE: case N_PGVAR: case N_PGFUNC: case N_PGPROC: case N_PLDATA: case N_PLTEXT: symbolp -> sym_un.sym_str.rfilep = ifilep; symbolp -> sym_un.sym_str.rline = nlp -> n_value; symbolp -> sym_un.sym_str.fromi = ifilep; symbolp -> sym_un.sym_str.iline = nlp -> n_value; return; case N_PEFUNC: case N_PEPROC: symbolp -> sym_un.sym_str.rfilep = NIL; symbolp -> sym_un.sym_str.rline = 0; /* * functions can only be declared external * in included files. */ if ( pfilep == ifilep ) { error( WARNING , "%s, line %d: %s %s must be declared in included file" , pfilep -> name , nlp -> n_value , classify( symbolp -> desc ) , symbolp -> name ); } symbolp -> sym_un.sym_str.fromi = ifilep; symbolp -> sym_un.sym_str.iline = nlp -> n_value; return; case N_PSO: if ( nlp -> n_value < N_FLAGCHECKSUM ) { error( WARNING, "%s is out of date and should be recompiled", ofilep -> name ); } pfilep = symbolp; ifilep = symbolp; symbolp -> sym_un.checksum = N_FLAGCHECKSUM; return; case N_PSOL: ifilep = symbolp; symbolp -> sym_un.checksum = nlp -> n_value; return; } } else {# ifdef DEBUG fprintf( stderr , "[checksymbol] ->name %s is OLD\n" , symbolp -> name );# endif DEBUG errtype = ERROR; switch ( symbolp -> desc ) { default: error( FATAL , "panic [checksymbol] OLD" ); return; case N_PSO: /* * finding a file again means you are back * in it after finishing an include file. */ if ( symbolp -> desc != nlp -> n_desc ) { error( FATAL , "panic [checksymbol] PSO" ); return; } pfilep = symbolp; ifilep = symbolp; return; case N_PSOL: /* * include files can be seen more than once, * but their checksums are checked if they are * greater than N_FLAGCHECKSUM. * PSOL's are seen with checksums as the * include file is entered, and with * N_FLAGCHECKSUM as we are back in an * included file from a nested include. */ if ( symbolp -> desc != nlp -> n_desc ) { error( FATAL , "panic [checksymbol] PSOL" ); return; } if ((unsigned) symbolp->sym_un.checksum > N_FLAGCHECKSUM && (unsigned) nlp -> n_value > N_FLAGCHECKSUM && symbolp -> sym_un.checksum != nlp -> n_value ) { error( ERROR, "%s included in %s differs from %s included in %s", symbolp -> name, pfilep -> name, symbolp -> name, symbolp -> fromp -> name ); } ifilep = symbolp; return; case N_PEFUNC: case N_PEPROC: /* * this might be the resolution of the external * has to match func/proc of external * and has to have included external * and has to not have been previously resolved. */ if ( ( ( symbolp -> desc == N_PEFUNC && nlp -> n_desc == N_PGFUNC ) || ( symbolp -> desc == N_PEPROC && nlp -> n_desc == N_PGPROC ) ) && ( symbolp -> fromp == pfilep ) && ( symbolp -> sym_un.sym_str.rfilep == NIL ) ) { /* * resolve external */# ifdef DEBUG fprintf( stderr , "[checksymbol] resolving external\n" );# endif DEBUG symbolp -> sym_un.sym_str.rfilep = ifilep; symbolp -> sym_un.sym_str.rline = nlp -> n_value; return; } /* * otherwise, it might be another external, * which is okay if it's * the same type and from the same include file */ if ( ( ( symbolp -> desc == N_PEFUNC && nlp -> n_desc == N_PEFUNC ) || ( symbolp -> desc == N_PEPROC && nlp -> n_desc == N_PEPROC ) ) && ( symbolp -> sym_un.sym_str.fromi == ifilep ) ) { /* * just another pretty external * make it look like it comes from here. */# ifdef DEBUG fprintf( stderr , "[checksymbol] just another pretty external\n" );# endif DEBUG symbolp -> fromp = pfilep; return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -