X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=rmac;a=blobdiff_plain;f=symbol.c;h=87f90c048d80952a5a0cb18aec48035ae5905c36;hp=747c5a7e7099d655437e00c17f3bc2466e422fb1;hb=66b362fa203d0850e8dce8045adb454e354c22ce;hpb=2b2451777ddcb27f2b1c21c6551085a7a35e6701 diff --git a/symbol.c b/symbol.c index 747c5a7..87f90c0 100644 --- a/symbol.c +++ b/symbol.c @@ -1,381 +1,500 @@ // -// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System +// RMAC - Reboot's Macro Assembler for all Atari computers // SYMBOL.C - Symbol Handling -// Copyright (C) 199x Landon Dyer, 2011-2012 Reboot and Friends +// Copyright (C) 199x Landon Dyer, 2011-2018 Reboot and Friends // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986 -// Source Utilised with the Kind Permission of Landon Dyer +// Source utilised with the kind permission of Landon Dyer // #include "symbol.h" +#include "error.h" #include "listing.h" +#include "object.h" #include "procln.h" -#include "error.h" -static SYM *sytab[NBUCKETS]; // User symbol-table header -int curenv; // Current enviroment number -SYM *sorder; // * -> Symbols, in order of reference -SYM *sordtail; // * -> Last symbol in sorder list -SYM *sdecl; // * -> Symbols, in order of declaration -SYM *sdecltail; // * -> Last symbol in sdecl list -// Tags for marking symbol spaces +// Macros +#define NBUCKETS 256 // Number of hash buckets (power of 2) + +static SYM * symbolTable[NBUCKETS]; // User symbol-table header +int curenv; // Current enviroment number +static SYM * sorder; // * -> Symbols, in order of reference +static SYM * sordtail; // * -> Last symbol in sorder list +static SYM * sdecl; // * -> Symbols, in order of declaration +static SYM * sdecltail; // * -> Last symbol in sdecl list +static uint32_t currentUID; // Symbol UID tracking (done by NewSymbol()) +uint32_t firstglobal; // Index of the first global symbol in an ELF object. + +// Tags for marking symbol spaces: // a = absolute // t = text // d = data // ! = "impossible!" // b = BSS -static char tdb_text[8] = { +static uint8_t tdb_text[8] = { 'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE }; + // -// --- Initialize Symbol Table --------------------------------------------------------------------- +// Initialize symbol table // - -void init_sym(void) { - int i; // Iterator - - for(i = 0; i < NBUCKETS; ++i) // Initialise symbol hash table - sytab[i] = NULL; - - curenv = 1; // Init local symbol enviroment - sorder = NULL; // Init symbol-reference list - sordtail = NULL; - sdecl = NULL; // Init symbol-decl list - sdecltail = NULL; +void InitSymbolTable(void) +{ + for(int i=0; isname = strdup(name); + symbol->stype = (uint8_t)type; + symbol->senv = (uint16_t)envno; + // We don't set this as DEFINED, as it could be a forward reference! + symbol->sattr = 0; + // We don't set RISCSYM here as not every symbol first seen in a RISC + // section is a RISC symbol! + symbol->sattre = 0; + symbol->svalue = 0; + symbol->sorder = NULL; + symbol->uid = currentUID++; + + // Install symbol in the symbol table + int hash = HashSymbol(name, envno); + symbol->snext = symbolTable[hash]; + symbolTable[hash] = symbol; + + // Append symbol to the symbol-order list + if (sorder == NULL) + sorder = symbol; // Add first symbol + else + sordtail->sorder = symbol; // Or append to tail of list + + sordtail = symbol; + return symbol; } + // -// --- Make a new symbol of type `type' in enviroment `envno' -------------------------------------- +// Look up the symbol name by its UID and return the pointer to the name. +// If it's not found, return NULL. // - -SYM *newsym(char *name, int type, int envno) { - int hash; // Symbol hash value - SYM *sy; // Pointer to symbol - - - // Allocate the symbol - sy = (SYM *)amem((long)(sizeof(SYM))); - if(sy == NULL) { - printf("SYMALLOC ERROR (%s)\n", name); - return(NULL); - } - - sy->sname = nstring(name); - - // Fill-in the symbol - sy->stype = (BYTE)type; - sy->senv = (WORD)envno; - sy->sattr = 0; - if(rgpu || rdsp) sy->sattre = RISCSYM; - else sy->sattre = 0; - sy->svalue = 0; - - // Install symbol in symbol table - hash = syhash(name, envno); - sy->snext = sytab[hash]; - sytab[hash] = sy; - - // Append symbol to symbol-order list - if(sorder == NULL) - sorder = sy; // Add first symbol - else - sordtail->sorder = sy; // Or append to tail of list - - sy->sorder = NULL; - sordtail = sy; - - return(sy); // Return pointer to symbol +uint8_t * GetSymbolNameByUID(uint32_t uid) +{ + //problem is with string lookup, that's why we're writing this + //so once this is written, we can put the uid in the token stream + + // A much better approach to the symbol order list would be to make an + // array--that way you can do away with the UIDs and all the rest, and + // simply do an array lookup based on position. But meh, let's do this for + // now until we can rewrite things so they make sense. + SYM * symbol = sorder; + + for(; symbol; symbol=symbol->sorder) + { + if (symbol->uid == uid) + return symbol->sname; + } + + return NULL; } + // -// --- Lookup the symbol `name', of the specified type, with the specified enviroment level -------- +// Lookup the symbol 'name', of the specified type, with the specified +// enviroment level // - -SYM *lookup(char *name, int type, int envno) { - SYM *sy; // Symbol record pointer - int k, sum; // Hash bucket calculation - char *s; // String pointer - - // Pick a hash-bucket (SAME algorithm as syhash()) - k = 0; - s = name; - for(sum = envno; *s;) { - if(k++ == 1) - sum += *s++ << 2; - else sum += *s++; - } - - sy = sytab[sum & (NBUCKETS-1)]; - - // Do linear-search for symbol in bucket - while(sy != NULL) { - if(sy->stype == type && // Type, envno and name must match - sy->senv == envno && - *name == *sy->sname && // Fast check for first character - !strcmp(name, sy->sname)) - break; - else sy = sy->snext; - } - - return(sy); // Return NULL or matching symbol +SYM * lookup(uint8_t * name, int type, int envno) +{ + SYM * symbol = symbolTable[HashSymbol(name, envno)]; + + // Do linear-search for symbol in bucket + while (symbol != NULL) + { + if (symbol->stype == type // Type, envno and name must match + && symbol->senv == envno + && *name == *symbol->sname // Fast check for first character + && !strcmp(name, symbol->sname)) // More expensive check + break; + + symbol = symbol->snext; + } + + // Return NULL or matching symbol + return symbol; } + // -// --- Put symbol on "order-of-declaration" list of symbols ---------------------------------------- +// Put symbol on "order-of-declaration" list of symbols // - -void sym_decl(SYM *sym) { - if(sym->sattr & SDECLLIST) return; // Already on list - sym->sattr |= SDECLLIST; // Mark "already on list" - - if(sdecl == NULL) - sdecl = sym; // First on decl-list - else - sdecltail->sdecl = sym; // Add to end of list - - sym->sdecl = NULL; // Fix up list's tail - sdecltail = sym; +void AddToSymbolDeclarationList(SYM * symbol) +{ + // Don't add if already on list, or it's an equated register/CC + if ((symbol->sattr & SDECLLIST) + || (symbol->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC))) + return; + + // Mark as "on .sdecl list" + symbol->sattr |= SDECLLIST; + + if (sdecl == NULL) + sdecl = symbol; // First on decl-list + else + sdecltail->sdecl = symbol; // Add to end of list + + // Fix up list's tail + symbol->sdecl = NULL; + sdecltail = symbol; } + // -// --- Make all referenced, undefined symbols global ----------------------------------------------- +// Make all referenced, undefined symbols global // +void ForceUndefinedSymbolsGlobal(void) +{ + SYM * sy; + + DEBUG printf("~ForceUndefinedSymbolsGlobal()\n"); + + // Scan through all symbols; if a symbol is REFERENCED but not DEFINED, + // then make it global. + for(sy=sorder; sy!=NULL; sy=sy->sorder) + { + if (sy->stype == LABEL && sy->senv == 0 + && ((sy->sattr & (REFERENCED | DEFINED)) == REFERENCED)) + sy->sattr |= GLOBAL; + } +} -int syg_fix(void) { - SYM *sy; - - DEBUG printf("~syg_fix()\n"); - - // Scan through all symbols; - // If a symbol is REFERENCED but not DEFINED, then make it global. - for(sy = sorder; sy != NULL; sy = sy->sorder) - if(sy->stype == LABEL && sy->senv == 0 && - ((sy->sattr & (REFERENCED|DEFINED)) == REFERENCED)) - sy->sattr |= GLOBAL; - return(0); +// +// Assign numbers to symbols that are to be exported or imported. The symbol +// number is put in 'senv'. Returns the number of symbols that will be in the +// symbol table. +// +// N.B.: This is usually called twice; first time with NULL parameters and the +// second time with real ones. The first one is typically done to get a +// count of the # of symbols in the symbol table, and the second is to +// actually create it. +// +uint32_t sy_assign(uint8_t * buf, uint8_t *(* construct)()) +{ + uint16_t scount = 0; + + // Done only on first pass... + if (buf == NULL) + { + // Append all symbols not appearing on the .sdecl list to the end of + // the .sdecl list + for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder) + AddToSymbolDeclarationList(sy); + } + + // Run through all symbols (now on the .sdecl list) and assign numbers to + // them. We also pick which symbols should be global or not here. + for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl) + { + // Export or import external references, and export COMMON blocks. + if ((sy->stype == LABEL) + && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED) + || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED)) + || (sy->sattr & COMMON)) + { + sy->senv = scount++; + + if (buf != NULL) + buf = construct(buf, sy, 1); + } + // Export vanilla labels (but don't make them global). An exception is + // made for equates, which are not exported unless they are referenced. + else if (sy->stype == LABEL && lsym_flag + && (sy->sattr & (DEFINED | REFERENCED)) != 0 + && (!as68_flag || *sy->sname != 'L')) + { + sy->senv = scount++; + + if (buf != NULL) + buf = construct(buf, sy, 0); + } + } + + return scount; } + // -// --- Convert string to uppercase ----------------------------------------------------------------- +// Custom version of sy_assign for ELF .o files. +// The order that the symbols should be dumped is different. +// (globals must be explicitly at the end of the table) // - -int uc_string(char *s) { - for(; *s; ++s) - if(*s >= 'a' && *s <= 'z') - *s -= 32; - return(0); +// N.B.: It should be possible to merge this with sy_assign, as there's nothing +// really ELF specific in here, other than the "globals go at the end of +// the queue" thing, which doesn't break the others. :-P +uint32_t sy_assign_ELF(uint8_t * buf, uint8_t *(* construct)()) +{ + uint16_t scount = 0; + +// if (construct == (uint8_t *(*)())constr_elfsymtab) +// if (buf == NULL) + { + // Append all symbols not appearing on the .sdecl list to the end of + // the .sdecl list + for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder) + AddToSymbolDeclarationList(sy); + } + + // Run through all symbols (now on the .sdecl list) and assign numbers to + // them. We also pick which symbols should be global or not here. + for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl) + { + // Export vanilla labels (but don't make them global). An exception is + // made for equates, which are not exported unless they are referenced. + if (sy->stype == LABEL && lsym_flag + && (sy->sattr & (DEFINED | REFERENCED)) != 0 + && (*sy->sname != '.') + && (sy->sattr & GLOBAL) == 0) + { + sy->senv = scount++; + + if (buf != NULL) + buf = construct(buf, sy, 0); + } + } + + firstglobal = scount; + + // For ELF object mode run through all symbols in reference order + // and export all global-referenced labels. Not sure if this is + // required but it's here nonetheless + + for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl) + { + if ((sy->stype == LABEL) + && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED) + || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED)) + || (sy->sattr & COMMON)) + { + sy->senv = scount++; + + if (buf != NULL) + buf = construct(buf, sy, 1); + } + else if ((sy->sattr == (GLOBAL | REFERENCED)) && (buf != NULL)) + { + buf = construct(buf, sy, 0); + scount++; + } + } + + return scount; } + // -// ------------------------------------------------------------------------------------------------- -// Assign numbers to symbols that are to be exported or imported. The symbol number is put in -// `.senv'. Return the number of symbols that will be in the symbol table. -// ------------------------------------------------------------------------------------------------- +// Convert string to uppercase // - -int sy_assign(char *buf, char *(*constr)()) { - SYM *sy; - int scount; - //int i; - - scount = 0; - - if(buf == NULL) - // Append all symbols not appearing on the .sdecl list to the end of the .sdecl list - for(sy = sorder; sy != NULL; sy = sy->sorder) { - - // Essentially the same as 'sym_decl()' above: - if(sy->sattr & SDECLLIST) continue; // Already on list - sy->sattr |= SDECLLIST; // Mark "on the list" - - if(sdecl == NULL) sdecl = sy; // First on decl-list - else sdecltail->sdecl = sy; // Add to end of list - - sy->sdecl = NULL; // Fix up list's tail - sdecltail = sy; - } - - // Run through all symbols (now on the .sdecl list) and assign numbers to them. We also pick - // which symbols should be global or not here. - for(sy = sdecl; sy != NULL; sy = sy->sdecl) { - - if(sy->sattre & UNDEF_EQUR) continue; // Don't want undefined on our list - if(sy->sattre & UNDEF_CC) continue; - - // Export or import external references, and export COMMON blocks. - if((sy->stype == LABEL) && - ((sy->sattr & (GLOBAL|DEFINED)) == (GLOBAL|DEFINED) || - (sy->sattr & (GLOBAL|REFERENCED)) == (GLOBAL|REFERENCED)) || - (sy->sattr & COMMON)) { - sy->senv = (WORD)scount++; - if(buf != NULL) buf = (*constr)(buf, sy, 1); - } else - // Export vanilla labels (but don't make them global). An exception is made for equates, - // which are not exported unless they are referenced. - if(sy->stype == LABEL && lsym_flag && - (sy->sattr & (DEFINED|REFERENCED)) != 0 && - (!as68_flag || *sy->sname != 'L') ) { - sy->senv = (WORD)scount++; - if(buf != NULL) buf = (*constr)(buf, sy, 0); - } - } - - return(scount); +void ToUppercase(uint8_t * s) +{ + for(; *s; s++) + { + if (*s >= 'a' && *s <= 'z') + *s -= 0x20; + } } + // -// --- Generate symbol table for listing file ------------------------------------------------------ +// Generate symbol table for listing file // - -int symtable(void) { - int i; - int j; - SYM *q = NULL; - SYM *p; - SYM *r; - SYM *k; - SYM **sy; - SYM *colptr[4]; - char ln[150]; - char ln1[150]; - char ln2[20]; - char c, c1; - WORD w; - int ww; - int colhei; - extern int pagelen; - - colhei = pagelen - 5; - - // Allocate storage for list headers and partition all labels. - // Throw away macros and macro arguments. - sy = (SYM **)amem((LONG)(128 * sizeof(LONG))); - for(i = 0; i < 128; ++i) sy[i] = NULL; - - for(i = 0; i < NBUCKETS; ++i) - for(p = sytab[i]; p != NULL; p = k) { - k = p->snext; - j = *p->sname; - r = NULL; - if(p->stype != LABEL) continue; // Ignore non-labels - if(p->sattre & UNDEF_EQUR) continue; - - for(q = sy[j]; q != NULL; q = q->snext) - if(strcmp(p->sname, q->sname) < 0) - break; - else r = q; - - if(r == NULL) { // Insert at front of list - p->snext = sy[j]; - sy[j] = p; - } else { // Insert in middle or append to list - p->snext = r->snext; - r->snext = p; - } - } - - // Link all symbols onto one list again - p = NULL; - for(i = 0; i < 128; ++i) - if((r = sy[i]) != NULL) { - if(p == NULL) - q = r; - else q->snext = r; - - while(q->snext != NULL) - q = q->snext; - - if(p == NULL) - p = r; - } - - eject(); - strcpy(subttl, "Symbol Table"); - - while(p != NULL) { - for (i = 0; i < 4; ++i) { - colptr[i] = p; - for(j = 0; j < colhei; ++j) - if(p == NULL) - break; - else p = p->snext; - } - - for(i = 0; i < colhei; ++i) { - *ln = EOS; - if(colptr[0] == NULL) - break; - - for(j = 0; j < 4; ++j) { - if((q = colptr[j]) == NULL) - break; - colptr[j] = q->snext; - w = q->sattr; - ww = q->sattre; - // Pick a tag: - // c common - // x external reference - // g global (export) - // space nothing special - c1 = SPACE; - c = SPACE; - - if(w & COMMON) c = 'c'; - else if((w & (DEFINED|GLOBAL)) == GLOBAL) c = 'x'; - else if(w & GLOBAL) c = 'g'; - - c1 = tdb_text[w & TDB]; - if(c == 'x') strcpy(ln2, "external"); - else { - sprintf(ln2, "%08ux", q->svalue); - uc_string(ln2); - } - - sprintf(ln1, " %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c); - - strcat(ln, ln1); - } - ship_ln(ln); - } - eject(); - } - - return(0); +int symtable(void) +{ + int i; + int j; + SYM * q = NULL; + SYM * p; + SYM * r; + SYM * k; + SYM * colptr[4]; + char ln[1024]; + char ln1[1024]; + char ln2[20]; + char c, c1; + WORD w; + int ww; + int colhei = pagelen - 5; + + // Allocate storage for list headers and partition all labels. Throw away + // macros and macro arguments. + SYM ** sy = (SYM **)malloc(128 * sizeof(SYM **)); + + for(i=0; i<128; i++) + sy[i] = NULL; + + for(i=0; isnext; + j = *p->sname; + r = NULL; + + // Ignore non-labels + if ((p->stype != LABEL) || (p->sattre & UNDEF_EQUR)) + continue; + + for(q=sy[j]; q!=NULL; q=q->snext) + { + if (strcmp(p->sname, q->sname) < 0) + break; + + r = q; + } + + if (r == NULL) + { + // Insert at front of list + p->snext = sy[j]; + sy[j] = p; + } + else + { + // Insert in middle or append to list + p->snext = r->snext; + r->snext = p; + } + } + } + + // Link all symbols onto one list again + p = NULL; + + for(i=0; i<128; ++i) + { + if ((r = sy[i]) != NULL) + { + if (p == NULL) + q = r; + else + q->snext = r; + + while (q->snext != NULL) + q = q->snext; + + if (p == NULL) + p = r; + } + } + + eject(); + strcpy(subttl, "Symbol Table"); + + while (p != NULL) + { + for(i=0; i<4; i++) + { + colptr[i] = p; + + for(j=0; jsnext; + } + } + + for(i=0; isnext; + w = q->sattr; + ww = q->sattre; + // Pick a tag: + // c common + // x external reference + // g global (export) + // space nothing special + c1 = SPACE; + c = SPACE; + + if (w & COMMON) + c = 'c'; + else if ((w & (DEFINED | GLOBAL)) == GLOBAL) + c = 'x'; + else if (w & GLOBAL) + c = 'g'; + + c1 = tdb_text[w & TDB]; + + if (c == 'x') + strcpy(ln2, "external"); + else + { + sprintf(ln2, "%016lX", q->svalue); + ToUppercase(ln2); + } + + sprintf(ln1, " %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c); + strcat(ln, ln1); + } + + ship_ln(ln); + } + + eject(); + } + + return 0; } +