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