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