]> Shamusworld >> Repos - rmac/blob - symbol.c
Fix to prevent defined registers/CCs from being exported in the symtab.
[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(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(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  = strdup(name);
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
103         // Record filename the symbol is defined (for now only used by macro error reporting)
104         symbol->cfileno = cfileno;
105
106         // Install symbol in the symbol table
107         int hash = HashSymbol(name, envno);
108         symbol->snext = symbolTable[hash];
109         symbolTable[hash] = symbol;
110
111         // Append symbol to the symbol-order list
112         if (sorder == NULL)
113                 sorder = symbol;                                        // Add first symbol
114         else
115                 sordtail->sorder = symbol;                      // Or append to tail of list
116
117         sordtail = symbol;
118         return symbol;
119 }
120
121 //
122 // Look up the symbol name by its UID and return the pointer to the name.
123 // If it's not found, return NULL.
124 //
125 uint8_t * GetSymbolNameByUID(uint32_t uid)
126 {
127         //problem is with string lookup, that's why we're writing this
128         //so once this is written, we can put the uid in the token stream
129
130         // A much better approach to the symbol order list would be to make an
131         // array--that way you can do away with the UIDs and all the rest, and
132         // simply do an array lookup based on position. But meh, let's do this for
133         // now until we can rewrite things so they make sense.
134         SYM * symbol = sorder;
135
136         for(; symbol; symbol=symbol->sorder)
137         {
138                 if (symbol->uid == uid)
139                         return symbol->sname;
140         }
141
142         return NULL;
143 }
144
145 //
146 // Lookup the symbol 'name', of the specified type, with the specified
147 // enviroment level
148 //
149 SYM * lookup(uint8_t * name, int type, int envno)
150 {
151         SYM * symbol = symbolTable[HashSymbol(name, envno)];
152
153         // Do linear-search for symbol in bucket
154         while (symbol != NULL)
155         {
156                 if (symbol->stype == type                       // Type, envno and name must match
157                         && symbol->senv  == envno
158                         && *name == *symbol->sname              // Fast check for first character
159                         && !strcmp(name, symbol->sname))        // More expensive check
160                         break;
161
162                 symbol = symbol->snext;
163         }
164
165         // Return NULL or matching symbol
166         return symbol;
167 }
168
169 //
170 // Put symbol on "order-of-declaration" list of symbols
171 //
172 void AddToSymbolDeclarationList(SYM * symbol)
173 {
174         // Don't add if already on list, or it's an equated register/CC
175         if ((symbol->sattr & SDECLLIST)
176                 || (symbol->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)))
177                 return;
178
179         // Mark as "on .sdecl list"
180         symbol->sattr |= SDECLLIST;
181
182         if (sdecl == NULL)
183                 sdecl = symbol;                         // First on decl-list
184         else
185                 sdecltail->sdecl = symbol;      // Add to end of list
186
187         // Fix up list's tail
188         symbol->sdecl = NULL;
189         sdecltail = symbol;
190 }
191
192 //
193 // Make all referenced, undefined symbols global
194 //
195 void ForceUndefinedSymbolsGlobal(void)
196 {
197         SYM * sy;
198
199         DEBUG printf("~ForceUndefinedSymbolsGlobal()\n");
200
201         // Scan through all symbols; if a symbol is REFERENCED but not DEFINED,
202         // then make it global.
203         for(sy=sorder; sy!=NULL; sy=sy->sorder)
204         {
205                 if (sy->stype == LABEL && sy->senv == 0
206                         && ((sy->sattr & (REFERENCED | DEFINED)) == REFERENCED))
207                         sy->sattr |= GLOBAL;
208         }
209 }
210
211 //
212 // Assign numbers to symbols that are to be exported or imported. The symbol
213 // number is put in 'senv'. Returns the number of symbols that will be in the
214 // symbol table.
215 //
216 // N.B.: This is usually called twice; first time with NULL parameters and the
217 //       second time with real ones. The first one is typically done to get a
218 //       count of the # of symbols in the symbol table, and the second is to
219 //       actually create it.
220 //
221 uint32_t AssignSymbolNos(uint8_t * buf, uint8_t *(* construct)())
222 {
223         uint16_t scount = 0;
224
225         // Done only on first pass...
226         if (buf == NULL)
227         {
228                 // Append all symbols not appearing on the .sdecl list to the end of
229                 // the .sdecl list
230                 for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
231                         AddToSymbolDeclarationList(sy);
232         }
233
234         // Run through all symbols (now on the .sdecl list) and assign numbers to
235         // them. We also pick which symbols should be global or not here.
236         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
237         {
238                 // Skip non-labels
239                 if (sy->stype != LABEL)
240                         continue;
241
242                 // Nuke equated register/CC symbols from orbit:
243                 if (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC))
244                         continue;
245
246                 // Export or import external references, and export COMMON blocks.
247                 // N.B.: This says to mark the symbol as global if either 1) the symbol
248                 //       is global AND the symbol is defined OR referenced, or 2) this
249                 //       symbol is a common symbol.
250                 if (((sy->sattr & GLOBAL) && (sy->sattr & (DEFINED | REFERENCED)))
251                         || (sy->sattr & COMMON))
252                 {
253                         sy->senv = scount++;
254
255                         if (buf != NULL)
256                                 buf = construct(buf, sy, 1);
257                 }
258                 // Export vanilla labels (but don't make them global). An exception is
259                 // made for equates, which are not exported unless they are referenced.
260                 // ^^^ The above just might be bullshit. ^^^
261                 // N.B.: This says if the symbol is either defined OR referenced (but
262                 //       because of the above we know it *won't* be GLOBAL).  And
263                 //       lsym_flag is always set true in Process() in rmac.c.
264                 else if (lsym_flag && (sy->sattr & (DEFINED | REFERENCED)))
265                 {
266                         sy->senv = scount++;
267
268                         if (buf != NULL)
269                                 buf = construct(buf, sy, 0);
270                 }
271         }
272
273         return scount;
274 }
275
276 //
277 // Custom version of AssignSymbolNos for ELF .o files.
278 // The order that the symbols should be dumped is different.
279 // (globals must be explicitly at the end of the table)
280 //
281 // N.B.: It should be possible to merge this with AssignSymbolNos, as there's
282 //       nothing really ELF specific in here, other than the "globals go at the
283 //       end of the queue" thing, which doesn't break the others. :-P
284 uint32_t AssignSymbolNosELF(uint8_t * buf, uint8_t *(* construct)())
285 {
286         uint16_t scount = 0;
287
288         // Append all symbols not appearing on the .sdecl list to the end of
289         // the .sdecl list
290         for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
291                 AddToSymbolDeclarationList(sy);
292
293         // Run through all symbols (now on the .sdecl list) and assign numbers to
294         // them. We also pick which symbols should be global or not here.
295         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
296         {
297                 // Export vanilla labels (but don't make them global). An exception is
298                 // made for equates, which are not exported unless they are referenced.
299                 if (sy->stype == LABEL && lsym_flag
300                         && (sy->sattr & (DEFINED | REFERENCED)) != 0
301                         && (*sy->sname != '.')
302                         && (sy->sattr & GLOBAL) == 0
303                         && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0)
304                 {
305                         sy->senv = scount++;
306
307                         if (buf != NULL)
308                                 buf = construct(buf, sy, 0);
309                 }
310         }
311
312         firstglobal = scount;
313
314         // For ELF object mode run through all symbols in reference order
315         // and export all global-referenced labels. Not sure if this is
316         // required but it's here nonetheless
317
318         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
319         {
320                 if ((sy->stype == LABEL)
321                         && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0
322                         && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
323                         || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
324                         || (sy->sattr & COMMON))
325                 {
326                         sy->senv = scount++;
327
328                         if (buf != NULL)
329                                 buf = construct(buf, sy, 1);
330                 }
331                 else if ((sy->sattr == (GLOBAL | REFERENCED)) &&  (buf != NULL) && (sy->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)) == 0)
332                 {
333                         buf = construct(buf, sy, 0); // <-- this creates a NON-global symbol...
334                         scount++;
335                 }
336         }
337
338         return scount;
339 }
340
341 //
342 // Helper function for dsp_lod_symbols
343 //
344 static uint16_t WriteLODSection(int section, uint16_t symbolCount)
345 {
346         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
347         {
348                 // Export vanilla labels (but don't make them global). An exception is
349                 // made for equates, which are not exported unless they are referenced.
350                 if (sy->stype == LABEL && lsym_flag
351                         && (sy->sattr & (DEFINED | REFERENCED)) != 0
352                         && (*sy->sname != '.')
353                         && (sy->sattr & GLOBAL) == 0
354                         && (sy->sattr & (section)))
355                 {
356                         sy->senv = symbolCount++;
357                         D_printf("%-19s   I %.6" PRIX64 "\n", sy->sname, sy->svalue);
358                 }
359         }
360
361         return symbolCount;
362 }
363
364 //
365 // Dump LOD style symbols into the passed in buffer
366 //
367 void DumpLODSymbols(void)
368 {
369         D_printf("_SYMBOL P\n");
370         uint16_t count = WriteLODSection(M56001P, 0);
371
372         D_printf("_SYMBOL X\n");
373         count = WriteLODSection(M56001X, count);
374
375         D_printf("_SYMBOL Y\n");
376         count = WriteLODSection(M56001Y, count);
377
378         D_printf("_SYMBOL L\n");
379         count = WriteLODSection(M56001L, count);
380
381         // TODO: I've seen _SYMBOL N in there but no idea what symbols it needs...
382         //D_printf("_SYMBOL N\n");
383         //WriteLODSection(M56001?, count);
384 }
385
386 //
387 // Convert string to uppercase
388 //
389 void ToUppercase(uint8_t * s)
390 {
391         for(; *s; s++)
392         {
393                 if (*s >= 'a' && *s <= 'z')
394                         *s -= 0x20;
395         }
396 }
397
398 //
399 // Generate symbol table for listing file
400 //
401 int symtable(void)
402 {
403         int i;
404         int j;
405         SYM * q = NULL;
406         SYM * p;
407         SYM * r;
408         SYM * k;
409         SYM * colptr[4];
410         char ln[1024];
411         char ln1[1024];
412         char ln2[20];
413         char c, c1;
414         WORD w;
415         int ww;
416         int colhei = pagelen - 5;
417
418         // Allocate storage for list headers and partition all labels. Throw away
419         // macros and macro arguments.
420         SYM ** sy = (SYM **)malloc(128 * sizeof(SYM **));
421
422         for(i=0; i<128; i++)
423                 sy[i] = NULL;
424
425         for(i=0; i<NBUCKETS; i++)
426         {
427                 for(p=symbolTable[i]; p!=NULL; p=k)
428                 {
429                         k = p->snext;
430                         j = *p->sname;
431                         r = NULL;
432
433                         // Ignore non-labels
434                         if ((p->stype != LABEL) || (p->sattre & UNDEF_EQUR))
435                                 continue;
436
437                         for(q=sy[j]; q!=NULL; q=q->snext)
438                         {
439                                 if (strcmp(p->sname, q->sname) < 0)
440                                         break;
441
442                                 r = q;
443                         }
444
445                         if (r == NULL)
446                         {
447                                 // Insert at front of list
448                                 p->snext = sy[j];
449                                 sy[j] = p;
450                         }
451                         else
452                         {
453                                 // Insert in middle or append to list
454                                 p->snext = r->snext;
455                                 r->snext = p;
456                         }
457                 }
458         }
459
460         // Link all symbols onto one list again
461         p = NULL;
462
463         for(i=0; i<128; ++i)
464         {
465                 if ((r = sy[i]) != NULL)
466                 {
467                         if (p == NULL)
468                                 q = r;
469                         else
470                                 q->snext = r;
471
472                         while (q->snext != NULL)
473                                 q = q->snext;
474
475                         if (p == NULL)
476                                 p = r;
477                 }
478         }
479
480         eject();
481         strcpy(subttl, "Symbol Table");
482
483         while (p != NULL)
484         {
485                 for(i=0; i<4; i++)
486                 {
487                         colptr[i] = p;
488
489                         for(j=0; j<colhei; j++)
490                         {
491                                 if (p == NULL)
492                                         break;
493                                 else
494                                         p = p->snext;
495                         }
496                 }
497
498                 for(i=0; i<colhei; i++)
499                 {
500                         *ln = EOS;
501
502                         if (colptr[0] == NULL)
503                                 break;
504
505                         for(j=0; j<4; j++)
506                         {
507                                 if ((q = colptr[j]) == NULL)
508                                         break;
509
510                                 colptr[j] = q->snext;
511                                 w = q->sattr;
512                                 ww = q->sattre;
513                                 // Pick a tag:
514                                 // c    common
515                                 // x    external reference
516                                 // g    global (export)
517                                 // space        nothing special
518                                 c1 = SPACE;
519                                 c = SPACE;
520
521                                 if (w & COMMON)
522                                         c = 'c';
523                                 else if ((w & (DEFINED | GLOBAL)) == GLOBAL)
524                                         c = 'x';
525                                 else if (w & GLOBAL)
526                                         c = 'g';
527
528                                 c1 = tdb_text[w & TDB];
529
530                                 if (c == 'x')
531                                         strcpy(ln2, "external");
532                                 else
533                                 {
534                                         sprintf(ln2, "%016lX", q->svalue);
535                                         ToUppercase(ln2);
536                                 }
537
538                                 sprintf(ln1, "  %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
539                                 strcat(ln, ln1);
540                         }
541
542                         ship_ln(ln);
543                 }
544
545                 eject();
546         }
547
548         return 0;
549 }