]> git.sur5r.net Git - cc65/blob - src/ca65/symtab.c
e592d06d4a2d05ab3a6bcc593c363ce2877c7c55
[cc65] / src / ca65 / symtab.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 symtab.c                                  */
4 /*                                                                           */
5 /*                 Symbol table for the ca65 macroassembler                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* common */
39 #include "addrsize.h"
40 #include "check.h"
41 #include "hashstr.h"
42 #include "mmodel.h"
43 #include "scopedefs.h"
44 #include "symdefs.h"
45 #include "xmalloc.h"
46
47 /* ca65 */
48 #include "global.h"
49 #include "error.h"
50 #include "expr.h"
51 #include "objfile.h"
52 #include "scanner.h"
53 #include "segment.h"
54 #include "sizeof.h"
55 #include "spool.h"
56 #include "studyexpr.h"
57 #include "symtab.h"
58
59
60
61 /*****************************************************************************/
62 /*                                   Data                                    */
63 /*****************************************************************************/
64
65
66
67 /* Combined symbol entry flags used within this module */
68 #define SF_UNDEFMASK    (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
69 #define SF_UNDEFVAL     (SF_REFERENCED)
70 #define SF_DBGINFOMASK  (SF_UNUSED | SF_DEFINED | SF_IMPORT)
71 #define SF_DBGINFOVAL   (SF_DEFINED)
72
73 /* Symbol tables */
74 SymTable*           CurrentScope = 0;   /* Pointer to current symbol table */
75 SymTable*           RootScope    = 0;   /* Root symbol table */
76 static SymTable*    LastScope    = 0;   /* Pointer to last scope in list */
77 static unsigned     ScopeCount   = 0;   /* Number of scopes */
78
79 /* Symbol table variables */
80 static unsigned     ImportCount = 0;    /* Counter for import symbols */
81 static unsigned     ExportCount = 0;    /* Counter for export symbols */
82
83
84
85 /*****************************************************************************/
86 /*                         Internally used functions                         */
87 /*****************************************************************************/
88
89
90
91 static unsigned ScopeTableSize (unsigned Level)
92 /* Get the size of a table for the given lexical level */
93 {
94     switch (Level) {
95         case 0:         return 213;
96         case 1:         return  53;
97         default:        return  29;
98     }
99 }
100
101
102
103 static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
104 /* Allocate a symbol table on the heap and return it */
105 {
106     /* Determine the lexical level and the number of table slots */
107     unsigned Level = Parent? Parent->Level + 1 : 0;
108     unsigned Slots = ScopeTableSize (Level);
109
110     /* Allocate memory */
111     SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*));
112
113     /* Set variables and clear hash table entries */
114     S->Left         = 0;
115     S->Right        = 0;
116     S->Childs       = 0;
117     S->OwnerSym     = 0;
118     S->SegRanges    = AUTO_COLLECTION_INITIALIZER;
119     S->Flags        = ST_NONE;
120     S->AddrSize     = ADDR_SIZE_DEFAULT;
121     S->Type         = SCOPETYPE_UNDEF;
122     S->Level        = Level;
123     S->TableSlots   = Slots;
124     S->TableEntries = 0;
125     S->Parent       = Parent;
126     S->Name         = GetStrBufId (Name);
127     while (Slots--) {
128         S->Table[Slots] = 0;
129     }
130
131     /* Insert the symbol table into the list of all symbol tables and maintain
132      * a unqiue id for each scope. Count the number of scopes.
133      */
134     S->Next = LastScope;
135     if (RootScope == 0) {
136         S->Id = 0;
137         RootScope = S;
138     } else {
139         S->Id = LastScope->Id + 1;
140     }
141     LastScope = S;
142     ++ScopeCount;
143
144     /* Insert the symbol table into the child tree of the parent */
145     if (Parent) {
146         SymTable* T = Parent->Childs;
147         if (T == 0) {
148             /* First entry */
149             Parent->Childs = S;
150         } else {
151             while (1) {
152                 /* Choose next entry */
153                 int Cmp = SB_Compare (Name, GetStrBuf (T->Name));
154                 if (Cmp < 0) {
155                     if (T->Left) {
156                         T = T->Left;
157                     } else {
158                         T->Left = S;
159                         break;
160                     }
161                 } else if (Cmp > 0) {
162                     if (T->Right) {
163                         T = T->Right;
164                     } else {
165                         T->Right = S;
166                         break;
167                     }
168                 } else {
169                     /* Duplicate scope name */
170                     Internal ("Duplicate scope name: `%m%p'", Name);
171                 }
172             }
173         }
174     }
175
176     /* Return the prepared struct */
177     return S;
178 }
179
180
181
182 /*****************************************************************************/
183 /*                                   Code                                    */
184 /*****************************************************************************/
185
186
187
188 void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
189                     unsigned char AddrSize, SymEntry* OwnerSym)
190 /* Enter a new lexical level */
191 {
192     /* Map a default address size to something real */
193     if (AddrSize == ADDR_SIZE_DEFAULT) {
194         /* Use the segment address size */
195         AddrSize = GetCurrentSegAddrSize ();
196     }
197
198     /* If we have a current scope, search for the given name and create a
199      * new one if it doesn't exist. If this is the root scope, just create it.
200      */
201     if (CurrentScope) {
202
203         /* Search for the scope, create a new one */
204         CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW);
205
206         /* Check if the scope has been defined before */
207         if (CurrentScope->Flags & ST_DEFINED) {
208             Error ("Duplicate scope `%m%p'", ScopeName);
209         }
210
211     } else {
212         CurrentScope = RootScope = NewSymTable (0, ScopeName);
213     }
214
215     /* Mark the scope as defined and set type, address size and owner symbol */
216     CurrentScope->Flags    |= ST_DEFINED;
217     CurrentScope->AddrSize = AddrSize;
218     CurrentScope->Type     = Type;
219     CurrentScope->OwnerSym = OwnerSym;
220
221     /* If this is a scope that allows to emit data into segments, add segment
222      * ranges for all currently existing segments. Doing this for just a few
223      * scope types is not really necessary but an optimization, because it
224      * does not allocate memory for useless data (unhandled types here don't
225      * occupy space in any segment).
226      */
227     if (CurrentScope->Type <= SCOPETYPE_HAS_DATA) {
228         AddSegRanges (&CurrentScope->SegRanges);
229     }
230 }
231
232
233
234 void SymLeaveLevel (void)
235 /* Leave the current lexical level */
236 {
237     /* Close the segment ranges. We don't care about the scope type here,
238      * since types without segment ranges will just have an empty list.
239      */
240     CloseSegRanges (&CurrentScope->SegRanges);
241
242     /* If we have segment ranges, the first one is the segment that was
243      * active, when the scope was opened. Set the size of the scope to the
244      * number of data bytes emitted into this segment. If we have an owner
245      * symbol set the size of this symbol, too.
246      */
247     if (CollCount (&CurrentScope->SegRanges) > 0) {
248         const SegRange* R = CollAtUnchecked (&CurrentScope->SegRanges, 0);
249         unsigned long Size = GetSegRangeSize (R);
250         DefSizeOfScope (CurrentScope, Size);
251         if (CurrentScope->OwnerSym) {
252             DefSizeOfSymbol (CurrentScope->OwnerSym, Size);
253         }
254     }
255
256     /* Leave the scope */
257     CurrentScope = CurrentScope->Parent;
258 }
259
260
261
262 SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, int AllocNew)
263 /* Find a scope in the given enclosing scope */
264 {
265     SymTable** T = &Parent->Childs;
266     while (*T) {
267         int Cmp = SB_Compare (Name, GetStrBuf ((*T)->Name));
268         if (Cmp < 0) {
269             T = &(*T)->Left;
270         } else if (Cmp > 0) {
271             T = &(*T)->Right;
272         } else {
273             /* Found the scope */
274             return *T;
275         }
276     }
277
278     /* Create a new scope if requested and we didn't find one */
279     if (*T == 0 && AllocNew) {
280         *T = NewSymTable (Parent, Name);
281     }
282
283     /* Return the scope */
284     return *T;
285 }
286
287
288
289 SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
290 /* Find a scope in the given or any of its parent scopes. The function will
291  * never create a new symbol, since this can only be done in one specific
292  * scope.
293  */
294 {
295     SymTable* Scope;
296     do {
297         /* Search in the current table */
298         Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING);
299         if (Scope == 0) {
300             /* Not found, search in the parent scope, if we have one */
301             Parent = Parent->Parent;
302         }
303     } while (Scope == 0 && Parent != 0);
304
305     return Scope;
306 }
307
308
309
310 SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, int AllocNew)
311 /* Find a cheap local symbol. If AllocNew is given and the entry is not
312  * found, create a new one. Return the entry found, or the new entry created,
313  * or - in case AllocNew is zero - return 0.
314  */
315 {
316     SymEntry* S;
317     int Cmp;
318
319     /* Local symbol, get the table */
320     if (!Parent) {
321         /* No last global, so there's no local table */
322         Error ("No preceeding global symbol");
323         if (AllocNew) {
324             return NewSymEntry (Name, SF_LOCAL);
325         } else {
326             return 0;
327         }
328     }
329
330     /* Search for the symbol if we have a table */
331     Cmp = SymSearchTree (Parent->Locals, Name, &S);
332
333     /* If we found an entry, return it */
334     if (Cmp == 0) {
335         return S;
336     }
337
338     if (AllocNew) {
339
340         /* Otherwise create a new entry, insert and return it */
341         SymEntry* N = NewSymEntry (Name, SF_LOCAL);
342         N->Sym.Entry = Parent;
343         if (S == 0) {
344             Parent->Locals = N;
345         } else if (Cmp < 0) {
346             S->Left = N;
347         } else {
348             S->Right = N;
349         }
350         return N;
351     }
352
353     /* We did not find the entry and AllocNew is false. */
354     return 0;
355 }
356
357
358
359 SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, int AllocNew)
360 /* Find a new symbol table entry in the given table. If AllocNew is given and
361  * the entry is not found, create a new one. Return the entry found, or the
362  * new entry created, or - in case AllocNew is zero - return 0.
363  */
364 {
365     SymEntry* S;
366
367     /* Global symbol: Get the hash value for the name */
368     unsigned Hash = HashBuf (Name) % Scope->TableSlots;
369
370     /* Search for the entry */
371     int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S);
372
373     /* If we found an entry, return it */
374     if (Cmp == 0) {
375         return S;
376     }
377
378     if (AllocNew) {
379
380         /* Otherwise create a new entry, insert and return it */
381         SymEntry* N = NewSymEntry (Name, SF_NONE);
382         N->Sym.Tab = Scope;
383         if (S == 0) {
384             Scope->Table[Hash] = N;
385         } else if (Cmp < 0) {
386             S->Left = N;
387         } else {
388             S->Right = N;
389         }
390         ++Scope->TableEntries;
391         return N;
392
393     }
394
395     /* We did not find the entry and AllocNew is false. */
396     return 0;
397 }
398
399
400
401 SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
402 /* Find a symbol in the given or any of its parent scopes. The function will
403  * never create a new symbol, since this can only be done in one specific
404  * scope.
405  */
406 {
407     SymEntry* Sym;
408     do {
409         /* Search in the current table */
410         Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
411         if (Sym) {
412             /* Found, return it */
413             break;
414         }
415
416         /* Not found, search in the parent scope, if we have one */
417         Scope = Scope->Parent;
418
419     } while (Sym == 0 && Scope != 0);
420
421     /* Return the result */
422     return Sym;
423 }
424
425
426
427 unsigned char GetCurrentSymTabType ()
428 /* Return the type of the current symbol table */
429 {
430     CHECK (CurrentScope != 0);
431     return CurrentScope->Type;
432 }
433
434
435
436 static void SymCheckUndefined (SymEntry* S)
437 /* Handle an undefined symbol */
438 {
439     /* Undefined symbol. It may be...
440      *
441      *   - An undefined symbol in a nested lexical level. In this
442      *     case, search for the symbol in the higher levels and
443      *     make the entry a trampoline entry if we find one.
444      *
445      *   - If the symbol is not found, it is a real undefined symbol.
446      *     If the AutoImport flag is set, make it an import. If the
447      *     AutoImport flag is not set, it's an error.
448      */
449     SymEntry* Sym = 0;
450     SymTable* Tab = GetSymParentScope (S);
451     while (Tab) {
452         Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING);
453         if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
454             /* We've found a symbol in a higher level that is
455              * either defined in the source, or an import.
456              */
457              break;
458         }
459         /* No matching symbol found in this level. Look further */
460         Tab = Tab->Parent;
461     }
462
463     if (Sym) {
464
465         /* We found the symbol in a higher level. Transfer the flags and
466          * address size from the local symbol to that in the higher level
467          * and check for problems.
468          */
469         if (S->Flags & SF_EXPORT) {
470             if (Sym->Flags & SF_IMPORT) {
471                 /* The symbol is already marked as import */
472                 LIError (&S->LineInfos,
473                          "Symbol `%s' is already an import",
474                          GetString (Sym->Name));
475             }
476             if (Sym->Flags & SF_EXPORT) {
477                 /* The symbol is already marked as an export. */
478                 if (Sym->AddrSize > S->ExportSize) {
479                     /* We're exporting a symbol smaller than it actually is */
480                     LIWarning (&S->LineInfos, 1,
481                                "Symbol `%m%p' is %s but exported %s",
482                               GetSymName (Sym),
483                               AddrSizeToStr (Sym->AddrSize),
484                               AddrSizeToStr (S->ExportSize));
485                 }
486             } else {
487                 /* Mark the symbol as an export */
488                 Sym->Flags |= SF_EXPORT;
489                 Sym->ExportSize = S->ExportSize;
490                 if (Sym->ExportSize == ADDR_SIZE_DEFAULT) {
491                     /* Use the actual size of the symbol */
492                     Sym->ExportSize = Sym->AddrSize;
493                 }
494                 if (Sym->AddrSize > Sym->ExportSize) {
495                     /* We're exporting a symbol smaller than it actually is */
496                     LIWarning (&S->LineInfos, 1,
497                                "Symbol `%m%p' is %s but exported %s",
498                                GetSymName (Sym),
499                                AddrSizeToStr (Sym->AddrSize),
500                                AddrSizeToStr (Sym->ExportSize));
501                 }
502             }
503         }
504         Sym->Flags |= (S->Flags & SF_REFERENCED);
505
506         /* Transfer all expression references */
507         SymTransferExprRefs (S, Sym);
508
509         /* Mark the symbol as unused removing all other flags */
510         S->Flags = SF_UNUSED;
511
512     } else {
513         /* The symbol is definitely undefined */
514         if (S->Flags & SF_EXPORT) {
515             /* We will not auto-import an export */
516             LIError (&S->LineInfos,
517                      "Exported symbol `%m%p' was never defined",
518                      GetSymName (S));
519         } else {
520             if (AutoImport) {
521                 /* Mark as import, will be indexed later */
522                 S->Flags |= SF_IMPORT;
523                 /* Use the address size for code */
524                 S->AddrSize = CodeAddrSize;
525             } else {
526                 /* Error */
527                 LIError (&S->LineInfos,
528                          "Symbol `%m%p' is undefined",
529                          GetSymName (S));
530             }
531         }
532     }
533 }
534
535
536
537 void SymCheck (void)
538 /* Run through all symbols and check for anomalies and errors */
539 {
540     SymEntry* S;
541
542     /* Check for open scopes */
543     if (CurrentScope->Parent != 0) {
544         Error ("Local scope was not closed");
545     }
546
547     /* First pass: Walk through all symbols, checking for undefined's and
548      * changing them to trampoline symbols or make them imports.
549      */
550     S = SymList;
551     while (S) {
552         /* If the symbol is marked as global, mark it as export, if it is
553          * already defined, otherwise mark it as import.
554          */
555         if (S->Flags & SF_GLOBAL) {
556             if (S->Flags & SF_DEFINED) {
557                 SymExportFromGlobal (S);
558             } else {
559                 SymImportFromGlobal (S);
560             }
561         }
562
563         /* Handle undefined symbols */
564         if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
565             /* This is an undefined symbol. Handle it. */
566             SymCheckUndefined (S);
567         }
568
569         /* Next symbol */
570         S = S->List;
571     }
572
573     /* Second pass: Walk again through the symbols. Count exports and imports
574      * and set address sizes where this has not happened before. Ignore
575      * undefined's, since we handled them in the last pass, and ignore unused
576      * symbols, since we handled them in the last pass, too.
577      */
578     S = SymList;
579     while (S) {
580         if ((S->Flags & SF_UNUSED) == 0 &&
581             (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
582
583             /* Check for defined symbols that were never referenced */
584             if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
585                 const StrBuf* Name = GetStrBuf (S->Name);
586                 if (SB_At (Name, 0) != '.') {           /* Ignore internals */
587                     LIWarning (&S->LineInfos, 2,
588                                "Symbol `%m%p' is defined but never used",
589                                GetSymName (S));
590                 }
591             }
592
593             /* Assign an index to all imports */
594             if (S->Flags & SF_IMPORT) {
595                 if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
596                     /* Imported symbol is not referenced */
597                     LIWarning (&S->LineInfos, 2,
598                                "Symbol `%m%p' is imported but never used",
599                                GetSymName (S));
600                 } else {
601                     /* Give the import an id, count imports */
602                     S->ImportId = ImportCount++;
603                 }
604             }
605
606             /* Count exports */
607             if (S->Flags & SF_EXPORT) {
608                 ++ExportCount;
609             }
610
611             /* If the symbol is defined but has an unknown address size,
612              * recalculate it.
613              */
614             if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
615                 ExprDesc ED;
616                 ED_Init (&ED);
617                 StudyExpr (S->Expr, &ED);
618                 S->AddrSize = ED.AddrSize;
619                 if (SymIsExport (S)) {
620                     if (S->ExportSize == ADDR_SIZE_DEFAULT) {
621                         /* Use the real export size */
622                         S->ExportSize = S->AddrSize;
623                     } else if (S->AddrSize > S->ExportSize) {
624                         /* We're exporting a symbol smaller than it actually is */
625                         LIWarning (&S->LineInfos, 1,
626                                    "Symbol `%m%p' is %s but exported %s",
627                                    GetSymName (S),
628                                    AddrSizeToStr (S->AddrSize),
629                                    AddrSizeToStr (S->ExportSize));
630                     }
631                 }
632                 ED_Done (&ED);
633             }
634
635             /* If the address size of the symbol was guessed, check the guess
636              * against the actual address size and print a warning if the two
637              * differ.
638              */
639             if (S->AddrSize != ADDR_SIZE_DEFAULT) {
640                 /* Do we have data for this address size? */
641                 if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) {
642                     /* Get the file position where the symbol was used */
643                     const FilePos* P = S->GuessedUse[S->AddrSize - 1];
644                     if (P) {
645                         PWarning (P, 0,
646                                   "Didn't use %s addressing for `%m%p'",
647                                   AddrSizeToStr (S->AddrSize),
648                                   GetSymName (S));
649                     }
650                 }
651             }
652
653         }
654
655         /* Next symbol */
656         S = S->List;
657     }
658 }
659
660
661
662 void SymDump (FILE* F)
663 /* Dump the symbol table */
664 {
665     SymEntry* S = SymList;
666
667     while (S) {
668         /* Ignore unused symbols */
669         if ((S->Flags & SF_UNUSED) != 0) {
670             fprintf (F,
671                      "%m%-24p %s %s %s %s %s\n",
672                      GetSymName (S),
673                      (S->Flags & SF_DEFINED)? "DEF" : "---",
674                      (S->Flags & SF_REFERENCED)? "REF" : "---",
675                      (S->Flags & SF_IMPORT)? "IMP" : "---",
676                      (S->Flags & SF_EXPORT)? "EXP" : "---",
677                      AddrSizeToStr (S->AddrSize));
678         }
679         /* Next symbol */
680         S = S->List;
681     }
682 }
683
684
685
686 void WriteImports (void)
687 /* Write the imports list to the object file */
688 {
689     SymEntry* S;
690
691     /* Tell the object file module that we're about to start the imports */
692     ObjStartImports ();
693
694     /* Write the import count to the list */
695     ObjWriteVar (ImportCount);
696
697     /* Walk throught list and write all valid imports to the file. An import
698      * is considered valid, if it is either referenced, or the forced bit is
699      * set. Otherwise, the import is ignored (no need to link in something
700      * that isn't used).
701      */
702     S = SymList;
703     while (S) {
704         if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
705             (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
706
707             ObjWrite8 (S->AddrSize);
708             ObjWriteVar (S->Name);
709             WriteLineInfo (&S->LineInfos);
710         }
711         S = S->List;
712     }
713
714     /* Done writing imports */
715     ObjEndImports ();
716 }
717
718
719
720 void WriteExports (void)
721 /* Write the exports list to the object file */
722 {
723     SymEntry* S;
724     unsigned Type;
725
726     /* Tell the object file module that we're about to start the exports */
727     ObjStartExports ();
728
729     /* Write the export count to the list */
730     ObjWriteVar (ExportCount);
731
732     /* Walk throught list and write all exports to the file */
733     S = SymList;
734     while (S) {
735         if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
736
737             /* Get the expression bits and the value */
738             long ConstVal;
739             unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
740
741             /* Check if this symbol has a size. If so, remember it in the
742              * flags.
743              */
744             long Size;
745             SymEntry* SizeSym = FindSizeOfSymbol (S);
746             if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
747                 ExprMask |= SYM_SIZE;
748             }
749
750             /* Count the number of ConDes types */
751             for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
752                 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
753                     SYM_INC_CONDES_COUNT (ExprMask);
754                 }
755             }
756
757             /* Write the type and the export size */
758             ObjWriteVar (ExprMask);
759             ObjWrite8 (S->ExportSize);
760
761             /* Write any ConDes declarations */
762             if (SYM_GET_CONDES_COUNT (ExprMask) > 0) {
763                 for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
764                     unsigned char Prio = S->ConDesPrio[Type];
765                     if (Prio != CD_PRIO_NONE) {
766                         ObjWrite8 (CD_BUILD (Type, Prio));
767                     }
768                 }
769             }
770
771             /* Write the name */
772             ObjWriteVar (S->Name);
773
774             /* Write the value */
775             if (SYM_IS_CONST (ExprMask)) {
776                 /* Constant value */
777                 ObjWrite32 (ConstVal);
778             } else {
779                 /* Expression involved */
780                 WriteExpr (S->Expr);
781             }
782
783             /* If the symbol has a size, write it to the file */
784             if (SYM_HAS_SIZE (ExprMask)) {
785                 ObjWriteVar (Size);
786             }
787
788             /* Write the line infos */
789             WriteLineInfo (&S->LineInfos);
790         }
791         S = S->List;
792     }
793
794     /* Done writing exports */
795     ObjEndExports ();
796 }
797
798
799
800 void WriteDbgSyms (void)
801 /* Write a list of all symbols to the object file */
802 {
803     unsigned Count;
804     SymEntry* S;
805
806     /* Tell the object file module that we're about to start the debug info */
807     ObjStartDbgSyms ();
808
809     /* Check if debug info is requested */
810     if (DbgSyms) {
811
812         /* Walk through the list, give each symbol an id and count them */
813         Count = 0;
814         S = SymList;
815         while (S) {
816             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL &&
817                 !IsSizeOfSymbol (S)) {
818                 S->DebugSymId = Count++;
819             }
820             S = S->List;
821         }
822
823         /* Write the symbol count to the list */
824         ObjWriteVar (Count);
825
826         /* Walk through list and write all symbols to the file. Ignore size
827          * symbols.
828          */
829         S = SymList;
830         while (S) {
831             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL &&
832                 !IsSizeOfSymbol (S)) {
833
834                 /* Get the expression bits and the value */
835                 long ConstVal;
836                 unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
837
838                 /* Check if this symbol has a size. If so, remember it in the
839                  * flags.
840                  */
841                 long Size;
842                 SymEntry* SizeSym = FindSizeOfSymbol (S);
843                 if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
844                     ExprMask |= SYM_SIZE;
845                 }
846
847                 /* Write the type */
848                 ObjWriteVar (ExprMask);
849
850                 /* Write the address size */
851                 ObjWrite8 (S->AddrSize);
852
853                 /* Write the id of the parent. For normal symbols, this is a
854                  * scope (symbol table), for cheap locals, it's a symbol.
855                  */
856                 if (SYM_IS_STD (ExprMask)) {
857                     ObjWriteVar (S->Sym.Tab->Id);
858                 } else {
859                     ObjWriteVar (S->Sym.Entry->DebugSymId);
860                 }
861
862                 /* Write the name */
863                 ObjWriteVar (S->Name);
864
865                 /* Write the value */
866                 if (SYM_IS_CONST (ExprMask)) {
867                     /* Constant value */
868                     ObjWrite32 (ConstVal);
869                 } else {
870                     /* Expression involved */
871                     WriteExpr (S->Expr);
872                 }
873
874                 /* If the symbol has a size, write it to the file */
875                 if (SYM_HAS_SIZE (ExprMask)) {
876                     ObjWriteVar (Size);
877                 }
878
879                 /* Write the line infos */
880                 WriteLineInfo (&S->LineInfos);
881             }
882             S = S->List;
883         }
884
885     } else {
886
887         /* No debug symbols */
888         ObjWriteVar (0);
889
890     }
891
892     /* Done writing debug symbols */
893     ObjEndDbgSyms ();
894 }
895
896
897
898 void WriteScopes (void)
899 /* Write the scope table to the object file */
900 {
901     /* Tell the object file module that we're about to start the scopes */
902     ObjStartScopes ();
903
904     /* We will write scopes only if debug symbols are requested */
905     if (DbgSyms) {
906
907         /* Get head of list */
908         const SymTable* S = LastScope;
909
910         /* Write the scope count to the file */
911         ObjWriteVar (ScopeCount);
912
913         /* Walk through all scopes and write them to the file */
914         while (S) {
915
916             /* Type must be defined */
917             CHECK (S->Type != SCOPETYPE_UNDEF);
918
919             /* Id of scope */
920             ObjWriteVar (S->Id);
921
922             /* Id of parent scope */
923             if (S->Parent) {
924                 ObjWriteVar (S->Parent->Id);
925             } else {
926                 ObjWriteVar (0);
927             }
928
929             /* Lexical level */
930             ObjWriteVar (S->Level);
931
932             /* Scope flags (currently always zero) */
933             ObjWriteVar (0);
934
935             /* Type of scope */
936             ObjWriteVar (S->Type);
937
938             /* Name of the scope */
939             ObjWriteVar (S->Name);
940
941             /* Segment ranges for this scope */
942             WriteSegRanges (&S->SegRanges);
943
944             /* Next scope */
945             S = S->Next;
946         }
947
948     } else {
949
950         /* No debug info requested */
951         ObjWriteVar (0);
952
953     }
954
955     /* Done writing the scopes */
956     ObjEndScopes ();
957 }
958
959
960