Multiple fixes for 020+ mode, including:
[rmac] / symbol.c
1 //
2 // RMAC - Reboot's Macro Assembler for all Atari computers
3 // SYMBOL.C - Symbol Handling
4 // Copyright (C) 199x Landon Dyer, 2011-2017 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 "error.h"
11 #include "listing.h"
12 #include "object.h"
13 #include "procln.h"
14
15
16 // Macros
17 #define NBUCKETS 256                            // Number of hash buckets (power of 2)
18
19 static SYM * symbolTable[NBUCKETS];     // User symbol-table header
20 int curenv;                                                     // Current enviroment number
21 static SYM * sorder;                            // * -> Symbols, in order of reference
22 static SYM * sordtail;                          // * -> Last symbol in sorder list
23 static SYM * sdecl;                                     // * -> Symbols, in order of declaration
24 static SYM * sdecltail;                         // * -> Last symbol in sdecl list
25 static uint32_t currentUID;                     // Symbol UID tracking (done by NewSymbol())
26 uint32_t firstglobal; // Index of the first global symbol in an ELF object.
27
28 // Tags for marking symbol spaces:
29 // a = absolute
30 // t = text
31 // d = data
32 // ! = "impossible!"
33 // b = BSS
34 static uint8_t tdb_text[8] = {
35    'a', 't', 'd', '!', 'b', SPACE, SPACE, SPACE
36 };
37
38
39 //
40 // Initialize symbol table
41 //
42 void InitSymbolTable(void)
43 {
44         for(int i=0; i<NBUCKETS; i++)                   // Initialise symbol hash table
45                 symbolTable[i] = NULL;
46
47         curenv = 1;                                                             // Init local symbol enviroment
48         sorder = NULL;                                                  // Init symbol-reference list
49         sordtail = NULL;
50         sdecl = NULL;                                                   // Init symbol-decl list
51         sdecltail = NULL;
52         currentUID = 0;
53 }
54
55
56 //
57 // Hash the ASCII name and enviroment number
58 //
59 int HashSymbol(uint8_t * name, int envno)
60 {
61         int sum = envno, k = 0;
62
63         for(; *name; name++)
64         {
65                 if (k++ == 1)
66                         sum += *name << 2;
67                 else
68                         sum += *name;
69         }
70
71         return sum & (NBUCKETS - 1);
72 }
73
74
75 //
76 // Make a new symbol of type 'type' in enviroment 'envno'
77 //
78 SYM * NewSymbol(uint8_t * name, int type, int envno)
79 {
80         // Allocate the symbol
81         SYM * symbol = malloc(sizeof(SYM));
82
83         if (symbol == NULL)
84         {
85                 printf("NewSymbol: MALLOC ERROR (symbol=\"%s\")\n", name);
86                 return NULL;
87         }
88
89         // Fill-in the symbol
90         symbol->sname  = strdup(name);
91         symbol->stype  = (uint8_t)type;
92         symbol->senv   = (uint16_t)envno;
93         // We don't set this as DEFINED, as it could be a forward reference!
94         symbol->sattr  = 0;
95         // We don't set RISCSYM here as not every symbol first seen in a RISC
96         // section is a RISC symbol!
97         symbol->sattre = 0;
98         symbol->svalue = 0;
99         symbol->sorder = NULL;
100         symbol->uid    = currentUID++;
101
102         // Install symbol in the symbol table
103         int hash = HashSymbol(name, envno);
104         symbol->snext = symbolTable[hash];
105         symbolTable[hash] = symbol;
106
107         // Append symbol to the symbol-order list
108         if (sorder == NULL)
109                 sorder = symbol;                                        // Add first symbol
110         else
111                 sordtail->sorder = symbol;                      // Or append to tail of list
112
113         sordtail = symbol;
114         return symbol;
115 }
116
117
118 //
119 // Look up the symbol name by its UID and return the pointer to the name.
120 // If it's not found, return NULL.
121 //
122 uint8_t * GetSymbolNameByUID(uint32_t uid)
123 {
124         //problem is with string lookup, that's why we're writing this
125         //so once this is written, we can put the uid in the token stream
126
127         // A much better approach to the symbol order list would be to make an
128         // array--that way you can do away with the UIDs and all the rest, and
129         // simply do an array lookup based on position. But meh, let's do this for
130         // now until we can rewrite things so they make sense.
131         SYM * symbol = sorder;
132
133         for(; symbol; symbol=symbol->sorder)
134         {
135                 if (symbol->uid == uid)
136                         return symbol->sname;
137         }
138
139         return NULL;
140 }
141
142
143 //
144 // Lookup the symbol 'name', of the specified type, with the specified
145 // enviroment level
146 //
147 SYM * lookup(uint8_t * name, int type, int envno)
148 {
149         SYM * symbol = symbolTable[HashSymbol(name, envno)];
150
151         // Do linear-search for symbol in bucket
152         while (symbol != NULL)
153         {
154                 if (symbol->stype == type                       // Type, envno and name must match
155                         && symbol->senv  == envno
156                         && *name == *symbol->sname              // Fast check for first character
157                         && !strcmp(name, symbol->sname))        // More expensive check
158                         break;
159
160                 symbol = symbol->snext;
161         }
162
163         // Return NULL or matching symbol
164         return symbol;
165 }
166
167
168 //
169 // Put symbol on "order-of-declaration" list of symbols
170 //
171 void AddToSymbolDeclarationList(SYM * symbol)
172 {
173         // Don't add if already on list, or it's an equated register/CC
174         if ((symbol->sattr & SDECLLIST)
175                 || (symbol->sattre & (EQUATEDREG | UNDEF_EQUR | EQUATEDCC | UNDEF_CC)))
176                 return;
177
178         // Mark as "on .sdecl list"
179         symbol->sattr |= SDECLLIST;
180
181         if (sdecl == NULL)
182                 sdecl = symbol;                         // First on decl-list
183         else
184                 sdecltail->sdecl = symbol;      // Add to end of list
185
186         // Fix up list's tail
187         symbol->sdecl = NULL;
188         sdecltail = symbol;
189 }
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 //
213 // Assign numbers to symbols that are to be exported or imported. The symbol
214 // number is put in 'senv'. Returns the number of symbols that will be in the
215 // symbol table.
216 //
217 // N.B.: This is usually called twice; first time with NULL parameters and the
218 //       second time with real ones. The first one is typically done to get a
219 //       count of the # of symbols in the symbol table, and the second is to
220 //       actually create it.
221 //
222 uint32_t sy_assign(uint8_t * buf, uint8_t *(* construct)())
223 {
224         uint16_t scount = 0;
225
226         // Done only on first pass...
227         if (buf == NULL)
228         {
229                 // Append all symbols not appearing on the .sdecl list to the end of
230                 // the .sdecl list
231                 for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
232                         AddToSymbolDeclarationList(sy);
233         }
234
235         // Run through all symbols (now on the .sdecl list) and assign numbers to
236         // them. We also pick which symbols should be global or not here.
237         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
238         {
239                 // Export or import external references, and export COMMON blocks.
240                 if ((sy->stype == LABEL)
241                         && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
242                         || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
243                         || (sy->sattr & COMMON))
244                 {
245                         sy->senv = scount++;
246
247                         if (buf != NULL)
248                                 buf = construct(buf, sy, 1);
249                 }
250                 // Export vanilla labels (but don't make them global). An exception is
251                 // made for equates, which are not exported unless they are referenced.
252                 else if (sy->stype == LABEL && lsym_flag
253                         && (sy->sattr & (DEFINED | REFERENCED)) != 0
254                         && (!as68_flag || *sy->sname != 'L'))
255                 {
256                         sy->senv = scount++;
257
258                         if (buf != NULL)
259                                 buf = construct(buf, sy, 0);
260                 }
261         }
262
263         // For ELF object mode run through all symbols in reference order
264         // and export all global-referenced labels. Not sure if this is
265         // required but it's here nonetheless
266 /* why?? when you have sy_assign_ELF ???
267         if (obj_format == ELF)
268         {
269                 for(sy=sdecl; sy!=NULL; sy=sy->sorder)
270                 {
271                         if ((sy->sattr == (GLOBAL | REFERENCED)) && (buf != NULL))
272                         {
273                                 buf = (*construct)(buf, sy, 0);
274                                 scount++;
275                         }
276                 }
277         }*/
278
279         return scount;
280 }
281
282
283 //
284 // Custom version of sy_assign for ELF .o files.
285 // The order that the symbols should be dumped is different.
286 // (globals must be explicitly at the end of the table)
287 //
288 // N.B.: It should be possible to merge this with sy_assign, as there's nothing
289 //       really ELF specific in here, other than the "globals go at the end of
290 //       the queue" thing, which doesn't break the others. :-P
291 uint32_t sy_assign_ELF(uint8_t * buf, uint8_t *(* construct)())
292 {
293         uint16_t scount = 0;
294
295 //      if (construct == (uint8_t *(*)())constr_elfsymtab)
296 //      if (buf == NULL)
297         {
298                 // Append all symbols not appearing on the .sdecl list to the end of
299                 // the .sdecl list
300                 for(SYM * sy=sorder; sy!=NULL; sy=sy->sorder)
301                         AddToSymbolDeclarationList(sy);
302         }
303
304         // Run through all symbols (now on the .sdecl list) and assign numbers to
305         // them. We also pick which symbols should be global or not here.
306         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
307         {
308                 // Export or import external references, and export COMMON blocks.
309                 //if ((sy->stype == LABEL)
310                 //      && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
311                 //      || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
312                 //      || (sy->sattr & COMMON))
313                 //{
314                 //      sy->senv = (WORD)scount++;
315         //
316                 //      if (buf != NULL)
317                 //              buf = (*construct)(buf, sy, 1);
318                 //}
319                 // Export vanilla labels (but don't make them global). An exception is
320                 // made for equates, which are not exported unless they are referenced.
321                 if (sy->stype == LABEL && lsym_flag
322                         && (sy->sattr & (DEFINED | REFERENCED)) != 0
323                         && (*sy->sname != '.')
324                         && (sy->sattr & GLOBAL) == 0)
325                 //if (sy->stype == 0)
326                 //      if (lsym_flag)
327                 //              if ((sy->sattr & (DEFINED | REFERENCED)) != 0)
328                 //                      if ((!as68_flag || *sy->sname != 'L'))
329                 {
330                         sy->senv = scount++;
331
332                         if (buf != NULL)
333                                 buf = construct(buf, sy, 0);
334                 }
335         }
336
337         firstglobal = scount;
338
339         // For ELF object mode run through all symbols in reference order
340         // and export all global-referenced labels. Not sure if this is
341         // required but it's here nonetheless
342
343         //for(sy=sdecl; sy!=NULL; sy=sy->sorder)
344         for(SYM * sy=sdecl; sy!=NULL; sy=sy->sdecl)
345         {
346                 if ((sy->stype == LABEL)
347                         && ((sy->sattr & (GLOBAL | DEFINED)) == (GLOBAL | DEFINED)
348                         || (sy->sattr & (GLOBAL | REFERENCED)) == (GLOBAL | REFERENCED))
349                         || (sy->sattr & COMMON))
350                 {
351                         sy->senv = scount++;
352
353                         if (buf != NULL)
354                                 buf = construct(buf, sy, 1);
355                 }
356                 else if ((sy->sattr == (GLOBAL | REFERENCED)) &&  (buf != NULL))
357                 {
358                         buf = construct(buf, sy, 0);
359                         scount++;
360                 }
361         }
362
363         return scount;
364 }
365
366
367 //
368 // Convert string to uppercase
369 //
370 void ToUppercase(uint8_t * s)
371 {
372         for(; *s; s++)
373         {
374                 if (*s >= 'a' && *s <= 'z')
375                         *s -= 0x20;
376         }
377 }
378
379
380 //
381 // Generate symbol table for listing file
382 //
383 int symtable(void)
384 {
385         int i;
386         int j;
387         SYM * q = NULL;
388         SYM * p;
389         SYM * r;
390         SYM * k;
391         SYM * colptr[4];
392         char ln[1024];
393         char ln1[1024];
394         char ln2[20];
395         char c, c1;
396         WORD w;
397         int ww;
398         int colhei = pagelen - 5;
399
400         // Allocate storage for list headers and partition all labels. Throw away
401         // macros and macro arguments.
402         SYM ** sy = (SYM **)malloc(128 * sizeof(SYM **));
403
404         for(i=0; i<128; i++)
405                 sy[i] = NULL;
406
407         for(i=0; i<NBUCKETS; i++)
408         {
409                 for(p=symbolTable[i]; p!=NULL; p=k)
410                 {
411                         k = p->snext;
412                         j = *p->sname;
413                         r = NULL;
414
415                         // Ignore non-labels
416                         if ((p->stype != LABEL) || (p->sattre & UNDEF_EQUR))
417                                 continue;
418
419                         for(q=sy[j]; q!=NULL; q=q->snext)
420                         {
421                                 if (strcmp(p->sname, q->sname) < 0)
422                                         break;
423
424                                 r = q;
425                         }
426
427                         if (r == NULL)
428                         {
429                                 // Insert at front of list
430                                 p->snext = sy[j];
431                                 sy[j] = p;
432                         }
433                         else
434                         {
435                                 // Insert in middle or append to list
436                                 p->snext = r->snext;
437                                 r->snext = p;
438                         }
439                 }
440         }
441
442         // Link all symbols onto one list again
443         p = NULL;
444
445         for(i=0; i<128; ++i)
446         {
447                 if ((r = sy[i]) != NULL)
448                 {
449                         if (p == NULL)
450                                 q = r;
451                         else
452                                 q->snext = r;
453
454                         while (q->snext != NULL)
455                                 q = q->snext;
456
457                         if (p == NULL)
458                                 p = r;
459                 }
460         }
461
462         eject();
463         strcpy(subttl, "Symbol Table");
464
465         while (p != NULL)
466         {
467                 for(i=0; i<4; i++)
468                 {
469                         colptr[i] = p;
470
471                         for(j=0; j<colhei; j++)
472                         {
473                                 if (p == NULL)
474                                         break;
475                                 else
476                                         p = p->snext;
477                         }
478                 }
479
480                 for(i=0; i<colhei; i++)
481                 {
482                         *ln = EOS;
483
484                         if (colptr[0] == NULL)
485                                 break;
486
487                         for(j=0; j<4; j++)
488                         {
489                                 if ((q = colptr[j]) == NULL)
490                                         break;
491
492                                 colptr[j] = q->snext;
493                                 w = q->sattr;
494                                 ww = q->sattre;
495                                 // Pick a tag:
496                                 // c    common
497                                 // x    external reference
498                                 // g    global (export)
499                                 // space        nothing special
500                                 c1 = SPACE;
501                                 c = SPACE;
502
503                                 if (w & COMMON)
504                                         c = 'c';
505                                 else if ((w & (DEFINED | GLOBAL)) == GLOBAL)
506                                         c = 'x';
507                                 else if (w & GLOBAL)
508                                         c = 'g';
509
510                                 c1 = tdb_text[w & TDB];
511
512                                 if (c == 'x')
513                                         strcpy(ln2, "external");
514                                 else
515                                 {
516                                         sprintf(ln2, "%08X", q->svalue);
517                                         ToUppercase(ln2);
518                                 }
519
520                                 sprintf(ln1, "  %16s %s %c%c%c", q->sname, ln2, (ww & EQUATEDREG) ? 'e' : SPACE, c1, c);
521                                 strcat(ln, ln1);
522                         }
523
524                         ship_ln(ln);
525                 }
526
527                 eject();
528         }
529
530         return 0;
531 }
532