/* ---------------------------------------------------------------------- */ /* Copyright (C) 1991 by Natrlich! */ /* This file is copyrighted! */ /* Refer to the documentation for details. */ /* ---------------------------------------------------------------------- */ /* In the faint hope that it will help searching speed, labels will */ /* be alphabetisized (also I do have already code for that...) */ /* ---------------------------------------------------------------------- */ #include #include "defines.h" #include "nasm.h" #include "debug.h" #include "labels.h" #define KEINE_CODE_INNEREIEN #include "code.h" #include "fix.h" #include "exprfast.h" #include "op.h" #if ! DORECLAIM # define expr_tryfree( x) #endif extern label huge *h_local[SEP], huge *t_local[SEP], huge *l_local, huge *h_global[SEP], huge *t_global[SEP], huge *l_global, huge *h_macro[SEP], huge *t_macro[SEP], huge *l_macro; extern int u_local, u_global, u_macro; extern lword l_hash; extern char err_defined[], warn_0fwd[], warn_equfwd[], buf[]; extern int _in_macro, runnable; int _in_instr; extern char *str_alloc(); /* ---------------------------------------------------------- */ /* This routine is called when a label */ /* that is PC-relative is encountered: */ /* foo: lda #56 */ /* bar *= $600 */ /* not: foo = 46 */ /* not: lda foo */ /* ---------------------------------------------------------- */ void enter_pclabel( s) register char *s; { register label huge *p; int is_local = (*s == '?' || *s == ':'); ENTER("enterlabel"); #if DEBUG fprintf( ESTREAM, "\t\tWith %s as name @$%4.4X\n", s, __pc); #endif u_local = u_global = -1; /* if we find a macro label this remains -1 */ if( ! (p = find_label( s))) { if( is_local) p = llab_alloc(); else p = lab_alloc(); p->name = s; p->hash = l_hash; p->type = __pc < 0x100 ? (L_ZERO | L_PC) : L_PC; p->val = __pc; p->refs = 0; if( is_local) { MESS("linking into local"); einlinker( h_local, t_local, l_local, u_local, p); } else if( _in_macro) { MESS("linking into macro"); einlinker( h_macro, t_macro, l_macro, u_macro, p); } else { MESS("linking into global"); einlinker( h_global, t_global, l_global, u_global, p); } } else { IMESS("p->refs = $%8.8X", (lword) p->refs, 4); if( p->refs) { if( __pc < 0x100) nswarning( warn_0fwd, p->name); p->val = __pc; p->type |= L_PC; if( ! _in_macro && u_local < 0 && u_global < 0) /* was assumed */ { /* macro, but is */ auslinker( h_macro, t_macro, l_macro, u_macro, p); /* global */ (void) find_label( s); if( is_local) { MESS("linking into local"); einlinker( h_local, t_local, l_local, u_local, p); } else { MESS("linking into global"); einlinker( h_global, t_global, l_global, u_global, p); } } if( p->type & L_EQU) nswarning( warn_equfwd, p->name); entrefer( p); } else if( _in_macro) { p->val = __pc; p->type |= L_PC; } else nserror( err_defined, s); } LEAVE(); } /* ---------------------------------------------------------- */ /* This routine is called when a equ label */ /* or .= label is encountered: */ /* e.g.: */ /* bar .= $600 */ /* foo = 462 */ /* bar == 67 */ /* not: lda foo */ /* not: foo: lda #56 */ /* not: foo *=$600 */ /* ---------------------------------------------------------- */ static expr edummy = { 0, 0, 0, 0, 0, FIX_NOTHING, 0, 0, 0 }; label *enter_elabel( s, ex, type) char *s; register expr huge *ex; register int type; { register label huge *p; int is_local = (*s == '?' || *s == ':'); ENTER("enterlabel/expression"); #if DEBUG fprintf( ESTREAM, "Name=%s type=$%4.4X + some s_expr @$%lX\n", s, type, ex); #endif if( ! (p = find_label( s))) /* if not found or at end of table */ { if( is_local) p = llab_alloc(); else p = lab_alloc(); p->refs = 0; p->name = s; p->hash = l_hash; if( unvalued( ex)) /* top is not value */ { jump1984: if( type == L_ZERO && e_pcrel( ex)) nerror("You can't assign a fwd ref to a zeropage label"); #if LOCALDEBUG fprintf( ESTREAM, "label %s is yet undefined\n", s); #endif p->type = type | (e_pcrel( ex) ? L_PC : 0); fix_lup( ex, p); (void) refer( p, &edummy); /* casting for prettyness */ } else { p->val = ex->val; if( type) { if( type & L_ZERO && p->val >= 0x100) nswarning( "zeropage label >= $100", s); } else if( p->val < 0x100 || ex->op & O_ZEROP) type |= L_ZERO; if( e_pcrel( ex)) type |= L_PC; if( (type & (L_PC | L_ZERO)) == (L_PC | L_ZERO)) nserror("Conflict between PC relativism and zeropageism", s); p->type = type; expr_tryfree( ex); } if( is_local) { MESS("linking into local"); einlinker( h_local, t_local, l_local, u_local, p); } else if( _in_macro) { MESS("linking into macro"); einlinker( h_macro, t_macro, l_macro, u_macro, p); } else { MESS("linking into global"); einlinker( h_global, t_global, l_global, u_global, p); } LEAVE(); return( p); } else if( type & L_EQU) { if( ! (p->type & L_EQU)) nswarning( ".= assignment for a normal label", s); if( valued( ex)) { p->val = ex->val; if( e_pcrel( ex)) p->type |= L_PC; if( p->refs) { if( p->type & L_EQU) nswarning( warn_equfwd, p->name); entrefer( p); } expr_tryfree( ex); p->type |= L_EQU; } else if( p->refs) { ex->fix = FIX_NOTHING; nserror( "Label still has open references", p->name); } else goto jump1984; } else if( p->refs) if( valued( ex)) { if( ex->val < 0x100) nswarning( warn_0fwd, s); p->val = ex->val; if( (e_pcrel( ex) ? L_PC : 0) ^ (p->type & L_PC)) nserror("Label was assumed to be pc relative", s); if( p->type & L_EQU) nswarning( warn_equfwd, s); entrefer( p); expr_tryfree( ex); } else goto jump1984; else nserror( err_defined, s); LEAVE(); return( p); } void def_label( name, val) /* Pyromania */ char *name; word val; { #if ! VERSION name = strcpy( str_alloc( strlen( name) + 1), name); #endif (void) enter_elabel( name, ival_pl( val), L_SPECIAL); } is_ref(s) char *s; { label huge *q; if( ! (q = find_label( s))) return( 0); return( q->type & L_REF); } is_def(s) char *s; { label huge *q; return( (q = find_label( s)) && ! q->refs); } void openrefs( table, message) label huge **table; char *message; { register int i, j, f = 0; register label huge *p; ENTER("openrefs"); for( i = 0; i != SEP; i++) { p = table[ i]; while( p) { if( p->refs) { if( ! f) { f = 1; j = 0; sprintf( buf, "Some %s labels remain undefined", message); nerror( buf); putc( '\t', ESTREAM); } if( j++ == 4) { j = 0; putc( '\n', ESTREAM); putc( '\t', ESTREAM); } fputs( p->name, ESTREAM); putc( '\t', ESTREAM); } p = p->next; } } if( f) putc( '\n', ESTREAM); LEAVE(); } void err_undefs() { register int i, j, k, f = 0; register label huge *p; ENTER("err_undefs"); if( runnable) { openrefs( h_global, "global"); openrefs( h_macro, "macro"); } else for( k = 0; k != 2; k++) for( i = 0; i != SEP;) if( p = k ? h_macro[ i++] : h_global[i++]) do if( ! (! p->refs || q_pcrel( p) || (p->type & (L_SPECIAL | L_LINKZERO)) )) { if( ! f) { f = 1; j = 0; nerror( "Some global non PC-relative labels remain undefined"); putc( '\t', ESTREAM); } if( j++ == 4) { j = 0; putc( '\n', ESTREAM); putc( '\t', ESTREAM); } fputs( p->name, ESTREAM); putc( '\t', ESTREAM); } while( p = p->next); if( f) putc( '\n', ESTREAM); LEAVE(); } void do_local() { register int i; ENTER("do_local"); #if LOCALDEBUG show_all(); #endif openrefs( h_local, "local"); llab_free(); for( i = 0; i != SEP; i++) h_local[ i] = t_local[ i] = 0; LEAVE(); } #if LOCALDEBUG || DEBUG #define oref p->refs ? '*' : ' ' static char format[] = "%c\"%8.8s\" type=$%2.2X value=$%4.4X hash=$%8.8lX\n"; void show_all() { label huge *p; int i; fprintf( ESTREAM, "Dumping global table:\n"); for( i = 0; i != SEP; i++) if( p = h_global[ i]) { do fprintf( ESTREAM, format, oref, p->name, p->type, p->val, p->hash); while( p = p->next); putc( '\n', ESTREAM); } fprintf( ESTREAM, "\n\nDumping local table:\n"); for( i = 0; i != SEP; i++) if( p = h_local[ i] ) { do fprintf( ESTREAM, format, oref, p->name, p->type, p->val, p->hash); while( p = p->next); putc( '\n', ESTREAM); } fprintf( ESTREAM, "\n\nDumping macro label table:\n"); for( i = 0; i != SEP; i++) if( p = h_macro[ i]) { do fprintf( ESTREAM, format, oref, p->name, p->type, p->val, p->hash); while( p = p->next); putc( '\n', ESTREAM); } } #endif