2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // SYMBOL.C - Symbol Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2022 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
18 #define NBUCKETS 256 // Number of hash buckets (power of 2)
20 static SYM * symbolTable[NBUCKETS]; // User symbol-table header
21 int curenv; // Current enviroment number
22 static SYM * sorder; // * -> Symbols, in order of reference
23 static SYM * sordtail; // * -> Last symbol in sorder list
24 static SYM * sdecl; // * -> Symbols, in order of declaration
25 static SYM * sdecltail; // * -> Last symbol in sdecl list
26 static uint32_t currentUID; // Symbol UID tracking (done by NewSymbol())
27 uint32_t firstglobal; // Index of the first global symbol in an ELF object.
29 // Tags for marking symbol spaces:
35 static uint8_t tdb_text[8] = {
36 'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE
39 // Internal function prototypes
40 static uint16_t WriteLODSection(int, uint16_t);
43 // Initialize symbol table
45 void InitSymbolTable(void)
47 for(int i=0; i<NBUCKETS; i++) // Initialise symbol hash table
48 symbolTable[i] = NULL;
50 curenv = 1; // Init local symbol enviroment
51 sorder = NULL; // Init symbol-reference list
53 sdecl = NULL; // Init symbol-decl list
59 // Hash the ASCII name and enviroment number
61 int HashSymbol(const uint8_t * name, int envno)
63 int sum = envno, k = 0;
73 return sum & (NBUCKETS - 1);
77 // Make a new symbol of type 'type' in enviroment 'envno'
79 SYM * NewSymbol(const uint8_t * name, int type, int envno)
81 // Allocate the symbol
82 SYM * symbol = malloc(sizeof(SYM));
86 printf("NewSymbol: MALLOC ERROR (symbol=\"%s\")\n", name);
91 symbol->sname = name ? strdup(name) : NULL;
92 symbol->stype = (uint8_t)type;
93 symbol->senv = (uint16_t)envno;
94 // We don't set this as DEFINED, as it could be a forward reference!
96 // We don't set RISCSYM here as not every symbol first seen in a RISC
97 // section is a RISC symbol!
100 symbol->sorder = NULL;
101 symbol->uid = currentUID++;
102 // We don't set st_type, st_desc, or st_other here because they are only
103 // used by stabs debug symbols, which are always initialized by
104 // NewDebugSymbol(), which always sets these fields. Hence, initializing
105 // them here would be redundant.
107 // Record filename the symbol is defined (Used by macro error reporting and some debug symbols)
108 symbol->cfileno = cfileno;
110 // Don't hash debug symbols: they are never looked up and may have no name.
113 // Install symbol in the symbol table
114 int hash = HashSymbol(name, envno);
115 symbol->snext = symbolTable[hash];
116 symbolTable[hash] = symbol;
119 // Append symbol to the symbol-order list
121 sorder = symbol; // Add first symbol
123 sordtail->sorder = symbol; // Or append to tail of list
130 // Look up the symbol name by its UID and return the pointer to the name.
131 // If it's not found, return NULL.
133 uint8_t * GetSymbolNameByUID(uint32_t uid)
135 //problem is with string lookup, that's why we're writing this
136 //so once this is written, we can put the uid in the token stream
138 // A much better approach to the symbol order list would be to make an
139 // array--that way you can do away with the UIDs and all the rest, and
140 // simply do an array lookup based on position. But meh, let's do this for
141 // now until we can rewrite things so they make sense.
142 SYM * symbol = sorder;
144 for(; symbol; symbol=symbol->sorder)
146 if (symbol->uid == uid)
147 return symbol->sname;
154 // Lookup the symbol 'name', of the specified type, with the specified
157 SYM * lookup(uint8_t * name, int type, int envno)
159 SYM * symbol = symbolTable[HashSymbol(name, envno)];
161 // Do linear-search for symbol in bucket
162 while (symbol != NULL)
164 if (symbol->stype == type // Type, envno and name must match
165 && symbol->senv == envno
166 && *name == *symbol->sname // Fast check for first character
167 && !strcmp(name, symbol->sname)) // More expensive check
170 symbol = symbol->snext;
173 // Return NULL or matching symbol
178 // Put symbol on "order-of-declaration" list of symbols
180 void AddToSymbolDeclarationList(SYM * symbol)
182 // Don't add if already on list, or it's an equated register/CC
183 if ((symbol->sattr & SDECLLIST)
184 || (symbol->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)))
187 // Mark as "on .sdecl list"
188 symbol->sattr |= SDECLLIST;
191 sdecl = symbol; // First on decl-list
193 sdecltail->sdecl = symbol; // Add to end of list
195 // Fix up list's tail
196 symbol->sdecl = NULL;
201 // Make all referenced, undefined symbols global
203 void ForceUndefinedSymbolsGlobal(void)
207 DEBUG printf("~ForceUndefinedSymbolsGlobal()\n");
209 // Scan through all symbols; if a symbol is REFERENCED but not DEFINED,
210 // then make it global.
211 for(sy=sorder; sy!=NULL; sy=sy->sorder)
213 if (sy->stype == LABEL && sy->senv == 0
214 && ((sy->sattr & (REFERENCED | DEFINED)) == REFERENCED))
220 // Assign numbers to symbols that are to be exported or imported. The symbol
221 // number is put in 'senv'. Returns the number of symbols that will be in the
224 // N.B.: This is usually called twice; first time with NULL parameters and the
225 // second time with real ones. The first one is typically done to get a
226 // count of the # of symbols in the symbol table, and the second is to
227 // actually create it.
229 uint32_t AssignSymbolNos(uint8_t * buf, uint8_t *(* construct)())
233 // Done only on first pass...
236 // Append all symbols not appearing on the .sdecl list to the end of
238 for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
239 AddToSymbolDeclarationList(sy);
242 // Run through all symbols (now on the .sdecl list) and assign numbers to
243 // them. We also pick which symbols should be global or not here.
244 for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
246 // Always export debug symbols. Don't force them global.
247 if (DBGSYM == sy->stype) {
251 buf = construct(buf, sy, 0);
256 if (sy->stype != LABEL)
259 // Nuke equated register/CC symbols from orbit:
260 if (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC))
263 // Export or import external references, and export COMMON blocks.
264 // N.B.: This says to mark the symbol as global if either 1) the symbol
265 // is global AND the symbol is defined OR referenced, or 2) this
266 // symbol is a common symbol.
267 if (((sy->sattr & GLOBAL) && (sy->sattr & (DEFINED | REFERENCED)))
268 || (sy->sattr & COMMON))
273 buf = construct(buf, sy, 1);
275 // Export vanilla labels (but don't make them global). An exception is
276 // made for equates, which are not exported unless they are referenced.
277 // ^^^ The above just might be bullshit. ^^^
278 // N.B.: This says if the symbol is either defined OR referenced (but
279 // because of the above we know it *won't* be GLOBAL). And
280 // lsym_flag is always set true in Process() in rmac.c.
281 else if (lsym_flag && (sy->sattr & (DEFINED | REFERENCED)))
286 buf = construct(buf, sy, 0);
294 // Custom version of AssignSymbolNos for ELF .o files.
295 // The order that the symbols should be dumped is different.
296 // (globals must be explicitly at the end of the table)
298 // N.B.: It should be possible to merge this with AssignSymbolNos, as there's
299 // nothing really ELF specific in here, other than the "globals go at the
300 // end of the queue" thing, which doesn't break the others. :-P
301 uint32_t AssignSymbolNosELF(uint8_t * buf, uint8_t *(* construct)())
305 // Append all symbols not appearing on the .sdecl list to the end of
307 for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
308 AddToSymbolDeclarationList(sy);
310 // Run through all symbols (now on the .sdecl list) and assign numbers to
311 // them. We also pick which symbols should be global or not here.
312 for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
314 // Export vanilla labels (but don't make them global). An exception is
315 // made for equates, which are not exported unless they are referenced.
316 if (sy->stype == LABEL && lsym_flag
317 && (sy->sattr & (DEFINED | REFERENCED)) != 0
318 && (*sy->sname != '.')
319 && (sy->sattr & GLOBAL) == 0
320 && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0)
325 buf = construct(buf, sy, 0);
329 firstglobal = scount;
331 // For ELF object mode run through all symbols in reference order
332 // and export all global-referenced labels. Not sure if this is
333 // required but it's here nonetheless
335 for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
337 if ((sy->stype == LABEL)
338 && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0
339 && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
340 || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
341 || (sy->sattr & COMMON))
346 buf = construct(buf, sy, 1);
348 else if ((sy->sattr == (GLOBAL | REFERENCED)) && (buf != NULL) && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0)
350 buf = construct(buf, sy, 0); // <-- this creates a NON-global symbol...
359 // Helper function for dsp_lod_symbols
361 static uint16_t WriteLODSection(int section, uint16_t symbolCount)
363 for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
365 // Export vanilla labels (but don't make them global). An exception is
366 // made for equates, which are not exported unless they are referenced.
367 if (sy->stype == LABEL && lsym_flag
368 && (sy->sattr & (DEFINED | REFERENCED)) != 0
369 && (*sy->sname != '.')
370 && (sy->sattr & GLOBAL) == 0
371 && (sy->sattr & (section)))
373 sy->senv = symbolCount++;
374 D_printf("%-19s I %.6" PRIX64 "\n", sy->sname, sy->svalue);
382 // Dump LOD style symbols into the passed in buffer
384 void DumpLODSymbols(void)
386 D_printf("_SYMBOL P\n");
387 uint16_t count = WriteLODSection(M56001P, 0);
389 D_printf("_SYMBOL X\n");
390 count = WriteLODSection(M56001X, count);
392 D_printf("_SYMBOL Y\n");
393 count = WriteLODSection(M56001Y, count);
395 D_printf("_SYMBOL L\n");
396 count = WriteLODSection(M56001L, count);
398 // TODO: I've seen _SYMBOL N in there but no idea what symbols it needs...
399 //D_printf("_SYMBOL N\n");
400 //WriteLODSection(M56001?, count);
404 // Convert string to uppercase
406 void ToUppercase(uint8_t * s)
410 if (*s >= 'a' && *s <= 'z')
416 // Generate symbol table for listing file
433 int colhei = pagelen - 5;
435 // Allocate storage for list headers and partition all labels. Throw away
436 // macros and macro arguments.
437 SYM ** sy = (SYM **)malloc(128 * sizeof(SYM **));
442 for(i=0; i<NBUCKETS; i++)
444 for(p=symbolTable[i]; p!=NULL; p=k)
451 if ((p->stype != LABEL) || (p->sattre & UNDEF_EQUR))
454 for(q=sy[j]; q!=NULL; q=q->snext)
456 if (strcmp(p->sname, q->sname) < 0)
464 // Insert at front of list
470 // Insert in middle or append to list
477 // Link all symbols onto one list again
482 if ((r = sy[i]) != NULL)
489 while (q->snext != NULL)
498 strcpy(subttl, "Symbol Table");
506 for(j=0; j<colhei; j++)
515 for(i=0; i<colhei; i++)
519 if (colptr[0] == NULL)
524 if ((q = colptr[j]) == NULL)
527 colptr[j] = q->snext;
532 // x external reference
534 // space nothing special
540 else if ((w & (DEFINED | GLOBAL)) == GLOBAL)
545 c1 = tdb_text[w & TDB];
548 strcpy(ln2, "external");
551 sprintf(ln2, "%016lX", q->svalue);
555 sprintf(ln1, " %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
568 SYM * NewDebugSymbol(const uint8_t * str, uint8_t type, uint8_t other, uint16_t desc)
570 SYM * symbol = NewSymbol(str, DBGSYM, 0);
573 fatal("Could not allocate space for debug symbol");
575 AddToSymbolDeclarationList(symbol);
577 symbol->st_type = type;
578 symbol->st_other = other;
579 symbol->st_desc = desc;
584 char *FilePath(const char * fname)
590 if ((fpath = realpath(fname, NULL)) != NULL)
593 for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
597 // Append path char if necessary
598 if (j > 0 && buf1[j - 1] != SLASHCHAR)
599 strcat(buf1, SLASHSTRING);
603 if ((fpath = realpath(buf1, NULL)) != NULL)
610 static void GenFileSym(const char * fname, uint8_t type, uint32_t addr, uint32_t sattr)
614 if (!(fpath = FilePath(fname)))
616 // Don't treat this as an error. Any file rmac can read is valid enough.
617 // Just use the relative filename in place of an absolute path for the
618 // debug information.
619 fpath = strdup(fname);
622 fatal("Could not allocate memory for fake path name");
625 SYM * symbol = NewDebugSymbol(fpath, type, 0, 0);
629 symbol->svalue = addr;
630 symbol->sattr |= sattr;
633 void GenMainFileSym(const char * fname)
635 GenFileSym(fname, 0x64 /* N_SO */, 0, DEFINED | TEXT);
638 void GenLineNoSym(void)
645 static uint16_t prevlineno = -1;
646 static uint32_t prevaddr = -1;
647 static uint16_t prevfileno = 0;
652 sattr = ABS | DEFINED | EQUATED;
653 // 0x4c is N_FLINE, function start/body/end line number, repurposed by
654 // MADMAC/ALN for ABS line numbers.
660 sattr = DEFINED | cursect;
661 type = 0x44; // N_SLINE, text section line number
664 if ((addr == prevaddr) || ((curlineno == prevlineno) && (prevfileno == cfileno)))
668 prevlineno = curlineno;
670 if (prevfileno != cfileno)
671 GenFileSym(curfname, 0x84 /* N_SOL */, addr, sattr);
673 prevfileno = cfileno;
675 /* MADMAC counts lines starting at 0. Offset curlineno accordingly */
676 symbol = NewDebugSymbol(NULL, type, 0, curlineno - 1);
678 symbol->svalue = addr;
679 symbol->sattr |= sattr;