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