]> git.sur5r.net Git - cc65/blob - src/ca65/symtab.c
More lineinfo usage.
[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 "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                 LIError (&S->LineInfos,
462                          "Symbol `%s' is already an import",
463                          GetString (Sym->Name));
464             }
465             if (Sym->Flags & SF_EXPORT) {
466                 /* The symbol is already marked as an export. */
467                 if (Sym->AddrSize > S->ExportSize) {
468                     /* We're exporting a symbol smaller than it actually is */
469                     LIWarning (&S->LineInfos, 1,
470                                "Symbol `%m%p' is %s but exported %s",
471                               GetSymName (Sym),
472                               AddrSizeToStr (Sym->AddrSize),
473                               AddrSizeToStr (S->ExportSize));
474                 }
475             } else {
476                 /* Mark the symbol as an export */
477                 Sym->Flags |= SF_EXPORT;
478                 Sym->ExportSize = S->ExportSize;
479                 if (Sym->ExportSize == ADDR_SIZE_DEFAULT) {
480                     /* Use the actual size of the symbol */
481                     Sym->ExportSize = Sym->AddrSize;
482                 }
483                 if (Sym->AddrSize > Sym->ExportSize) {
484                     /* We're exporting a symbol smaller than it actually is */
485                     LIWarning (&S->LineInfos, 1,
486                                "Symbol `%m%p' is %s but exported %s",
487                                GetSymName (Sym),
488                                AddrSizeToStr (Sym->AddrSize),
489                                AddrSizeToStr (Sym->ExportSize));
490                 }
491             }
492         }
493         Sym->Flags |= (S->Flags & SF_REFERENCED);
494
495         /* Transfer all expression references */
496         SymTransferExprRefs (S, Sym);
497
498         /* Mark the symbol as unused removing all other flags */
499         S->Flags = SF_UNUSED;
500
501     } else {
502         /* The symbol is definitely undefined */
503         if (S->Flags & SF_EXPORT) {
504             /* We will not auto-import an export */
505             LIError (&S->LineInfos, 
506                      "Exported symbol `%m%p' was never defined",
507                      GetSymName (S));
508         } else {
509             if (AutoImport) {
510                 /* Mark as import, will be indexed later */
511                 S->Flags |= SF_IMPORT;
512                 /* Use the address size for code */
513                 S->AddrSize = CodeAddrSize;
514             } else {
515                 /* Error */
516                 LIError (&S->LineInfos, 
517                          "Symbol `%m%p' is undefined", 
518                          GetSymName (S));
519             }
520         }
521     }
522 }
523
524
525
526 void SymCheck (void)
527 /* Run through all symbols and check for anomalies and errors */
528 {
529     SymEntry* S;
530
531     /* Check for open scopes */
532     if (CurrentScope->Parent != 0) {
533         Error ("Local scope was not closed");
534     }
535
536     /* First pass: Walk through all symbols, checking for undefined's and
537      * changing them to trampoline symbols or make them imports.
538      */
539     S = SymList;
540     while (S) {
541         /* If the symbol is marked as global, mark it as export, if it is
542          * already defined, otherwise mark it as import.
543          */
544         if (S->Flags & SF_GLOBAL) {
545             if (S->Flags & SF_DEFINED) {
546                 SymExportFromGlobal (S);
547             } else {
548                 SymImportFromGlobal (S);
549             }
550         }
551
552         /* Handle undefined symbols */
553         if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
554             /* This is an undefined symbol. Handle it. */
555             SymCheckUndefined (S);
556         }
557
558         /* Next symbol */
559         S = S->List;
560     }
561
562     /* Second pass: Walk again through the symbols. Count exports and imports
563      * and set address sizes where this has not happened before. Ignore
564      * undefined's, since we handled them in the last pass, and ignore unused
565      * symbols, since we handled them in the last pass, too.
566      */
567     S = SymList;
568     while (S) {
569         if ((S->Flags & SF_UNUSED) == 0 &&
570             (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
571
572             /* Check for defined symbols that were never referenced */
573             if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
574                 const StrBuf* Name = GetStrBuf (S->Name);
575                 if (SB_At (Name, 0) != '.') {           /* Ignore internals */
576                     LIWarning (&S->LineInfos, 2,
577                                "Symbol `%m%p' is defined but never used",
578                                GetSymName (S));
579                 }
580             }
581
582             /* Assign an index to all imports */
583             if (S->Flags & SF_IMPORT) {
584                 if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
585                     /* Imported symbol is not referenced */
586                     LIWarning (&S->LineInfos, 2,
587                                "Symbol `%m%p' is imported but never used",
588                                GetSymName (S));
589                 } else {
590                     /* Give the import an id, count imports */
591                     S->ImportId = ImportCount++;
592                 }
593             }
594
595             /* Count exports */
596             if (S->Flags & SF_EXPORT) {
597                 ++ExportCount;
598             }
599
600             /* If the symbol is defined but has an unknown address size,
601              * recalculate it.
602              */
603             if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
604                 ExprDesc ED;
605                 ED_Init (&ED);
606                 StudyExpr (S->Expr, &ED);
607                 S->AddrSize = ED.AddrSize;
608                 if (SymIsExport (S)) {
609                     if (S->ExportSize == ADDR_SIZE_DEFAULT) {
610                         /* Use the real export size */
611                         S->ExportSize = S->AddrSize;
612                     } else if (S->AddrSize > S->ExportSize) {
613                         /* We're exporting a symbol smaller than it actually is */
614                         LIWarning (&S->LineInfos, 1,
615                                    "Symbol `%m%p' is %s but exported %s",
616                                    GetSymName (S),
617                                    AddrSizeToStr (S->AddrSize),
618                                    AddrSizeToStr (S->ExportSize));
619                     }
620                 }
621                 ED_Done (&ED);
622             }
623
624             /* If the address size of the symbol was guessed, check the guess
625              * against the actual address size and print a warning if the two
626              * differ.
627              */
628             if (S->AddrSize != ADDR_SIZE_DEFAULT) {
629                 /* Do we have data for this address size? */
630                 if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) {
631                     /* Get the file position where the symbol was used */
632                     const FilePos* P = S->GuessedUse[S->AddrSize - 1];
633                     if (P) {
634                         PWarning (P, 0,
635                                   "Didn't use %s addressing for `%m%p'",
636                                   AddrSizeToStr (S->AddrSize),
637                                   GetSymName (S));
638                     }
639                 }
640             }
641
642         }
643
644         /* Next symbol */
645         S = S->List;
646     }
647 }
648
649
650
651 void SymDump (FILE* F)
652 /* Dump the symbol table */
653 {
654     SymEntry* S = SymList;
655
656     while (S) {
657         /* Ignore unused symbols */
658         if ((S->Flags & SF_UNUSED) != 0) {
659             fprintf (F,
660                      "%m%-24p %s %s %s %s %s\n",
661                      GetSymName (S),
662                      (S->Flags & SF_DEFINED)? "DEF" : "---",
663                      (S->Flags & SF_REFERENCED)? "REF" : "---",
664                      (S->Flags & SF_IMPORT)? "IMP" : "---",
665                      (S->Flags & SF_EXPORT)? "EXP" : "---",
666                      AddrSizeToStr (S->AddrSize));
667         }
668         /* Next symbol */
669         S = S->List;
670     }
671 }
672
673
674
675 void WriteImports (void)
676 /* Write the imports list to the object file */
677 {
678     SymEntry* S;
679
680     /* Tell the object file module that we're about to start the imports */
681     ObjStartImports ();
682
683     /* Write the import count to the list */
684     ObjWriteVar (ImportCount);
685
686     /* Walk throught list and write all valid imports to the file. An import
687      * is considered valid, if it is either referenced, or the forced bit is
688      * set. Otherwise, the import is ignored (no need to link in something
689      * that isn't used).
690      */
691     S = SymList;
692     while (S) {
693         if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
694             (S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
695
696             ObjWrite8 (S->AddrSize);
697             ObjWriteVar (S->Name);
698             WriteLineInfo (&S->LineInfos);
699         }
700         S = S->List;
701     }
702
703     /* Done writing imports */
704     ObjEndImports ();
705 }
706
707
708
709 void WriteExports (void)
710 /* Write the exports list to the object file */
711 {
712     SymEntry* S;
713     unsigned Type;
714
715     /* Tell the object file module that we're about to start the exports */
716     ObjStartExports ();
717
718     /* Write the export count to the list */
719     ObjWriteVar (ExportCount);
720
721     /* Walk throught list and write all exports to the file */
722     S = SymList;
723     while (S) {
724         if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
725
726             /* Get the expression bits and the value */
727             long ConstVal;
728             unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
729
730             /* Count the number of ConDes types */
731             for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
732                 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
733                     SYM_INC_CONDES_COUNT (ExprMask);
734                 }
735             }
736
737             /* Write the type and the export size */
738             ObjWriteVar (ExprMask);
739             ObjWrite8 (S->ExportSize);
740
741             /* Write any ConDes declarations */
742             if (SYM_GET_CONDES_COUNT (ExprMask) > 0) {
743                 for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
744                     unsigned char Prio = S->ConDesPrio[Type];
745                     if (Prio != CD_PRIO_NONE) {
746                         ObjWrite8 (CD_BUILD (Type, Prio));
747                     }
748                 }
749             }
750
751             /* Write the name */
752             ObjWriteVar (S->Name);
753
754             /* Write the value */
755             if (SYM_IS_CONST (ExprMask)) {
756                 /* Constant value */
757                 ObjWrite32 (ConstVal);
758             } else {
759                 /* Expression involved */
760                 WriteExpr (S->Expr);
761             }
762
763             /* Write the line infos */
764             WriteLineInfo (&S->LineInfos);
765         }
766         S = S->List;
767     }
768
769     /* Done writing exports */
770     ObjEndExports ();
771 }
772
773
774
775 void WriteDbgSyms (void)
776 /* Write a list of all symbols to the object file */
777 {
778     unsigned Count;
779     SymEntry* S;
780
781     /* Tell the object file module that we're about to start the debug info */
782     ObjStartDbgSyms ();
783
784     /* Check if debug info is requested */
785     if (DbgSyms) {
786
787         /* Walk through the list, give each symbol an id and count them */
788         Count = 0;
789         S = SymList;
790         while (S) {
791             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
792                 S->DebugSymId = Count++;
793             }
794             S = S->List;
795         }
796
797         /* Write the symbol count to the list */
798         ObjWriteVar (Count);
799
800         /* Walk through list and write all symbols to the file */
801         S = SymList;
802         while (S) {
803             if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
804
805                 /* Get the expression bits and the value */
806                 long ConstVal;
807                 unsigned ExprMask = GetSymInfoFlags (S, &ConstVal);
808
809                 /* Write the type */
810                 ObjWriteVar (ExprMask);
811
812                 /* Write the address size */
813                 ObjWrite8 (S->AddrSize);
814
815                 /* Write the name */
816                 ObjWriteVar (S->Name);
817
818                 /* Write the value */
819                 if (SYM_IS_CONST (ExprMask)) {
820                     /* Constant value */
821                     ObjWrite32 (ConstVal);
822                 } else {
823                     /* Expression involved */
824                     WriteExpr (S->Expr);
825                 }
826
827                 /* Write the line infos */
828                 WriteLineInfo (&S->LineInfos);
829             }
830             S = S->List;
831         }
832
833     } else {
834
835         /* No debug symbols */
836         ObjWriteVar (0);
837
838     }
839
840     /* Done writing debug symbols */
841     ObjEndDbgSyms ();
842 }
843
844
845
846 void WriteScopes (void)
847 /* Write the scope table to the object file */
848 {
849     /* Tell the object file module that we're about to start the scopes */
850     ObjStartScopes ();
851
852     /* No debug info requested */
853     ObjWriteVar (0);
854
855     /* Done writing the scopes */
856     ObjEndScopes ();
857 }
858
859
860