1/*****************************************************************************/
2/* */
3/* symentry.c */
4/* */
5/* Symbol table entry 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 "symdefs.h"
41#include "xmalloc.h"
42
43/* ca65 */
44#include "error.h"
45#include "expr.h"
46#include "global.h"
47#include "scanner.h"
48#include "segment.h"
49#include "spool.h"
50#include "studyexpr.h" /* ### */
51#include "symentry.h"
52#include "symtab.h"
53
54
55
56/*****************************************************************************/
57/* Data */
58/*****************************************************************************/
59
60
61
62/* List of all symbol table entries */
63SymEntry* SymList = 0;
64
65/* Pointer to last defined symbol */
66SymEntry* SymLast = 0;
67
68
69
70/*****************************************************************************/
71/* Code */
72/*****************************************************************************/
73
74
75
76SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
77/* Allocate a symbol table entry, initialize and return it */
78{
79 unsigned I;
80
81 /* Allocate memory */
82 SymEntry* S = xmalloc (sizeof (SymEntry));
83
84 /* Initialize the entry */
85 S->Left = 0;
86 S->Right = 0;
87 S->Locals = 0;
88 S->Sym.Tab = 0;
89 S->DefLines = EmptyCollection;
90 S->RefLines = EmptyCollection;
91 for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) {
92 S->GuessedUse[I] = 0;
93 }
94 S->HLLSym = 0;
95 S->Flags = Flags;
96 S->DebugSymId = ~0U;
97 S->ImportId = ~0U;
98 S->ExportId = ~0U;
99 S->Expr = 0;
100 S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
101 S->ExportSize = ADDR_SIZE_DEFAULT;
102 S->AddrSize = ADDR_SIZE_DEFAULT;
103 memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
104 S->Name = GetStrBufId (Name);
105
106 /* Insert it into the list of all entries */
107 S->List = SymList;
108 SymList = S;
109
110 /* Return the initialized entry */
111 return S;
112}
113
114
115
116int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
117/* Search in the given tree for a name. If we find the symbol, the function
118** will return 0 and put the entry pointer into E. If we did not find the
119** symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
120** E will be set to the last entry, and the result of the function is <0 if
121** the entry should be inserted on the left side, and >0 if it should get
122** inserted on the right side.
123*/
124{
125 /* Is there a tree? */
126 if (T == 0) {
127 *E = 0;
128 return 1;
129 }
130
131 /* We have a table, search it */
132 while (1) {
133
134 /* Get the symbol name */
135 const StrBuf* SymName = GetStrBuf (T->Name);
136
137 /* Choose next entry */
138 int Cmp = SB_Compare (Name, SymName);
139 if (Cmp < 0 && T->Left) {
140 T = T->Left;
141 } else if (Cmp > 0 && T->Right) {
142 T = T->Right;
143 } else {
144 /* Found or end of search, return the result */
145 *E = T;
146 return Cmp;
147 }
148 }
149}
150
151
152
153void SymTransferExprRefs (SymEntry* From, SymEntry* To)
154/* Transfer all expression references from one symbol to another. */
155{
156 unsigned I;
157
158 for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
159
160 /* Get the expression node */
161 ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
162
163 /* Safety */
164 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
165
166 /* Replace the symbol reference */
167 E->V.Sym = To;
168
169 /* Add the expression reference */
170 SymAddExprRef (To, E);
171 }
172
173 /* Remove all symbol references from the old symbol */
174 CollDeleteAll (&From->ExprRefs);
175}
176
177
178
179static void SymReplaceExprRefs (SymEntry* S)
180/* Replace the references to this symbol by a copy of the symbol expression */
181{
182 unsigned I;
183 long Val;
184
185 /* Check if the expression is const and get its value */
186 int IsConst = IsConstExpr (S->Expr, &Val);
187 CHECK (IsConst);
188
189 /* Loop over all references */
190 for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
191
192 /* Get the expression node */
193 ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
194
195 /* Safety */
196 CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
197
198 /* We cannot touch the root node, since there are pointers to it.
199 ** Replace it by a literal node.
200 */
201 E->Op = EXPR_LITERAL;
202 E->V.IVal = Val;
203 }
204
205 /* Remove all symbol references from the symbol */
206 CollDeleteAll (&S->ExprRefs);
207}
208
209
210
211void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
212/* Define a new symbol */
213{
214 if (S->Flags & SF_IMPORT) {
215 /* Defined symbol is marked as imported external symbol */
216 Error ("Symbol '%m%p' is already an import", GetSymName (S));
217 return;
218 }
219 if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
220 /* Variable symbols cannot be exports or globals */
221 Error ("Var symbol '%m%p' cannot be an export or global symbol", GetSymName (S));
222 return;
223 }
224 if (S->Flags & SF_DEFINED) {
225 /* Multiple definition. In case of a variable, this is legal. */
226 if ((S->Flags & SF_VAR) == 0) {
227 Error ("Symbol '%m%p' is already defined", GetSymName (S));
228 S->Flags |= SF_MULTDEF;
229 return;
230 } else {
231 /* Redefinition must also be a variable symbol */
232 if ((Flags & SF_VAR) == 0) {
233 Error ("Symbol '%m%p' is already different kind", GetSymName (S));
234 return;
235 }
236 /* Delete the current symbol expression, since it will get
237 ** replaced
238 */
239 FreeExpr (S->Expr);
240 S->Expr = 0;
241 }
242 }
243
244 /* Map a default address size to a real value */
245 if (AddrSize == ADDR_SIZE_DEFAULT) {
246 /* ### Must go! Delay address size calculation until end of assembly! */
247 ExprDesc ED;
248 ED_Init (&ED);
249 StudyExpr (Expr, &ED);
250 AddrSize = ED.AddrSize;
251 ED_Done (&ED);
252 }
253
254 /* Set the symbol value */
255 S->Expr = Expr;
256
257 /* In case of a variable symbol, walk over all expressions containing
258 ** this symbol and replace the (sub-)expression by the literal value of
259 ** the tree. Be sure to replace the expression node in place, since there
260 ** may be pointers to it.
261 */
262 if (Flags & SF_VAR) {
263 SymReplaceExprRefs (S);
264 }
265
266 /* If the symbol is marked as global, export it. Address size is checked
267 ** below.
268 */
269 if (S->Flags & SF_GLOBAL) {
270 S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
271 ReleaseFullLineInfo (&S->DefLines);
272 }
273
274 /* Mark the symbol as defined and use the given address size */
275 S->Flags |= (SF_DEFINED | Flags);
276 S->AddrSize = AddrSize;
277
278 /* Remember the line info of the symbol definition */
279 GetFullLineInfo (&S->DefLines);
280
281 /* If the symbol is exported, check the address sizes */
282 if (S->Flags & SF_EXPORT) {
283 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
284 /* Use the real size of the symbol */
285 S->ExportSize = S->AddrSize;
286 } else if (S->AddrSize > S->ExportSize) {
287 /* We're exporting a symbol smaller than it actually is */
288 Warning (1, "Symbol '%m%p' is %s but exported %s",
289 GetSymName (S), AddrSizeToStr (S->AddrSize),
290 AddrSizeToStr (S->ExportSize));
291 }
292 }
293
294 /* If this is not a local symbol, remember it as the last global one */
295 if ((S->Flags & SF_LOCAL) == 0) {
296 SymLast = S;
297 }
298}
299
300
301
302void SymRef (SymEntry* S)
303/* Mark the given symbol as referenced */
304{
305 /* Mark the symbol as referenced */
306 S->Flags |= SF_REFERENCED;
307
308 /* Remember the current location */
309 CollAppend (&S->RefLines, GetAsmLineInfo ());
310}
311
312
313
314void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
315/* Mark the given symbol as an imported symbol */
316{
317 if (S->Flags & SF_DEFINED) {
318 Error ("Symbol '%m%p' is already defined", GetSymName (S));
319 S->Flags |= SF_MULTDEF;
320 return;
321 }
322 if (S->Flags & SF_EXPORT) {
323 /* The symbol is already marked as exported symbol */
324 Error ("Cannot import exported symbol '%m%p'", GetSymName (S));
325 return;
326 }
327
328 /* If no address size is given, use the address size of the enclosing
329 ** segment.
330 */
331 if (AddrSize == ADDR_SIZE_DEFAULT) {
332 AddrSize = GetCurrentSegAddrSize ();
333 }
334
335 /* If the symbol is marked as import or global, check the address size,
336 ** then do silently remove the global flag.
337 */
338 if (S->Flags & SF_IMPORT) {
339 if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
340 Error ("Redeclaration mismatch for symbol '%m%p'", GetSymName (S));
341 }
342 if (AddrSize != S->AddrSize) {
343 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
344 }
345 }
346 if (S->Flags & SF_GLOBAL) {
347 S->Flags &= ~SF_GLOBAL;
348 if (AddrSize != S->AddrSize) {
349 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
350 }
351 }
352
353 /* Set the symbol data */
354 S->Flags |= (SF_IMPORT | Flags);
355 S->AddrSize = AddrSize;
356
357 /* Mark the position of the import as the position of the definition.
358 ** Please note: In case of multiple .global or .import statements, the line
359 ** infos add up.
360 */
361 GetFullLineInfo (&S->DefLines);
362}
363
364
365
366void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
367/* Mark the given symbol as an exported symbol */
368{
369 /* Check if it's ok to export the symbol */
370 if (S->Flags & SF_IMPORT) {
371 /* The symbol is already marked as imported external symbol */
372 Error ("Symbol '%m%p' is already an import", GetSymName (S));
373 return;
374 }
375 if (S->Flags & SF_VAR) {
376 /* Variable symbols cannot be exported */
377 Error ("Var symbol '%m%p' cannot be exported", GetSymName (S));
378 return;
379 }
380
381 /* If the symbol was marked as global before, remove the global flag and
382 ** proceed, but check the address size.
383 */
384 if (S->Flags & SF_GLOBAL) {
385 if (AddrSize != S->ExportSize) {
386 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
387 }
388 S->Flags &= ~SF_GLOBAL;
389
390 /* .GLOBAL remembers line infos in case an .IMPORT follows. We have
391 ** to remove these here.
392 */
393 ReleaseFullLineInfo (&S->DefLines);
394 }
395
396 /* If the symbol was already marked as an export, but wasn't defined
397 ** before, the address sizes in both definitions must match.
398 */
399 if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
400 if (S->ExportSize != AddrSize) {
401 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
402 }
403 }
404 S->ExportSize = AddrSize;
405
406 /* If the symbol is already defined, check symbol size against the
407 ** exported size.
408 */
409 if (S->Flags & SF_DEFINED) {
410 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
411 /* No export size given, use the real size of the symbol */
412 S->ExportSize = S->AddrSize;
413 } else if (S->AddrSize > S->ExportSize) {
414 /* We're exporting a symbol smaller than it actually is */
415 Warning (1, "Symbol '%m%p' is %s but exported %s",
416 GetSymName (S), AddrSizeToStr (S->AddrSize),
417 AddrSizeToStr (S->ExportSize));
418 }
419 }
420
421 /* Set the symbol data */
422 S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
423
424 /* Remember line info for this reference */
425 CollAppend (&S->RefLines, GetAsmLineInfo ());
426}
427
428
429
430void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
431/* Mark the given symbol as a global symbol, that is, as a symbol that is
432** either imported or exported.
433*/
434{
435 if (S->Flags & SF_VAR) {
436 /* Variable symbols cannot be exported or imported */
437 Error ("Var symbol '%m%p' cannot be made global", GetSymName (S));
438 return;
439 }
440
441 /* If the symbol is already marked as import, the address size must match.
442 ** Apart from that, ignore the global declaration.
443 */
444 if (S->Flags & SF_IMPORT) {
445 if (AddrSize == ADDR_SIZE_DEFAULT) {
446 /* Use the size of the current segment */
447 AddrSize = GetCurrentSegAddrSize ();
448 }
449 if (AddrSize != S->AddrSize) {
450 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
451 }
452 return;
453 }
454
455 /* If the symbol is already an export: If it is not defined, the address
456 ** sizes must match.
457 */
458 if (S->Flags & SF_EXPORT) {
459 if ((S->Flags & SF_DEFINED) == 0) {
460 /* Symbol is undefined */
461 if (AddrSize != S->ExportSize) {
462 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
463 }
464 } else if (AddrSize != ADDR_SIZE_DEFAULT) {
465 /* Symbol is defined and address size given */
466 if (AddrSize != S->ExportSize) {
467 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
468 }
469 }
470 return;
471 }
472
473 /* If the symbol is already marked as global, the address size must match.
474 ** Use the ExportSize here, since it contains the actual address size
475 ** passed to this function.
476 */
477 if (S->Flags & SF_GLOBAL) {
478 if (AddrSize != S->ExportSize) {
479 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
480 }
481 return;
482 }
483
484 /* If we come here, the symbol was neither declared as export, import or
485 ** global before. Check if it is already defined, in which case it will
486 ** become an export. If it is not defined, mark it as global and remember
487 ** the given address sizes.
488 */
489 if (S->Flags & SF_DEFINED) {
490 /* The symbol is defined, export it */
491 S->ExportSize = AddrSize;
492 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
493 /* No export size given, use the real size of the symbol */
494 S->ExportSize = S->AddrSize;
495 } else if (S->AddrSize > S->ExportSize) {
496 /* We're exporting a symbol smaller than it actually is */
497 Warning (1, "Symbol '%m%p' is %s but exported %s",
498 GetSymName (S), AddrSizeToStr (S->AddrSize),
499 AddrSizeToStr (S->ExportSize));
500 }
501 S->Flags |= (SF_EXPORT | Flags);
502 } else {
503 /* Since we don't know if the symbol will get exported or imported,
504 ** remember two different address sizes: One for an import in AddrSize,
505 ** and the other one for an export in ExportSize.
506 */
507 S->AddrSize = AddrSize;
508 if (S->AddrSize == ADDR_SIZE_DEFAULT) {
509 /* Use the size of the current segment */
510 S->AddrSize = GetCurrentSegAddrSize ();
511 }
512 S->ExportSize = AddrSize;
513 S->Flags |= (SF_GLOBAL | Flags);
514
515 /* Remember the current location as location of definition in case
516 ** an .IMPORT follows later.
517 */
518 GetFullLineInfo (&S->DefLines);
519 }
520}
521
522
523
524void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
525/* Mark the given symbol as a module constructor/destructor. This will also
526** mark the symbol as an export. Initializers may never be zero page symbols.
527*/
528{
529 /* Check the parameters */
530#if (CD_TYPE_MIN != 0)
531 CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
532#else
533 CHECK (Type <= CD_TYPE_MAX);
534#endif
535 CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
536
537 /* Check for errors */
538 if (S->Flags & SF_IMPORT) {
539 /* The symbol is already marked as imported external symbol */
540 Error ("Symbol '%m%p' is already an import", GetSymName (S));
541 return;
542 }
543 if (S->Flags & SF_VAR) {
544 /* Variable symbols cannot be exported or imported */
545 Error ("Var symbol '%m%p' cannot be exported", GetSymName (S));
546 return;
547 }
548
549 /* If the symbol was already marked as an export or global, check if
550 ** this was done specifiying the same address size. In case of a global
551 ** declaration, silently remove the global flag.
552 */
553 if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
554 if (S->ExportSize != AddrSize) {
555 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
556 }
557 S->Flags &= ~SF_GLOBAL;
558 }
559 S->ExportSize = AddrSize;
560
561 /* If the symbol is already defined, check symbol size against the
562 ** exported size.
563 */
564 if (S->Flags & SF_DEFINED) {
565 if (S->ExportSize == ADDR_SIZE_DEFAULT) {
566 /* Use the real size of the symbol */
567 S->ExportSize = S->AddrSize;
568 } else if (S->AddrSize != S->ExportSize) {
569 Error ("Address size mismatch for symbol '%m%p'", GetSymName (S));
570 }
571 }
572
573 /* If the symbol already was declared as a condes of this type,
574 ** check if the new priority value is the same as the old one.
575 */
576 if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
577 if (S->ConDesPrio[Type] != Prio) {
578 Error ("Redeclaration mismatch for symbol '%m%p'", GetSymName (S));
579 }
580 }
581 S->ConDesPrio[Type] = Prio;
582
583 /* Set the symbol data */
584 S->Flags |= (SF_EXPORT | SF_REFERENCED);
585
586 /* Remember the line info for this reference */
587 CollAppend (&S->RefLines, GetAsmLineInfo ());
588}
589
590
591
592void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
593/* Mark the address size of the given symbol as guessed. The address size
594** passed as argument is the one NOT used, because the actual address size
595** wasn't known. Example: Zero page addressing was not used because symbol
596** is undefined, and absolute addressing was available.
597*/
598{
599 /* We must have a valid address size passed */
600 PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
601
602 /* We do not support all address sizes currently */
603 if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
604 return;
605 }
606
607 /* We can only remember one such occurance */
608 if (Sym->GuessedUse[AddrSize-1]) {
609 return;
610 }
611
612 /* Ok, remember the file position */
613 Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos));
614}
615
616
617
618void SymExportFromGlobal (SymEntry* S)
619/* Called at the end of assembly. Converts a global symbol that is defined
620** into an export.
621*/
622{
623 /* Remove the global flag and make the symbol an export */
624 S->Flags &= ~SF_GLOBAL;
625 S->Flags |= SF_EXPORT;
626}
627
628
629
630void SymImportFromGlobal (SymEntry* S)
631/* Called at the end of assembly. Converts a global symbol that is undefined
632** into an import.
633*/
634{
635 /* Remove the global flag and make it an import */
636 S->Flags &= ~SF_GLOBAL;
637 S->Flags |= SF_IMPORT;
638}
639
640
641
642int SymIsConst (const SymEntry* S, long* Val)
643/* Return true if the given symbol has a constant value. If Val is not NULL
644** and the symbol has a constant value, store it's value there.
645*/
646{
647 /* Check for constness */
648 return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
649}
650
651
652
653SymTable* GetSymParentScope (SymEntry* S)
654/* Get the parent scope of the symbol (not the one it is defined in). Return
655** NULL if the symbol is a cheap local, or defined on global level.
656*/
657{
658 if ((S->Flags & SF_LOCAL) != 0) {
659 /* This is a cheap local symbol */
660 return 0;
661 } else if (S->Sym.Tab == 0) {
662 /* Symbol not in a table. This may happen if there have been errors
663 ** before. Return NULL in this case to avoid further errors.
664 */
665 return 0;
666 } else {
667 /* This is a global symbol */
668 return S->Sym.Tab->Parent;
669 }
670}
671
672
673
674struct ExprNode* GetSymExpr (SymEntry* S)
675/* Get the expression for a non-const symbol */
676{
677 PRECONDITION (S != 0 && SymHasExpr (S));
678 return S->Expr;
679}
680
681
682
683const struct ExprNode* SymResolve (const SymEntry* S)
684/* Helper function for DumpExpr. Resolves a symbol into an expression or return
685** NULL. Do not call in other contexts!
686*/
687{
688 return SymHasExpr (S)? S->Expr : 0;
689}
690
691
692
693long GetSymVal (SymEntry* S)
694/* Return the value of a symbol assuming it's constant. FAIL will be called
695** in case the symbol is undefined or not constant.
696*/
697{
698 long Val;
699 CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
700 return Val;
701}
702
703
704
705unsigned GetSymImportId (const SymEntry* S)
706/* Return the import id for the given symbol */
707{
708 PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
709 return S->ImportId;
710}
711
712
713
714unsigned GetSymExportId (const SymEntry* S)
715/* Return the export id for the given symbol */
716{
717 PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U);
718 return S->ExportId;
719}
720
721
722
723unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
724/* Return a set of flags used when writing symbol information into a file.
725** If the SYM_CONST bit is set, ConstVal will contain the constant value
726** of the symbol. The result does not include the condes count.
727** See common/symdefs.h for more information.
728*/
729{
730 /* Setup info flags */
731 unsigned Flags = 0;
732 Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
733 Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
734 Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
735 if (S->Flags & SF_EXPORT) {
736 Flags |= SYM_EXPORT;
737 }
738 if (S->Flags & SF_IMPORT) {
739 Flags |= SYM_IMPORT;
740 }
741
742 /* Return the result */
743 return Flags;
744}
745