Class MEMBER describers a named structure member.
When a STRUC is defined, each its D* statement
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 DS).
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
Sss.EmitBuffer to OutEmitBuffer
, updating matching members by keywords in Stm.KeyBuffer.
DS).
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
ENDPROGRAM member