Object SYM represents a program symbol.
All defined symbols of the program including externs, literals and unnamed ($) symbols are kept on PGM.SymList.
A record on PGM.SymList is created
Symbol is not created when its attribute is queried, e.g. in %IF TYPE# aSymbol
.
Basic properties of symbol are
name .NamePtr, .NameSize
,
scope .Status
,
offset (AKA value) .OffsetLow, .OffsetHigh
,
segment identification .Section
.
When SYM.Section=0
, it is scalar with value in SYM.Offset
.
Otherwise it is addressing symbol and its (relocatable) virtual address is calculated as a sum of
SYM.Offset
and VA of the bottom of its segment (even when the symbol is defined in a segment's section).
Section bottom is recalculated when each pass ends, but segment bottom is always 0 at asm-time.
When the final assembly pass terminates, sections are permanently linked to their segments
and symbol's SYM.Section
is redefined and then it refers to its segment.
At link-time are homonymous segments from other modules combined, segment order is established by
PgmOrderSegments, external symbols resolved and
SYM.Frame
then specifies the group or segment used for addressing and relocation.
In case of scalar (segmentless) symbols some assemblers create an auxilliary pseudosegment named .scalars, absolute etc. When the symbol is external, its segment identification is NULL.
Strategy of €ASM is different: scalar (numeric) symbols have their segment identification empty (SYM.Section=0
)
and for external symbols it creates auxilliar pseudosegments of sssExtern
type with the same name.
Each external symbol in €ASM is accompanied with its homonymous external pseudosegment,
which is used in linking.
Also each ordinary relocable section and segment ([.text], [.data]
etc) is accompanied with its homonymous private symbol (.text, .data
etc) with
SYM.Status=symSe
, which is used for relocations.
Procedure | Condition | Action | Comment |
---|---|---|---|
PassCreate | SetSt symFixed | At the start of each pass all symbols created in previous passes are marked symFixed. | |
RstSt symDefInPass | |||
PassInspect | All symbols are fixed | SetSt pgmLastPass | If one or more symbols is not fixed, the next pass cannot be the last. |
!symFixed | RstSt pgmLastPass | ||
PassDestroy | symGlobal && symDefInPass | SetSt symPublic | At the end of each pass the flag symGlobal|symGlobalRef is expanded either to symPublic or symExtern. |
symGlobal && !symDefInPass | SetSt symExtern | ||
pgmLastPass && !symExtern && !symDefInPass && !symQueried | E6601 | ||
pgmLastPass && !symUsed && !symIncluded && !symPublic && !symExport | W2101 |
Querying symbol's attributes does not throw error even if the symbol is not defined.
Referencing a symbol which was not defined yet does not throw
an error (unless pgmLastPass
is set). Instead it is created with
temporary estimated attribute values:
Attribute | Value | Remark |
---|---|---|
TYPE# | '?' | Unknown in the first pass(es). |
SIZE# | 0 | Assuming it represents a non-dimensional point. |
SCOPE# | 'S' | Assuming standard private scope. |
OFFSET# | OFFSET#$+64 | Assuming it will be defined later withing short jump reach. |
SECTION# | SECTION#$ | Assuming it will be defined in the same section. |
SEGMENT# | SEGMENT#$ | Assuming it will be defined in the same segment. |
GROUP# | GROUP#$ | Assuming it will be defined in the same group. |
PARA# | GROUP#$>>4 | Assuming it will be defined in the same group. |
Attribute | Value | Remark |
---|---|---|
TYPE# | 'A' | Assuming it will stay external (undefined in program). |
SIZE# | 0 | |
SCOPE# | 'E' | Assuming it will stay external (undefined in program). |
OFFSET# | 0 | Runtime offset will be resolved by pseudosegment relocation. |
SECTION# | [Symbol] | A new extern pseudosegment is created together with the symbol.
Pseudosegment name is identical with external/imported symbol name. |
SEGMENT# | ||
GROUP# | ||
PARA # |
EUROASM NOWARN=2101 sym PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules. INCLUDEHEAD \ ; Include headers of another modules used in this module. ctx.htm, \ dict.htm, \ ea.htm, \ eaopt.htm, \ exp.htm, \ member.htm, \ msg.htm, \ pgm.htm, \ pgmopt.htm, \ reloc.htm, \ sss.htm, \ stm.htm, \ syswin.htm, \ var.htm, \ ;;
sym HEAD ; Start of module interface.
SYM STRUC ; +00h. .NamePtr D D ; Full qualified name (leading dot resolved, colons removed), or literal name, e.g.=B'abcd'
. .NameSize D D ; Number of bytes in symbol name {without colons). .InterNamePtr D D ; Pointer to imported symbol internal name or to forwarded export name. .InterNameSize D D ; Number of bytes in .InterName. ; +10h. .OffsetLow D D ; Value of scalar symbol or offset from the bottom of its section. .OffsetHigh D D ; .SymbPtr D D ; 0 if unresolved, or pointer to the resolved public symbol ifSYM.Status=symExtern|symImport|symExport
. .Section D D ; 0 for scalar, otherwise ^SSS (sssSection|sssExtern) where it was defined. ; +20h. .DllNamePtr D D ; Pointer to file name of DLL from which the symbol is imported or forwarded DLL name. .DllNameSize D D ; Number of bytes in .DllNamePtr. .LinePtr D D ; Pointer to memory-mapped source text where the symbol was declared. .Status D D ; Symbol properties, see SymEnc below. ; +30h. .Size D D ; Number of bytes emitted or reserved by the declaring statement. .Align D D ; Explicit alignment. 0=default,1,2,4,8,16,... .NameIndex D D ; Ordinal number (0..) in the symbol table. Also used as paragraph FA of module in LIBOMF. .NameDynIndex D D ; Ordinal number (0..) in the dynamic symbol table use in ELFSO format. ; +40h. .OrdinalNr D D ; Imported ordinal number value. Valid whenSYM.Status:symImportedByOrd
is set. ENDSTRUC SYM
SYM.Status
flags defined here are adopted from the refering
statement: symTypeMask + symPropMask
are kept synchronized with
stmTypeMask + stmPropMask
in statement encoding StmEnc.
symFixed
in PassCreate (when a new pass starts)
and the flag is reset if symbol properties are changed in the pass.; Symbol TYPE# symTypeMask = 0x0000_00FF ; Uppercase letter BUWDQTOYZISNA?. Synchronized with stmTypeMask. ; Symbol SCOPE#. value scope symPrivate = 0x0000_0000 ; 'S'. Default standard symbol scope. symExtern = 0x0000_0100 ; 'E'. Explicitly declared as EXTERN. symImport = 0x0000_0200 ; 'I'. Explicitly declared as IMPORT. symImportedByOrd = 0x0000_0400 ; 'I'. Imported by ordinal, not by name. Valid with symImport only. symExport = 0x0000_0800 ; 'X'. Explicitly declared as EXPORT. symForwarded = 0x0000_1000 ; 'X'. Export of symbol provided by other DLL. Valid with symExport only symSe = 0x0000_2000 ; 'S'. Implicit private symbol representing the bottom address of a segment|section. symEntry = 0x0000_4000 ; 'P'. Program public Entry symbol. Don't E6601 if undefined in the main program. symLiteral = 0x0000_8000 ; 'S'. Symbol is literal. symPublic = 0x0001_0000 ; 'P'. Explicitly declared as PUBLIC. symWeak = 0x0002_0000 ; 'P'. This weak-public symbol is ignored when another nonweak public symbol is linked. symGlobal = 0x0004_0000 ; 'G'|'P'|'E'. Explicitly declared as GLOBAL. symExplScopeMask = symPublic|symExport|symExtern|symImport|symGlobal|symWeak ; Symbol properties. Synchronized with stmPropMask symGlobalRef = 0x0008_0000 ; EQU stmLabelIsPublic. 'G'|'P'|'E'. Implicitly refered as global (its name ends with ::). symIncluded = 0x0010_0000 ; EQU stmIncluded. Symbol was defined in included source chunk. Do not warn W2101 if not used. symProc = 0x0020_0000 ; EQU stmProc. Symbol is defined as PROC or PROC1 or external function entry. symNear = 0x0040_0000 ; EQU stmNear. Symbol symProc has DIST=NEAR. symFar = 0x0080_0000 ; EQU stmFar. Symbol symProc has DIST=FAR. symPropMask = symIncluded|symProc|symNear|symFar symScopeMask = symExplScopeMask | symGlobalRef ; Referencing symbol flags. symEstimated = 0x0100_0000 ; Offset and other properties are only estimated in this pass. symDefined = 0x0200_0000 ; Symbol was defined at least once in any pass. symDefInPass = 0x0400_0000 ; Symbol was already defined in this pass. Reset in PassDestroy. symQueried = 0x0800_0000 ; Symbol's attribute was queried. Don't E6601 if not defined and not referred. symReferenced = 0x1000_0000 ; Symbol was referred. It should be defined, otherwise E6601. symUsed = 0x2000_0000 ; Symbol was referenced or queried at least once in any pass (symDirty). symFixed = 0x4000_0000 ; Offset and other properties are finally computed and fixed. symResolved = 0x8000_0000 ; This extern|export|import symbol was matched to a public symbol.
ENDHEAD sym ; End of module interface.
symExtern, symPublic, symImport, symExport
, or symPrivate=0
which will accept symbol of any scope.
SymFindByName Procedure SymScope, NamePtr, NameSize, ProgPtr MOV ESI,[%ProgPtr] TEST ESI JNZ .10: Invoke PgmGetCurrent:: JC .NotFound: MOV ESI,EAX ; ^PGM. .10: MOV EDX,[%NameSize] MOV EBX,[%NamePtr] TEST EDX JZ .NotFound: ListGetFirst [ESI+PGM.SymList] JZ .NotFound: .20: MOV ECX,[%SymScope] JECXZ .40: ; Skip symbol status check if %SymScope=0 (any scope will fit). JNSt [EAX+SYM.Status],ECX,.70: .40: CMP EDX,[EAX+SYM.NameSize] JNE .70: MOV ESI,[EAX+SYM.NamePtr] MOV ECX,EDX MOV EDI,EBX REPE CMPSB JE .Found .70: ListGetNext EAX JNZ .20: .NotFound: SUB EAX,EAX STC .Found:MOV [%ReturnEAX],EAX EndProcedure SymFindByName
symExtern, symPublic, symImport, symExport
, or 0,
which will accept symbol of any scope.
SymFindByInterName Procedure SymScope, NamePtr, NameSize, ProgPtr MOV ESI,[%ProgPtr] TEST ESI JNZ .05: Invoke PgmGetCurrent:: JC .NotFound: MOV ESI,EAX ; ^PGM. .05: MOV EDX,[%NameSize] MOV EBX,[%NamePtr] TEST EDX JZ .NotFound: ListGetFirst [ESI+PGM.SymList] JZ .NotFound: .10: MOV ECX,[%SymScope] JECXZ .20: ; Skip symbol status check if %SymScope=0. JNSt [EAX+SYM.Status],ECX,.70: .20: CMP EDX,[EAX+SYM.InterNameSize] JNE .70: MOV ESI,[EAX+SYM.InterNamePtr] MOV ECX,EDX MOV EDI,EBX REPE CMPSB JE .Found .70: ListGetNext EAX JNZ .10: .NotFound: SUB EAX,EAX STC .Found:MOV [%ReturnEAX],EAX EndProcedure SymFindByInterName
SYM.NameIndex
in €ASM symbols stored on
PGM.SymList
of the program identified by %ProgPtr
.SymFindByIndex Procedure SymIndex, ProgPtr XOR EAX,EAX MOV ECX,[%SymIndex] STC JECXZ .90: MOV EAX,[%ProgPtr] TEST EAX JNZ .10: Invoke PgmGetCurrent:: JC .90: .10:MOV EAX,[EAX+PGM.SymList] ListGetFirst EAX .30:STC JZ .90: CMP [EAX+SYM.NameIndex],ECX JE .90: ListGetNext EAX JMP .30: .90:MOV [%ReturnEAX],EAX EndProcedure SymFindByIndex
memberDelocal, memberDelocalParent
or memberDelocalNone
..data
).SymDelocalName Procedure NamePtr, NameSize, NameBuffer, Delocalize MOV ECX,[%NameSize] MOV ESI,[%NamePtr] MOV EBX,[%NameBuffer] MOV EDX,[%Delocalize] JECXZ .20: ; Empty name will pass. JNSt EDX, memberDelocal | memberDelocalParent, .20: ; If memberDelocalNone. CMPB [ESI],'.' ; Is the Name local? JNE .20: ; A local name will be prefixed with the current or parent namespace in the NameBuffer. SUB EAX,EAX JNSt [%Delocalize],memberDelocalParent,.10: Invoke CtxPeek::, ctxNamespace,0 ; Get and forget the current namespace context to EAX. .10: Invoke CtxPeek::, ctxNamespace,EAX JC .20: ; If there's no namespace on context stack. BufferStore EBX,[EAX+CTX.NamePtr],[EAX+CTX.NameSize] ; Store namespace name first. .20: BufferStore EBX,ESI,ECX ; Store the (local) Name. BufferRetrieve EBX JECXZ .90: LODSB ; Check the first character used in the name. DEC ECX ExpClassify AL TEST AH, expLetter | expFullstop JZ .E6110: ; Invalid symbol name "!1S". .30: JECXZ .90: LODSB DEC ECX ExpClassify AL TEST AH, expLetter | expDigit | expFullstop JNZ .30: .E6110:LEA EDI,[%NamePtr] Msg '6110',EDI,PgmStatus=pgmLastPass ; Invalid symbol name "!1S". STC .90:EndProcedure SymDelocalName
OffsetLow
, OffsetHigh
, Section
, Size
, LinePtr
.
symFixed
or 0.
SYM.%Member
.
SymMemberUpdate %MACRO Member MOV EAX,[EBX+STM.%Member] CMP EAX,[EDI+SYM.%Member] JE .Fixed%Member%.: MOV [EDI+SYM.%Member],EAX XOR ECX,ECX ; Set flag Fixed to FALSE. .Fixed%Member%.: %ENDMACRO SymMemberUpdate
SymCreate returns a program symbol specified by Name.
It will create a new symbol if it didn't exist in Program.SymList.
The symbol is then updated by Statement properties.
SymCreate is invoked in those circumstances:
symScopeMask
, symbol is declared
. This happens when the symbol scope is explicitly declared with pseudoinstruction
GLOBAL
, PUBLIC
, EXTERN
, EXPORT
or
IMPORT
.symDefined
, the symbol is defined
. This happens when symbol name appears in the label field of empty or machine instruction
or when it is explicitly defined with pseudoinstruction EQU
, D
,
PROC
or PROC1
.
symGlobalRef
may be set simultaneously in Reason parameter,
the symbol will be marked as symPublic or symExport later.symReferenced
, the symbol is referenced
, i.e. its name figures in an expression.
symGlobalRef
may be set simultaneously with
symReferenced
in Reason parameter.symQueried
, this means that some attribute of the symbol is queried
, i.e. an expression computes its attribute, e.g. %IF TYPE# Symbol = '?'
.
New symbol is not created when it didn't exist yet.Type and some other properties of created symbol are provided by
STM:.Section
, .Offset
,
.Size
, LinePtr
, stmTypeMask
,stmPropMask
.
Due to optimisation passes the final offset of the created symbol may be different from the value estimated
at symbol creation. Statement offset and other properties are updated here.
SYM.Status:symFixed
is reset when symbol properties got changed during the update.
Reason=symReferenced
, in this case new symbol will not be created if it didn't exist yet.SymCreate Procedure Reason, NamePtr, NameSize, Statement PgmPtr LocalVar ; ^Current program. PgmStatus LocalVar ; Local copy of program status. Fixed LocalVar ; Value of SYM.Status:symFixed during SymMemberUpdate. ClearLocalVar MOV EBX,[%Statement] ; Check if Program and Statement is provided. TEST EBX JZ .05: ; Internal error: creating symbol "!1S". MOV EDX,[EBX+STM.Program] MOV [%PgmPtr],EDX TEST EDX JZ .05: MOV EAX,[EDX+PGM.Status] MOV [%PgmStatus],EAX MOVD [%Fixed],symFixed JMP .10: .05:JSt [%Reason],symReferenced,.10: .F9960:LEA ESI,[%NamePtr] Msg '9960',ESI ; Internal error: creating symbol "!1S" outside a statement. .Error: XOR EAX,EAX MOV [%ReturnEAX],EAX STC JMP .90: .E6601: Msg '6601',EDI,[EDI+SYM.LinePtr] ; Symbol "!1S" mentioned at !2@ was not found. JMP .Error: .E6610:Msg '6610',EDI,[EDI+SYM.LinePtr] ; Symbol "!1S" was already defined at "!2@" JMP .Error: .E6621:Msg '6621',EDI,[EDI+SYM.LinePtr] ; External symbol "!1S" defined at "!2@" cannot be made public. JMP .Error: .E6622:Msg '6622',EDI,[EDI+SYM.LinePtr] ; Public symbol "!1S" defined at "!2@" cannot be made external. JMP .Error: .E6624:Msg '6624',EDI,[EDI+SYM.LinePtr] ; Symbol "!1S" was declared as external at !2@. JMP .Error: .E6637:Msg '6637' ; Special symbol "$" can be defined with EQU only. JMP .Error: .E6638:Msg '6638' ; Special symbol "$" cannot be declared global. JMP .Error: .10:TEST EDX JNZ .12: Invoke PgmGetCurrent:: MOV EDX,EAX .12:TEST EBX JNZ .13: MOV EBX,[EDX+PGM.CurrentStm] TEST EBX JZ .F9960: .13:; Check symbol name. MOV ESI,[%NamePtr] MOV ECX,[%NameSize] StripSpaces ESI,ECX StripColons ESI,ECX TEST ECX JZ .Error: ; Silently do not create symbol with empty name. CMP ECX,1 JNE .15: CMPB [ESI],'$' JNE .15: JSt [%Reason],symScopeMask,.E6638: ; Special symbol "$" cannot be declared global. JMP .E6637: ; Special symbol "$" can be defined with EQU only. .15:; Convert local name ESI,ECX to standard scope. CMPB [ESI],'.' JNE .18: ; If the name is not local. Invoke EaBufferReserve::,SymCreate Invoke SymDelocalName,ESI,ECX,EAX,memberDelocal BufferRetrieve EAX Invoke EaBufferRelease::, EAX .18:; ESI,ECX is now nonlocal nonempty trimmed symbol name. Check if it already exists on Program.SymList. Invoke SymFindByName,0,ESI,ECX,EDX MOV [%ReturnEAX],EAX ; Pointer to symbol, if found, otherwise 0. MOV EDI,EAX JNC .35: ; Skip the definition when the symbol already exists. ; Symbol does not exist yet. A new symbol will be defined/declared/referenced/queried. JSt [%Reason],symQueried,.90: ; Return no symbol (EAX=0), CF=0. ListNew [EDX+PGM.SymList],Zeroed=yes MOV EDI,EAX ; Pointer to a new empty symbol. MOV [%ReturnEAX],EAX PoolStore [EDX+PGM.Pool],ESI,ECX MOV ESI,EAX ; ESI,ECX is now nonvolatile nonlocal symbol name in Pgm.Pool. MOV [EDI+SYM.NamePtr],ESI MOV [EDI+SYM.NameSize],ECX MOV ECX,[%Fixed] SymMemberUpdate LinePtr ; Where was the symbol defined. MOV [%Fixed],ECX MOV EAX,[%Reason] SetSt [EDI+SYM.Status],EAX JNSt EAX,symDefined,.20: ; New symbol is being defined. Copy its type and properties from the statement. MOV ECX,stmTypeMask+stmPropMask+stmLabelIsPublic ; Masks aliases to symbol properties. AND ECX,[EBX+STM.Status] OR ECX,symDefined+symDefInPass SetSt [EDI+SYM.Status],ECX ; Inherit type, properties and symGlobalRef from the statement. RstSt [EDI+SYM.Status],symEstimated JMP .45: .20:JNSt EAX,symExplScopeMask, .25: ; New symbol EDI will be declared by explicit scope pseudoinstruction. JSt EAX,symPublic|symExport,.30: ; Go to estimate its properties. ; New symbol is declared symExtern or symImport. Invoke SssCreateExtern::,EDI,[%PgmPtr] JMP .90: .25:JNSt EAX,symReferenced,.90: ; New symbol EDI is forward referenced. Its properties will be estimated. SetSt EAX,symUsed+symReferenced+symEstimated + '?' MOV [EDI+SYM.Status],EAX .30:MOV ECX,[%Fixed] SymMemberUpdate Section ; Assume SECTION# $. SymMemberUpdate OffsetLow SymMemberUpdate OffsetHigh MOV [%Fixed],ECX ADDD [EDI+SYM.OffsetLow],64 ; Assume OFFSET# $ + 64. ADCD [EDI+SYM.OffsetHigh],0 JMP .80: .35: ; Symbol EDI already exists. It is redefined/redeclared/referenced. JNSt [%Reason],symDefined,.60: ; Existing symbol EDI is (re)defined. It will be updated from the statement EBX. MOV EDX,[EDI+SYM.Status] ; Old properties. JSt EDX,symDefInPass, .E6610: ; Symbol "!1S" was already defined at "!2@". JSt EDX,symExtern|symImport, .E6624: ; Symbol "!1S" was declared as external at !2@. MOV EAX,[EBX+STM.Status] ; New properties. MOV ECX,stmTypeMask+stmPropMask+stmLabelIsPublic ; Synchronized with symTypeMask+symPropMask+symGlobalRef. JNSt EDX,symEntry,.38: OR EAX,stmLabelIsPublic ; When the ENTRY is defined in source, pretend it is implicitely global::. .38:; Update symbol type and miscellaneous properties. JNSt EDX,symGlobalRef,.39: SetSt EAX,symGlobalRef .39:AND EAX,ECX AND EDX,ECX CMP EAX,EDX JE .40: RstSt [EDI+SYM.Status],symFixed ; If any of symbol properties had changed, a new pass will be required. .40:OR EAX,symDefined+symDefInPass NOT ECX ANDD [EDI+SYM.Status],ECX ; Erase old symbol type and properties. SetSt [EDI+SYM.Status],EAX ; Replace them with the new ones. .45:; Update other properties from the statement. MOV ECX,[%Fixed] SymMemberUpdate Section JNSt [EDI+SYM.Status],symExplScopeMask,.47: MOV ECX,[%Fixed] ; Do not reset symFixed due to SYM.Section change when the symbol is defined and exported. .47:JSt [EDI+SYM.Status],symProc,.48: ; Size of PROC symbol will be updated in PseudoENDPROC. SymMemberUpdate Size MOV [%Fixed],ECX ; Update offset. .48:MOV EAX,[EDI+SYM.OffsetLow] MOV EDX,[EDI+SYM.OffsetHigh] SUB EAX,[EBX+STM.OffsetLow] SBB EDX,[EBX+STM.OffsetHigh] ; EDX:EAX is negative if symbol offset grows in this pass. JS .50: ; Growing is acceptable in any pass, including the fixing one. JNSt [%PgmStatus],pgmFixingPass|pgmLastPass,.50: ; Do not decrease symbol offset in fixing pass. Stuff the emitted code with NOPs instead. ADD [EBX+STM.AlignBytes],EAX JMP .80: .50:SUB [EDI+SYM.OffsetLow],EAX ; Update offset in ordinary passes. SBB [EDI+SYM.OffsetHigh],EDX OR EAX,EDX JZ .55: RstSt [%Fixed],symFixed ; Signalize that offset has changed. .55: ; Update flag symFixed. JSt [%Fixed],symFixed,.60: RstSt [EDI+SYM.Status],symFixed ; This will force PassInspect to require one more pass. .60:MOV EAX,[%Reason] JNSt EAX,symExplScopeMask,.80: ; Existing symbol EDI is (re)declared. Check for conflicts. JNSt EAX,symPublic|symExport,.70: JSt EAX,symForwarded|symExport,.70: JSt [EDI+SYM.Status],symExtern|symImport,.E6621: ; External symbol "!1S" defined at "!2@" cannot be made public. .70:JNSt EAX,symExtern|symImport,.75: JSt [EDI+SYM.Status],symDefined,.E6622: ; Public symbol "!1S" defined at "!2@" cannot be made external. .75:SetSt [EDI+SYM.Status],EAX ; Update the scope. .80:MOV EAX,[%Reason] JNSt EAX,symReferenced,.85: ; Existing symbol is referenced. SetSt EAX,symUsed PUSH EAX,EDI; If symbol EDI is member of a structured symbol, mark the parent symbol symReferenced, too. MOV EBX,EDI MOV EDI,[EBX+SYM.NamePtr] MOV ECX,[EBX+SYM.NameSize] MOV EDX,EDI MOV AL,'.' REPNE SCASB JNE .84: ; If there's no membership in symbol name. DEC EDI MOV ECX,[%Statement] JECXZ .84: MOV ECX,[ECX+STM.Program] SUB EDI,EDX ; EDX,EDI is now potentional parent's name. Invoke SymFindByName,0,EDX,EDI,ECX JC .84: ; If no parent exists. SetSt [EAX+SYM.Status],symUsed+symReferenced .84:POP EDI,EAX SetSt [EDI+SYM.Status],EAX JSt [EDI+SYM.Status],symDefined,.85: JNSt [EDI+SYM.Status],symEstimated,.85: RstSt [EDI+SYM.Status],symEstimated XOR EAX,EAX MOV [EDI+SYM.OffsetLow],EAX ; In the next passes is the original estimated offset $+64 changed to 0. MOV [EDI+SYM.OffsetHigh],EAX .85:JNSt [%PgmStatus],pgmLastPass,.90: ; Final pass check of the symbol. JSt [EDI+SYM.Status],symDefined,.88: JSt [EDI+SYM.Status],symExtern|symImport|symForwarded|symEntry,.90: JMP .E6601: ; Symbol "!1S" mentioned at !2@ was not found. .88:JSt [EDI+SYM.Status],symIncluded|symScopeMask|symReferenced|symQueried,.90: MOV ECX,[EDI+SYM.Section] JECXZ .89: JSt [ECX+SSS.Status],sssStructure,.90: .89:Msg '2101',EDI ; Symbol !1S was defined but never used. .90:EndProcedure SymCreate
sssGroup
if symbol's segment is in a GROUP, otherwise
sssSegment
. In program formats ELF* it is always sssSegment
because sssGroup
represents "segment" in ELF program header.SymFrameAddress Procedure Symbol, Program SUB EAX,EAX SUB EDX,EDX SUB ECX,ECX MOV ESI,[%Symbol] MOV EBX,[%Program] TEST ESI JZ .80: MOV EAX,[ESI+SYM.OffsetLow] MOV EDX,[ESI+SYM.OffsetHigh] MOV ECX,[ESI+SYM.Section] JECXZ .80: ; Symbol is scalar. JSt [EBX+PGM.Pgmopt.Status],pgmoptELFbased,.80: ; Skip group in ELF* format. MOV EDI,[ECX+SSS.GroupPtr] TEST EDI JNZ .10: MOV EDI,ECX .10:JNSt [ECX+SSS.Status],sssExtern,.20: MOV ESI,[ECX+SSS.SymPtr] TEST ESI JZ .80: ADD EAX,[ESI+SYM.OffsetLow] ADC EDX,[ESI+SYM.OffsetHigh] MOV ECX,[ESI+SYM.Section] JECXZ .80: MOV ECX,[ECX+SSS.SegmPtr] MOV EDI,[ECX+SSS.GroupPtr] TEST EDI JNZ .20: MOV EDI,ECX ; Group EDI equals to segment ECX if the segment is not grouped. JMP .30: .20:MOV EDI,[EDI+SSS.GroupPtr] ; Group might be linked from external module. .30:TEST EDI JNZ .40: MOV EDI,ECX ; Group EDI equals to segment ECX if the segment is not grouped. .40:; ECX is now symbol's segment and EDI its group, both are nonzero. JSt [EBX+PGM.Pgmopt.Status],pgmoptFLAT,.50: ; Frame is 0 in FLAT model. ADD EAX,[ECX+SSS.BottomLow] ADC EDX,[ECX+SSS.BottomHigh] SUB EAX,[EDI+SSS.BottomLow] SBB EDX,[EDI+SSS.BottomHigh] .50:MOV ECX,EDI .80:MOV [%ReturnEAX],EAX MOV [%ReturnEDX],EDX MOV [%ReturnECX],ECX EndProcedure SymFrameAddress
.DllName
and .InterName
. Both Dll and Fwd parameters may be empty.
user32.dll.
SymDynamicLink Procedure Sym,PgmPtr,DllPtr,DllSize,FwdPtr,FwdSize MOV EDI,[%Sym] MOV EBX,[%PgmPtr] TEST EDI JZ .90: Invoke SssCreateExtern::,EDI,EBX JSt [EDI+SYM.Status],symImport,.10: JNSt [EDI+SYM.Status],symExport,.90: SetSt [EDI+SYM.Status],symGlobal ; Export symbol implies globality. .10: MOV ECX,[%DllSize] MOV ESI,[%DllPtr] JECXZ .60: ; If LIB= is not explicitly specified, leave it as is. ListGetFirst [EBX+PGM.SymList] ; Reuse identical DllName from any older symbol. JZ .40: .20: JNSt [EAX+SYM.Status],symImport|symExport,.30: MOV EDX,[EAX+SYM.DllNamePtr] ; Old nonvolatile DllName. Compare EDX,[EAX+SYM.DllNameSize],ESI,ECX JE .50: ; If found, reuse previously stored name EDX. .30: ListGetNext EAX JNZ .20: .40: PoolStore [EBX+PGM.Pool],ESI,ECX ; Make DllName nonvolatile. MOV EDX,EAX .50: MOV ESI,EDX MOV [EDI+SYM.DllNamePtr],ESI MOV [EDI+SYM.DllNameSize],ECX .60: JNSt [EDI+SYM.Status],symExport,.90: MOV ESI,[%FwdPtr] MOV ECX,[%FwdSize] JECXZ .90: ; If no forward was specified. SetSt [EDI+SYM.Status],symForwarded PoolStore [EBX+PGM.Pool],ESI,ECX JMP .80: .70: MOV EAX,[EDI+SYM.NamePtr] ; Default Fwd name is identical with symbol name. MOV ECX,[EDI+SYM.NameSize] .80: MOV [EDI+SYM.InterNamePtr],EAX MOV [EDI+SYM.InterNameSize],ECX .90:EndProcedure SymDynamicLink
symExport+symForwarded
flags set.
SymStoreForwarderName Procedure Symb, FwdBuffer MOV EBX,[%Symb] JNSt [EBX+SYM.Status],symExport,.90: JNSt [EBX+SYM.Status],symForwarded,.90: MOV ESI,[EBX+SYM.DllNamePtr] MOV ECX,[EBX+SYM.DllNameSize] FileNameParse ESI,Size=ECX,Unicode=0 SUB ECX,EAX ; EAX,ECX is now the file name without extension. MOV EDX,[%FwdBuffer] BufferStore EDX,EAX,ECX BufferStoreByte EDX,'.' MOV ESI,[EBX+SYM.InterNamePtr] MOV ECX,[EBX+SYM.InterNameSize] TEST ECX JNZ .80: MOV ESI,[EBX+SYM.NamePtr] MOV ECX,[EBX+SYM.NameSize] .80: BufferStore EDX,ESI,ECX BufferStoreByte EDX,0 .90:EndProcedure SymStoreForwarderName
StmPtr.Program.SymList
or reuse existing symbol with identical name.
LIteral strings without type specifier, e.g. ="String" will be in fact created under modified name =B"String" or =U"String".
SymCreateLiteral Procedure LitPtr, LitSize, StmPtr LitNameBuffer LocalVar ; Temporary buffer for updated literal name. LitEmitBuffer LocalVar ; Temporary buffer for emitted data. LitRelocBuffer LocalVar ; Temporary buffer for emitted relocations. LitSection LocalVar ; ^SSS with [@RT0] or [@LT*]. ExpStatus LocalVar ; Status of literal evaluated to EXP. EaStackCheck ; Protect from SO in case of recursed literal. Invoke EaBufferReserve::,SymCreateLiteral MOV [%LitNameBuffer],EAX Invoke EaBufferReserve::,SymCreateLiteral MOV [%LitEmitBuffer],EAX Invoke EaBufferReserve::,SymCreateLiteral MOV [%LitRelocBuffer],EAX MOV EBX,[%StmPtr] TEST EBX JZ .Error: MOV EDX,[EBX+STM.Program] TEST EDX JNZ .10: .Error:SUB EAX,EAX MOV [%ReturnEAX],EAX STC JMP .90: .10: ; Prepare literal name. MOV EDI,[%LitNameBuffer] MOV ESI,[%LitPtr] MOV ECX,[%LitSize] StripSpaces ESI,ECX BufferStore EDI,ESI,ECX LEA EDX,[ESI+ECX] LODSB CMP AL,'=' JNE .Error: .14: CMP ESI,EDX JNB .22: LODSB ExpClassify AL TEST AH,expWhiteSpace JNZ .14: DEC ESI ; ESI now points to source data expression. SUB EDX,ESI ; EDX is size of the value, i.e. everything following =. TEST AH,expQuote JZ .22: ; Literal defines a string without type.B
orU
will be injected into its name. BufferClear EDI MOV AX,"=U" JSt [Ea.Eaopt.Status::],eaoptUNICODE,.18: ; If EUROASM UNICODE=Enabled. MOV AX,"=B" .18: BufferStoreWord EDI,EAX ; Insert either=B
or=U
. BufferStore EDI,ESI,EDX ; Insert the rest (quoted string). .22: ; Evaluate literal data to %LitEmitBuffer and %LitRelocBuffer. BufferRetrieve EDI ; Literal name, e.g.=U"Text"
. INC ESI ; Omit theleading =. DEC ECX MOV EDX,[%LitEmitBuffer] Invoke ExpEvalData::,EDX,[%LitRelocBuffer],ESI,ECX,0,EBX MOV [%ExpStatus],EAX ; EAX='B' or 'W' or 'I'...etc (datatype) + expString flag. JC .Error: JNSt EAX,expString, .30: CMP AL,'B' JNE .26: BufferStoreByte EDX,0 ; Terminate string literal value with NUL byte. .26: CMP AL,'U' JNE .30: BufferStoreWord EDX,0 ; Terminate string literal value with NUL unichar. .30: CMP AL,'I' ; Get|create literal section suitable for the literal data|code. JNE .34: Invoke SssCreate@RT::,0,EBX ; Create code literal section if it didn't exist. JMP .38: ; EBX=^STM. .34: Invoke SssCreate@LT::,EAX,EBX ; Create data literal section if it didn't exist. .38: JC .Error: MOV [%LitSection],EAX BufferRetrieve [%LitNameBuffer] MOV EDX,[EBX+STM.Program] XOR EDI,EDI Invoke SymFindByName,0,ESI,ECX,EDX ; Look if literal symbol with verbatim same name was already created in program EDX. MOV [%ReturnEAX],EAX ; EAX=^SYM or 0. JNC .40: PoolStore [EDX+PGM.Pool],ESI,ECX ; Not found. A new literal symbol with name ESI,ECX will be created in program EDX. MOV ESI,EAX ; ESI,ECX is now nonvolatile literal name, e.g. "=B 1+2", with PGM lifetime. ListNew [EDX+PGM.SymList], Zeroed=yes ; Allocate room for the new literal symbol in program EDX. MOV [%ReturnEAX],EAX ; EAX=^SYM, EBX=^STM, EDX=^PGM, ESI,ECX=literal name. MOV [EAX+SYM.NamePtr],ESI MOV [EAX+SYM.NameSize],ECX MOV ECX,[%ExpStatus] ; (Re)initialize status of literal symbol EAX. MOV EDX,[EBX+STM.LinePtr] RstSt ECX,expString SetSt ECX,symLiteral+symDefined+symReferenced+symUsed+symFixed MOV [EAX+SYM.LinePtr],EDX ; Source line where it was first referred, i.e. created. MOV [EAX+SYM.Status],ECX .40: MOV EBX,[%LitSection] MOV EDI,[EAX+SYM.OffsetLow] JSt [EAX+SYM.Status],symDefInPass,.62: ; Skip emit to literal section when already emitted. SetSt [EAX+SYM.Status],symDefInPass ; Look if the value of symbol EAX stored in [%LitEmitBuffer] is already emitted in %LitSection. BufferRetrieve [%LitRelocBuffer] ; Are there any relocations in literal value? TEST ECX ; Relocatable value cannot be shared JNZ .53: ; because it might be resolved to a different VA. BufferRetrieve [EBX+SSS.EmitBuffer] MOV EDI,ESI LEA EDX,[ESI+ECX] ; EDI..EDX is now the already emitted contents of literal section. .46: BufferRetrieve [%LitEmitBuffer] ; ESI,ECX is now the new literal value. EAX=^SYM, EBX=^SSS. LEA EAX,[EDI+ECX] CMP EAX,EDX JA .53: ; Skip when behind the section limit. PUSH EDI REPE CMPSB POP EDI JE .49: ; Reusable literal value was found. ADD EDI,[EBX+SSS.Alignment] ; Try the next possible aligned position in literal section. JMP .46: .49: ; Reusable literal value was found in SSS.EmitBuffer at EDI. BufferRetrieve [EBX+SSS.EmitBuffer] SUB EDI,ESI JMP .62: .53: ; Literal value was not found in SSS.EmitBuffer. Let's emit [%LitEmitBuffer] to the section EBX. Invoke ExpAlign::,[EBX+SSS.OrgLow],[EBX+SSS.Alignment],0 ; Get AlignBytes to ECX. MOV EDI,[EBX+SSS.OrgLow] ADD EDI,ECX MOV EAX,[%ReturnEAX] MOV [EAX+SYM.OffsetLow],EDI MOV ESI,[%StmPtr] MOV EAX,[ESI+STM.Program] MOV ESI,[%LitRelocBuffer] JSt [EAX+PGM.Status],pgmLastPass, .57: XOR ESI,ESI ; Do not store relocation if not in the final pass. .57: Invoke SssEmit::,EBX,[%LitEmitBuffer],ESI,ECX .62: MOV EAX,[%ReturnEAX] ; Update properties of literal symbol EAX. CMP EDI,[EAX+SYM.OffsetLow] ; EDI is symbol offset from segment's bottom. JE .70: MOV [EAX+SYM.OffsetLow],EDI ; Offset from previous pass is different. RstSt [EAX+SYM.Status],symFixed .70: MOV EBX,[%LitSection] CMP EBX,[EAX+SYM.Section] JE .75: MOV [EAX+SYM.Section],EBX RstSt [EAX+SYM.Status],symFixed .75: MOV ECX,[EBX+SSS.Alignment] CMP ECX,[EAX+SYM.Align] JE .80: MOV [EAX+SYM.Align],ECX RstSt [EAX+SYM.Status],symFixed .80: BufferRetrieve [%LitEmitBuffer] CMP ECX,[EAX+SYM.Size] JE .90: MOV [EAX+SYM.Size],ECX RstSt [EAX+SYM.Status],symFixed .90: PUSHFD ; Keep CF. Invoke EaBufferRelease::,[%LitEmitBuffer] Invoke EaBufferRelease::,[%LitRelocBuffer] Invoke EaBufferRelease::,[%LitNameBuffer] POPFD ; Restore CF. EndProcedure SymCreateLiteral
symSe
with the same name as the group|segment|section.
This new symbol represents the bottom of group|segment|section and it can be used in relocations.SSS.SymPtr
.SymCreateSe Procedure SePtr, PgmPtr MOV EDI,[%SePtr] MOV EBX,[%PgmPtr] MOV ESI,[EDI+SSS.NamePtr] MOV ECX,[EDI+SSS.NameSize] Invoke SymFindByName,symSe,ESI,ECX,EBX JNC .20: ListNew [EBX+PGM.SymList],Zeroed=Yes .20: MOV [EDI+SSS.SymPtr],EAX MOV [EAX+SYM.NamePtr],ESI MOV [EAX+SYM.NameSize],ECX MOV [EAX+SYM.Section],EDI MOV ECX,[EDI+SSS.LinePtr] MOV [EAX+SYM.Status],symSe+symDefined+symFixed+'A' MOV [EAX+SYM.LinePtr],ECX EndProcedure SymCreateSe
SymCombine Procedure Symbol, BasePgm MOV EBX,[%BasePgm] MOV ESI,[%Symbol] MOV EDX,[ESI+SYM.Status] JNSt EDX,symSe,.30: MOV ECX,[ESI+SYM.Section] ; Symbol symSe (which is assigned to a segment). JECXZ .90: JNSt [ECX+SSS.Status],sssCombined,.30: MOV EDX,[ECX+SSS.SegmPtr] ; Do not copy symSe symbol from already combined segment to the BasePgm. MOV EAX,[EDX+SSS.SymPtr] ; Let it refer to the symSe in BasePgm instead. MOV [ESI+SYM.SymbPtr],EAX JMP .90: .30:JNSt EDX,symPublic,.40: Invoke SymFindByName, symPublic,[ESI+SYM.NamePtr],[ESI+SYM.NameSize],EBX JC .70: Msg '8540',EAX,[EAX+SYM.LinePtr]; Public symbol "!1S" was already defined at !2@. JMP .90: .40:JNSt EDX,symImport,.70: Invoke SymFindByName, symImport,[ESI+SYM.NamePtr],[ESI+SYM.NameSize],EBX JC .70: ; Merge import symbol ESI to EAX. MOV [ESI+SYM.SymbPtr],EAX SetSt [ESI+SYM.Status],symResolved MOV ECX,[EAX+SYM.DllNameSize] TEST ECX JNZ .90: MOV EDI,[ESI+SYM.DllNamePtr] MOV ECX,[ESI+SYM.DllNameSize] MOV [EAX+SYM.DllNamePtr],EDI MOV [EAX+SYM.DllNameSize],ECX JMP .90: .70:ListStore [EBX+PGM.SymList],ESI ; Copy the linked symbol to BasePgm. MOV EDI,EAX ; Copied symbol on BasePgm. SetSt [EDI+SYM.Status],symDefined MOV [ESI+SYM.SymbPtr],EDI ; Let the abandoned symbol ESI refer to copied symbol EDI. MOV ECX,[EDI+SYM.Section] JECXZ .90: MOV EAX,[ECX+SSS.BottomLow] MOV EDX,[ECX+SSS.BottomHigh] MOV ECX,[ECX+SSS.SegmPtr] SUB EAX,[ECX+SSS.BottomLow] SBB EDX,[ECX+SSS.BottomHigh] ADD [EDI+SYM.OffsetLow],EAX ADC [EDI+SYM.OffsetHigh],EDX MOV [EDI+SYM.Section],ECX .90:EndProcedure SymCombine
PgmCheckUnresolved will check all external and imported symbols and report E6961 when they were not matched to their homonymous public symbols.
This procedure is not invoked when the program format is linkable.
SymReportUnresolved Procedure PgmPtr MOV EBX,[%PgmPtr] ListGetFirst [EBX+PGM.SymList] JZ .90: .10:JNSt [EAX+SYM.Status],symExtern|symImport,.80: JSt [EAX+SYM.Status],symResolved|symPublic|symForwarded,.80: Msg '6961',EAX ; Unresolved external/imported symbol "!1S". .80:ListGetNext EAX JNZ .10: .90:EndProcedure SymReportUnresolved
symResolved
and its
SYM.SymbPtr
points to the matching public (or weak) symbol in BasePgm.SymResolve Procedure Symbol, BasePgm MOV EDI,[%Symbol] MOV EBX,[%BasePgm] JSt [EDI+SYM.Status],symResolved,.90: JNSt [EDI+SYM.Status],symExtern|symImport,.90: MOV EDX,EDI MOV ECX,[EDI+SYM.SymbPtr] JECXZ .30: MOV EDX,ECX MOV ECX,[EDX+SYM.SymbPtr] JECXZ .30: MOV EDX,ECX .30:MOV ESI,[EDI+SYM.NamePtr] MOV ECX,[EDI+SYM.NameSize] Invoke SymFindByName,symPublic,ESI,ECX,EBX ; Prefer PUBLIC scope. JNC .50: Invoke SymFindByName,symWeak,ESI,ECX,EBX ; When PUBLIC symbol is not found, try to find a WEAK one. JNC .50: Invoke SymFindByName,symImport,ESI,ECX,EBX ; Try to match external symbol to an imported one. JNC .50: Invoke SymFindByName,symSe,ESI,ECX,EBX ; Try to match external segment's pseudosymbol to a standard one. JC .90: .50:CMP EAX,EDI JE .90: ; Never resolve symbol with itself. MOV [EDI+SYM.SymbPtr],EAX ; Pointer to the resolved public counterpart. .60:SetSt [EDI+SYM.Status],symResolved .70:JNSt [EDI+SYM.Status],symExport,.90: SetSt [EAX+SYM.Status],symExport .90:EndProcedure SymResolve
SYM.DllNamePtr
is converted to lower case.SymLowcaseDll Procedure ImpSym MOV EBX,[%ImpSym] MOV ECX,[EBX+SYM.DllNameSize] JECXZ .90: MOV ESI,[EBX+SYM.DllNamePtr] .20:LODSB CMP AL,'A' JB .50: CMP AL,'Z' JA .50: XOR AL,'A'^'a' MOV [ESI-1],AL .50:DEC ECX JNZ .20: .90:EndProcedure SymLowcaseDll
ENDPROGRAM sym