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