Class MEMBER describers a named structure member.
When a STRUC is defined, each its
with a label creates MEMBER record added to its Sss.MemberBuffer.
Local member names are similary kept in Sss.PgmPool until end of program.
Structure members themselves create a plain-numeric symbols. Address symbols will be created from them whenever the structure is expanded (data variable created with
Declaring a STRUC/ENDSTRUC block creates symbol from each its member, no matter if the structure will be ever expanded in data section or not. Name of such symbols is created from structure name appended with local member name. Their type is 'N'.
When the structure is expanded (using
DS statement), another set of symbols
is created, their name is constructed from
DS label appended with local member name.
member PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
sss HEAD ; Start of module interface.
MEMBER STRUC ; Description of named data (D* statements) inside the structure. .NamePtr D D ; Pointer to local member name. .NameSize D D ; Number of bytes in member name. .Offset D D ; Aligned offset of this member relative to start of the structure. .Size D D ; Size of member value in bytes. .Status D D ; DataType in LSB ('B','U','W','D','Q','T') ENDSTRUC MEMBER
memberType EQU 0x0000_00FF ; DataType od structure member ('B','U','W','D','Q','T').
ENDHEAD sss ; End of module interface.
MemberAdd Procedure SssPtr, StmPtr, DstrucPtr OutMember LocalVar Size=SIZE#MEMBER InnMember LocalVar Size=SIZE#MEMBER MOV EBX,[%StmPtr] MOV EDI,[%SssPtr] MOV ESI,[EBX+STM.LabelPtr] MOV ECX,[EBX+STM.LabelSize] PoolStore [EDI+SSS.PgmPool],ESI,ECX LEA EDI,[%OutMember] MOV [EDI+MEMBER.NamePtr],EAX MOV [EDI+MEMBER.NameSize],ECX MOV EAX,[EBX+STM.Status] MOV EDX,[EBX+STM.Size] MOV [EDI+MEMBER.Status],EAX MOV [EDI+MEMBER.Size],EDX MOV ESI,[%SssPtr] MOV EAX,[ESI+SSS.OrgLow] ADD EAX,[EBX+STM.AlignBytes] MOV [EDI+MEMBER.Offset],EAX BufferStore [ESI+SSS.MemberBuffer],EDI,SIZE#MEMBER Msg cc=C,'9314',MemberAdd ; If the added member (.Out2) is structured, its submembers will be stored, too. MOV EDX,[%DstrucPtr] TEST EDX JZ .90: JNSt [EDX+SSS.Status],sssStructure,.90: MOV EBX,ESI ; EDI=^MEMBER just added (".Out2"). ; EBX=^SSS struc which the member was just added to (Outer) ; EDX=^SSS belonging to the added member (Inner). ; Local name of each member from structure EDX (".Inn1") will be prefixed with ; member name (".Out2"), saved on [EBX+SSS.PgmPool] and added to [EBX+SSS.MemberBuffer]. BufferRetrieve [EDX+SSS.MemberBuffer] TEST ECX JZ .90: .20: PUSH ECX ; ESI=^MEMBER from inner structure (.Inn1) LEA EDX,[%InnMember] MOV EAX,[ESI+MEMBER.Status] MOV ECX,[ESI+MEMBER.Size] MOV [EDX+MEMBER.Status],EAX MOV [EDX+MEMBER.Size],ECX MOV EAX,[EDI+MEMBER.Offset] ADD EAX,[ESI+MEMBER.Offset] MOV [EDX+MEMBER.Offset],EAX Invoke EaBufferReserve::,MemberAdd ; Temporary buffer for names concatenation. BufferStore EAX,[EDI+MEMBER.NamePtr],[EDI+MEMBER.NameSize] JC .F9314: BufferStore EAX,[ESI+MEMBER.NamePtr],[ESI+MEMBER.NameSize] JC .F9314: PUSH ESI BufferRetrieve EAX Invoke EaBufferRelease::,EAX PoolStore [EBX+SSS.PgmPool],ESI,ECX MOV [EDX+MEMBER.NamePtr],EAX MOV [EDX+MEMBER.NameSize],ECX POP ESI BufferStore [EBX+SSS.MemberBuffer],EDX,SIZE#MEMBER JNC .80: .F9314:Msg cc=C,'9314',MemberAdd POP ECX JMPS .90: .80: POP ECX ADD ESI,SIZE#MEMBER SUB ECX,SIZE#MEMBER JA .20: .90:EndProcedure MemberAdd
MemberCreate Procedure SssPtr, StmPtr McStm LocalVar Size=SIZE#STM ; Fake statement which provides info for creating a symbol. LEA EBX,[%McStm] CopyTo EBX,[%StmPtr],Size=SIZE#STM ; Initialize temporary fake statement. .10:MOV EDX,[%SssPtr] ; ^SSS structure. MOV EDI,[EBX+STM.OffsetLow] TEST EDX STC JZ .90: BufferRetrieve [EDX+SSS.MemberBuffer] TEST ECX JZ .90: ; Do nothing if no named members are in buffer. .50:PUSH ECX,ESI,EDI ; ESI=^MEMBER. MOV ECX,[ESI+MEMBER.NameSize] MOV EDX,[ESI+MEMBER.Size] ADD EDI,[ESI+MEMBER.Offset] MOV EAX,[ESI+MEMBER.Status] MOV ESI,[ESI+MEMBER.NamePtr] MOV [EBX+STM.Size],EDX MOV [EBX+STM.OffsetLow],EDI MOV [EBX+STM.Status],AL MOV EAX,stmLabelIsPublic AND EAX,[EBX+STM.Status] OR EAX,symDefined Invoke SymCreate::,EAX,ESI,ECX,EBX TEST EAX JZ .80: SetSt [EAX+SYM.Status],symReferenced ; Member of a structure shouldn't report W2101. .80: POP EDI,ESI,ECX ADD ESI,SIZE#MEMBER SUB ECX,SIZE#MEMBER JA .50: .90:EndProcedure MemberCreate
OutEmitBuffer, updating matching members by keywords in
MemberUpdate Procedure SssPtr, StmPtr, OutEmitBuffer, OutRelocBuffer MuEmitBuffer LocalVar ; Temporary buffer used in keyword value evaluation. MuRelocBuffer LocalVar ; Temporary buffer used in keyword value evaluation. Invoke EaBufferReserve::,MemberUpdate MOV [%MuEmitBuffer],EAX Invoke EaBufferReserve::,MemberUpdate MOV [%MuRelocBuffer],EAX MOV EDI,[%SssPtr] ; Instantionized structure. MOV EBX,[%StmPtr] ; Definition statement with keywords. TEST EDI STC JZ .99: BufferRetrieve [EDI+SSS.EmitBuffer] ; Template data of the structure, including its static defaults. BufferStore [%OutEmitBuffer],ESI,ECX Msg cc=C,'9314',MemberUpdate ; OutEmitBuffer is initialized with STRUC defaults. Now its members will be updated by Stm keywords. ; Outer loop .10: .. .80: walks through statement keywords, and for each keyword ; an inner loop .20: .. .30: searches for the member. BufferRetrieve [EBX+STM.KeyBuffer] LEA EDX,[ESI+ECX] ; ESI..EDX are keyword records (4*DD). .10: CMP ESI,EDX JNB .90: PUSH EDX,ESI MOV EDI,[%SssPtr] MOV EBX,ESI ; EBX is now keyword record (4*DD). BufferRetrieve [EDI+SSS.MemberBuffer] LEA EDX,[ESI+ECX] ; ESI..EDX are MEMBER records. .20: CMP ESI,EDX JNB .30: Compare [EBX+0],[EBX+4],[ESI+MEMBER.NamePtr],[ESI+MEMBER.NameSize] JE .40: ADD ESI,SIZE#MEMBER JMP .20: .30: ; Keyword is not in memberlist. Msg '2612',EBX,EDI,PgmStatus=pgmLastPass ; "!1S" is not member of structure !2S. Ignored. JMP .80: ; Continue with the next keyword. .40: ; Matching member found. Keyword value at [EBX+8],[EBX+12] will safely rewrite ; corresponding contents of OutEmitBuffer at [ESI+MEMBER.Offset]. BufferClear [%MuEmitBuffer] BufferClear [%MuRelocBuffer] Invoke ExpEvalData::,[%MuEmitBuffer],[%MuRelocBuffer],[EBX+8],[EBX+12],[ESI+MEMBER.Status],[%StmPtr] JC .80: MOV EAX,[ESI+MEMBER.Offset] ; Relative offset inside the structure contents (0..value size). MOV EDX,[ESI+MEMBER.Size] ; Maximal size that may be rewritten. BufferRetrieve [%MuEmitBuffer] ; ESI,ECX is proposed new value. CMP ECX,EDX JBE .50: LEA ECX,[EBX+8] Msg '2613',ECX,[%SssPtr],EBX ; Value "!1S" does not fit to structure member !2S.!3S. Truncated. MOV ECX,EDX .50: MOV EDI,ESI MOV EDX,ECX ; EDI,EDX is now truncated new value. BufferRetrieve [%OutEmitBuffer] ADD ESI,EAX ; Add member offset. CopyTo ESI,EDI,Size=EDX ; Rewrite (truncated) data in OutEmitBuffer. BufferRetrieve [%MuRelocBuffer] JECXZ .80: .60: ; Each relocation in keyword value will be patched with member offset in EAX. ADD [ESI+RELOC.OrgLow],EAX ADCD [ESI+RELOC.OrgHigh],0 BufferStore [%OutRelocBuffer],ESI,SIZE#RELOC Msg cc=C,'9314',MemberUpdate ADD ESI,SIZE#RELOC SUB ECX,SIZE#RELOC JA .60: .80:POP ESI,EDX ADD ESI,16 ; Next keyword. JMP .10: [.data] ALIGN DWORD .TempReloc DS RELOC ; Swap area for .SortByOrg. [.text] .SortByOrg:: PROC ; ShellSort callback for sorting relocations. ; Input: ESI and EDI are RELOC objects to compare by origin. ; If they are in wrong order, procedure performs their swap and returns CF. ; Also called back from PfOutput. MOV EAX,[EDI+RELOC.OrgLow] MOV EDX,[EDI+RELOC.OrgHigh] CMP EDX,[ESI+RELOC.OrgHigh] JA .OK: JB .Swap: CMP EAX,[ESI+RELOC.OrgLow] JAE .OK: .Swap:MOV EDX,MemberUpdate.TempReloc CopyTo EDX,ESI,Size=SIZE#RELOC CopyTo ESI,EDI,Size=SIZE#RELOC CopyTo EDI,EDX,Size=SIZE#RELOC STC .OK: RET ENDP .SortByOrg .90: ; %OutRelocBuffer was filled with relocations from updating keywords. ; However, not updated members of the structure may have its own relocations, ; they will be appended to %OutRelocBuffer unless a relocation already exists ; on the same origin. MOV EDI,[%SssPtr] BufferRetrieve [EDI+SSS.RelocBuffer] JECXZ .98: .92: PUSH ECX,ESI MOV EBX,ESI ; Relocation from the structure. MOV EDX,[EBX+RELOC.OrgLow] BufferRetrieve [%OutRelocBuffer] JECXZ .95: .94: CMP EDX,[ESI+RELOC.OrgLow] ; Compare with relocation from keywords. JE .96: ; Relocation with this origin was already stored in OutRelocBuffer, skip. ADD ESI,SIZE#RELOC SUB ECX,SIZE#RELOC JA .94: .95: ; None from relocations already stored in %OutRelocBuffer has the same origin EDX as EBX. BufferStore [%OutRelocBuffer],EBX,SIZE#RELOC Msg cc=C,'9314',MemberUpdate .96: POP ESI,ECX ADD ESI,SIZE#RELOC SUB ECX,SIZE#RELOC JA .92: .98: Invoke EaBufferRelease::,[%MuRelocBuffer] Invoke EaBufferRelease::,[%MuEmitBuffer] ; Contents of OutRelocBuffer must be sorted by origin. BufferRetrieve [%OutRelocBuffer] JECXZ .99: MOV EDI,SIZE#RELOC MOV EAX,ECX CDQ DIV EDI ShellSort ESI,EAX,EDI,.SortByOrg .99: EndProcedure MemberUpdate