]> Shamusworld >> Repos - rmac/blob - symbol.c
Version bump for last commit. :-)
[rmac] / symbol.c
1 //
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
7 //
8
9 #include "symbol.h"
10 #include "dsp56k.h"
11 #include "error.h"
12 #include "listing.h"
13 #include "object.h"
14 #include "procln.h"
15
16
17 // Macros
18 #define NBUCKETS 256                            // Number of hash buckets (power of 2)
19
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.
28
29 // Tags for marking symbol spaces:
30 // a = absolute
31 // t = text
32 // d = data
33 // ! = "impossible!"
34 // b = BSS
35 static uint8_t tdb_text[8] = {
36    'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE
37 };
38
39 // Internal function prototypes
40 static uint16_t WriteLODSection(int, uint16_t);
41
42 //
43 // Initialize symbol table
44 //
45 void InitSymbolTable(void)
46 {
47         for(int i=0; i<NBUCKETS; i++)                   // Initialise symbol hash table
48                 symbolTable[i] = NULL;
49
50         curenv = 1;                                                             // Init local symbol enviroment
51         sorder = NULL;                                                  // Init symbol-reference list
52         sordtail = NULL;
53         sdecl = NULL;                                                   // Init symbol-decl list
54         sdecltail = NULL;
55         currentUID = 0;
56 }
57
58 //
59 // Hash the ASCII name and enviroment number
60 //
61 int HashSymbol(const uint8_t * name, int envno)
62 {
63         int sum = envno, k = 0;
64
65         for(; *name; name++)
66         {
67                 if (k++ == 1)
68                         sum += *name << 2;
69                 else
70                         sum += *name;
71         }
72
73         return sum & (NBUCKETS - 1);
74 }
75
76 //
77 // Make a new symbol of type 'type' in enviroment 'envno'
78 //
79 SYM * NewSymbol(const uint8_t * name, int type, int envno)
80 {
81         // Allocate the symbol
82         SYM * symbol = malloc(sizeof(SYM));
83
84         if (symbol == NULL)
85         {
86                 printf("NewSymbol: MALLOC ERROR (symbol=\"%s\")\n", name);
87                 return NULL;
88         }
89
90         // Fill-in the symbol
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!
95         symbol->sattr  = 0;
96         // We don't set RISCSYM here as not every symbol first seen in a RISC
97         // section is a RISC symbol!
98         symbol->sattre = 0;
99         symbol->svalue = 0;
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.
106
107         // Record filename the symbol is defined (Used by macro error reporting and some debug symbols)
108         symbol->cfileno = cfileno;
109
110         // Don't hash debug symbols: they are never looked up and may have no name.
111         if (type != DBGSYM)
112         {
113                 // Install symbol in the symbol table
114                 int hash = HashSymbol(name, envno);
115                 symbol->snext = symbolTable[hash];
116                 symbolTable[hash] = symbol;
117         }
118
119         // Append symbol to the symbol-order list
120         if (sorder == NULL)
121                 sorder = symbol;                                        // Add first symbol
122         else
123                 sordtail->sorder = symbol;                      // Or append to tail of list
124
125         sordtail = symbol;
126         return symbol;
127 }
128
129 //
130 // Look up the symbol name by its UID and return the pointer to the name.
131 // If it's not found, return NULL.
132 //
133 uint8_t * GetSymbolNameByUID(uint32_t uid)
134 {
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
137
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;
143
144         for(; symbol; symbol=symbol->sorder)
145         {
146                 if (symbol->uid == uid)
147                         return symbol->sname;
148         }
149
150         return NULL;
151 }
152
153 //
154 // Lookup the symbol 'name', of the specified type, with the specified
155 // enviroment level
156 //
157 SYM * lookup(uint8_t * name, int type, int envno)
158 {
159         SYM * symbol = symbolTable[HashSymbol(name, envno)];
160
161         // Do linear-search for symbol in bucket
162         while (symbol != NULL)
163         {
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
168                         break;
169
170                 symbol = symbol->snext;
171         }
172
173         // Return NULL or matching symbol
174         return symbol;
175 }
176
177 //
178 // Put symbol on "order-of-declaration" list of symbols
179 //
180 void AddToSymbolDeclarationList(SYM * symbol)
181 {
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)))
185                 return;
186
187         // Mark as "on .sdecl list"
188         symbol->sattr |= SDECLLIST;
189
190         if (sdecl == NULL)
191                 sdecl = symbol;                         // First on decl-list
192         else
193                 sdecltail->sdecl = symbol;      // Add to end of list
194
195         // Fix up list's tail
196         symbol->sdecl = NULL;
197         sdecltail = symbol;
198 }
199
200 //
201 // Make all referenced, undefined symbols global
202 //
203 void ForceUndefinedSymbolsGlobal(void)
204 {
205         SYM * sy;
206
207         DEBUG printf("~ForceUndefinedSymbolsGlobal()\n");
208
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)
212         {
213                 if (sy->stype == LABEL && sy->senv == 0
214                         && ((sy->sattr & (REFERENCED | DEFINED)) == REFERENCED))
215                         sy->sattr |= GLOBAL;
216         }
217 }
218
219 //
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
222 // symbol table.
223 //
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.
228 //
229 uint32_t AssignSymbolNos(uint8_t * buf, uint8_t *(* construct)())
230 {
231         uint16_t scount = 0;
232
233         // Done only on first pass...
234         if (buf == NULL)
235         {
236                 // Append all symbols not appearing on the .sdecl list to the end of
237                 // the .sdecl list
238                 for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
239                         AddToSymbolDeclarationList(sy);
240         }
241
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)
245         {
246                 // Always export debug symbols. Don't force them global.
247                 if (DBGSYM == sy->stype) {
248                         sy->senv = scount++;
249
250                         if (buf != NULL)
251                                 buf = construct(buf, sy, 0);
252                         continue;
253                 }
254
255                 // Skip non-labels.
256                 if (sy->stype != LABEL)
257                         continue;
258
259                 // Nuke equated register/CC symbols from orbit:
260                 if (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC))
261                         continue;
262
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))
269                 {
270                         sy->senv = scount++;
271
272                         if (buf != NULL)
273                                 buf = construct(buf, sy, 1);
274                 }
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)))
282                 {
283                         sy->senv = scount++;
284
285                         if (buf != NULL)
286                                 buf = construct(buf, sy, 0);
287                 }
288         }
289
290         return scount;
291 }
292
293 //
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)
297 //
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)())
302 {
303         uint16_t scount = 0;
304
305         // Append all symbols not appearing on the .sdecl list to the end of
306         // the .sdecl list
307         for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
308                 AddToSymbolDeclarationList(sy);
309
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)
313         {
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)
321                 {
322                         sy->senv = scount++;
323
324                         if (buf != NULL)
325                                 buf = construct(buf, sy, 0);
326                 }
327         }
328
329         firstglobal = scount;
330
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
334
335         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
336         {
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))
342                 {
343                         sy->senv = scount++;
344
345                         if (buf != NULL)
346                                 buf = construct(buf, sy, 1);
347                 }
348                 else if ((sy->sattr == (GLOBAL | REFERENCED)) &&  (buf != NULL) && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0)
349                 {
350                         buf = construct(buf, sy, 0); // <-- this creates a NON-global symbol...
351                         scount++;
352                 }
353         }
354
355         return scount;
356 }
357
358 //
359 // Helper function for dsp_lod_symbols
360 //
361 static uint16_t WriteLODSection(int section, uint16_t symbolCount)
362 {
363         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
364         {
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)))
372                 {
373                         sy->senv = symbolCount++;
374                         D_printf("%-19s   I %.6" PRIX64 "\n", sy->sname, sy->svalue);
375                 }
376         }
377
378         return symbolCount;
379 }
380
381 //
382 // Dump LOD style symbols into the passed in buffer
383 //
384 void DumpLODSymbols(void)
385 {
386         D_printf("_SYMBOL P\n");
387         uint16_t count = WriteLODSection(M56001P, 0);
388
389         D_printf("_SYMBOL X\n");
390         count = WriteLODSection(M56001X, count);
391
392         D_printf("_SYMBOL Y\n");
393         count = WriteLODSection(M56001Y, count);
394
395         D_printf("_SYMBOL L\n");
396         count = WriteLODSection(M56001L, count);
397
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);
401 }
402
403 //
404 // Convert string to uppercase
405 //
406 void ToUppercase(uint8_t * s)
407 {
408         for(; *s; s++)
409         {
410                 if (*s >= 'a' && *s <= 'z')
411                         *s -= 0x20;
412         }
413 }
414
415 //
416 // Generate symbol table for listing file
417 //
418 int symtable(void)
419 {
420         int i;
421         int j;
422         SYM * q = NULL;
423         SYM * p;
424         SYM * r;
425         SYM * k;
426         SYM * colptr[4];
427         char ln[1024];
428         char ln1[1024];
429         char ln2[20];
430         char c, c1;
431         WORD w;
432         int ww;
433         int colhei = pagelen - 5;
434
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 **));
438
439         for(i=0; i<128; i++)
440                 sy[i] = NULL;
441
442         for(i=0; i<NBUCKETS; i++)
443         {
444                 for(p=symbolTable[i]; p!=NULL; p=k)
445                 {
446                         k = p->snext;
447                         j = *p->sname;
448                         r = NULL;
449
450                         // Ignore non-labels
451                         if ((p->stype != LABEL) || (p->sattre & UNDEF_EQUR))
452                                 continue;
453
454                         for(q=sy[j]; q!=NULL; q=q->snext)
455                         {
456                                 if (strcmp(p->sname, q->sname) < 0)
457                                         break;
458
459                                 r = q;
460                         }
461
462                         if (r == NULL)
463                         {
464                                 // Insert at front of list
465                                 p->snext = sy[j];
466                                 sy[j] = p;
467                         }
468                         else
469                         {
470                                 // Insert in middle or append to list
471                                 p->snext = r->snext;
472                                 r->snext = p;
473                         }
474                 }
475         }
476
477         // Link all symbols onto one list again
478         p = NULL;
479
480         for(i=0; i<128; ++i)
481         {
482                 if ((r = sy[i]) != NULL)
483                 {
484                         if (p == NULL)
485                                 q = r;
486                         else
487                                 q->snext = r;
488
489                         while (q->snext != NULL)
490                                 q = q->snext;
491
492                         if (p == NULL)
493                                 p = r;
494                 }
495         }
496
497         eject();
498         strcpy(subttl, "Symbol Table");
499
500         while (p != NULL)
501         {
502                 for(i=0; i<4; i++)
503                 {
504                         colptr[i] = p;
505
506                         for(j=0; j<colhei; j++)
507                         {
508                                 if (p == NULL)
509                                         break;
510                                 else
511                                         p = p->snext;
512                         }
513                 }
514
515                 for(i=0; i<colhei; i++)
516                 {
517                         *ln = EOS;
518
519                         if (colptr[0] == NULL)
520                                 break;
521
522                         for(j=0; j<4; j++)
523                         {
524                                 if ((q = colptr[j]) == NULL)
525                                         break;
526
527                                 colptr[j] = q->snext;
528                                 w = q->sattr;
529                                 ww = q->sattre;
530                                 // Pick a tag:
531                                 // c    common
532                                 // x    external reference
533                                 // g    global (export)
534                                 // space        nothing special
535                                 c1 = SPACE;
536                                 c = SPACE;
537
538                                 if (w & COMMON)
539                                         c = 'c';
540                                 else if ((w & (DEFINED | GLOBAL)) == GLOBAL)
541                                         c = 'x';
542                                 else if (w & GLOBAL)
543                                         c = 'g';
544
545                                 c1 = tdb_text[w & TDB];
546
547                                 if (c == 'x')
548                                         strcpy(ln2, "external");
549                                 else
550                                 {
551                                         sprintf(ln2, "%016lX", q->svalue);
552                                         ToUppercase(ln2);
553                                 }
554
555                                 sprintf(ln1, "  %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
556                                 strcat(ln, ln1);
557                         }
558
559                         ship_ln(ln);
560                 }
561
562                 eject();
563         }
564
565         return 0;
566 }
567
568 SYM * NewDebugSymbol(const uint8_t * str, uint8_t type, uint8_t other, uint16_t desc)
569 {
570         SYM * symbol = NewSymbol(str, DBGSYM, 0);
571
572         if (NULL == symbol)
573                 fatal("Could not allocate space for debug symbol");
574
575         AddToSymbolDeclarationList(symbol);
576
577         symbol->st_type = type;
578         symbol->st_other = other;
579         symbol->st_desc = desc;
580
581         return symbol;
582 }
583
584 char *FilePath(const char * fname)
585 {
586         char buf1[256];
587         char * fpath;
588         int i, j;
589
590         if ((fpath = realpath(fname, NULL)) != NULL)
591                 return fpath;
592
593         for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
594         {
595                 j = strlen(buf1);
596
597                 // Append path char if necessary
598                 if (j > 0 && buf1[j - 1] != SLASHCHAR)
599                         strcat(buf1, SLASHSTRING);
600
601                 strcat(buf1, fname);
602
603                 if ((fpath = realpath(buf1, NULL)) != NULL)
604                         return fpath;
605         }
606
607         return NULL;
608 }
609
610 static void GenFileSym(const char * fname, uint8_t type, uint32_t addr, uint32_t sattr)
611 {
612         char *fpath;
613
614         if (!(fpath = FilePath(fname)))
615         {
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);
620
621                 if (!fpath)
622                         fatal("Could not allocate memory for fake path name");
623         }
624
625         SYM * symbol = NewDebugSymbol(fpath, type, 0, 0);
626
627         free(fpath);
628
629         symbol->svalue = addr;
630         symbol->sattr |= sattr;
631 }
632
633 void GenMainFileSym(const char * fname)
634 {
635         GenFileSym(fname, 0x64 /* N_SO */, 0, DEFINED | TEXT);
636 }
637
638 void GenLineNoSym(void)
639 {
640         uint32_t addr;
641         uint32_t sattr;
642         uint8_t type;
643         SYM * symbol;
644
645         static uint16_t prevlineno = -1;
646         static uint32_t prevaddr = -1;
647         static uint16_t prevfileno = 0;
648
649         if (orgactive)
650         {
651                 addr = orgaddr;
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.
655                 type = 0x4c;
656         }
657         else
658         {
659                 addr = pcloc;
660                 sattr = DEFINED | cursect;
661                 type = 0x44; // N_SLINE, text section line number
662         }
663
664         if ((addr == prevaddr) || ((curlineno == prevlineno) && (prevfileno == cfileno)))
665                 return;
666
667         prevaddr = addr;
668         prevlineno = curlineno;
669
670         if (prevfileno != cfileno)
671                 GenFileSym(curfname, 0x84 /* N_SOL */, addr, sattr);
672
673         prevfileno = cfileno;
674
675         /* MADMAC counts lines starting at 0. Offset curlineno accordingly */
676         symbol = NewDebugSymbol(NULL, type, 0, curlineno - 1);
677
678         symbol->svalue = addr;
679         symbol->sattr |= sattr;
680 }