This source PFLIB creates and imports object and import library in COFF standard.
EUROASM NOWARN=2101
pflibcof PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
INCLUDEHEAD euroasm.htm, \ Interface (structures, symbols and macros) of other modules used in this source.
ea.htm,eaopt.htm,exp.htm,msg.htm,pf.htm,pfcoff.htm,pflibomf.htm,pgm.htm, \
pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm
pflibcof HEAD ; Start module interface.
PFLIBCOF_ARCHIVE_MEMBER_HEADER STRUC .Name D 16*B ; Member name terminated with /, padded with spaces. .Date D 12*B ; Time of member creation as seconds since Jan 1st, 1970 UTC, in decimal. .UserId D 6*B ; Unix user ID in decimal, always 0. .GroupId D 6*B ; Unix group ID in decimal, always 0. .Mode D 8*B ; Unix filemode in octal, always 100666. .Size D 10*B ; Size of following library member (COFF object) in decimal. .EndHeader D 2*B ; Member header terminator 0x60,0x0A. ENDSTRUC PFLIBCOF_ARCHIVE_MEMBER_HEADER
PFLIBCOF_IMPORT_OBJECT_HEADER STRUC .Sig1 D W ; Signature 1, always 0x0000. .Sig2 D W ; Signature 2, always 0xFFFF. .Version D W ; The structure version. .Machine D W ; Type of target machine CPU value in PFCOFF_encodings. .TimeDateStamp D D ; Time stamp as seconds since Jan 1st, 1970 UTC. .SizeOfData D D ; Brutto size of two ASCIIZ strings which follow the header. .Ordinal D W ; Import ordinal number or hint for the import. .Type D W ; Imported object type in PflibcofObjectTypeEnc+PflibcofNameTypeEnc. ENDSTRUC PFLIBCOF_IMPORT_OBJECT_HEADER
pflibcofImportCode = 000_000_00b ; Imported symbol is entry of executable procedure. pflibcofImportData = 000_000_01b ; Imported symbol represents static data. pflibcofImportConst = 000_000_10b ; Imported symbol is a scalar value.
pflibcofImportOrdinal = 000_000_00b ; Symbol is imported by PFLIBCOF_IMPORT_OBJECT_HEADER.Ordinal number.
pflibcofImportName = 000_001_00b ; Internal import name is identical with the public name.
pflibcofImportNameNoprefix = 000_010_00b ; Internal import name is public name without leading ?, @, _.
pflibcofImportNameUndecorate = 000_011_00b ; As in pflibcofImportNameNoprefix and truncating at the first @.
ENDHEAD pflibcof ; End of module interface.
BasePgm.Pool and stored on BasePgm.ModulePgmList.BasePgm.ModulePgmList.
PflibcofLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
LongNames LocalVar ; Pointer to the 1st ASCIIZ longname in Longnames member.
ShortName LocalVar Size=16 ; Room for short archive member name.
MOV EDI,[%ObjBegin]
MOV ECX,[%ObjSize]
LEA EDX,[EDI+ECX] ; Pointer to the end of mapped library.
ADD EDI,8 ; Skip LIBCOF signature !<arch>.
; Linker dictionary members are not used by €ASM.
CALL .SkipHeader: ; Skip the First Linker Member.
JC .90:
CALL .SkipHeader: ; Skip the Second Linker Member.
JC .90:
CALL .SkipHeader: ; Skip the Longnames Member.
JC .90:
MOV [%LongNames],ESI
; Read and load all object and import members.
.50:CMP EDI,EDX ; Test the end of file.
JNB .90:
; EDI now points to the header of COFF object module or short COFF import.
CALL .SkipHeader: ; Skip the module header.
JC .90:
CMPD [ESI],0xFFFF_0000 ; Is it PFLIBCOF_IMPORT_OBJECT_HEADER?
JNE .60: ; If it is an ordinary COFF object starting with PFCOFF_FILE_HEADER.
; Library member ESI,EAX is a short format COFF import.
; Its name will be identical with ASCIIZ imported symbol name which follows the import object header.
Invoke PflibcofLoadImportModule,[%BasePgm],ESI,EAX,[%FileNamePtr]
JMP .50: ; The next library member.
.60:; Library member ESI,EAX is an ordinary COFF module. Its name is in archive member header in the form ShortName/ or /LongNameOffset.
LEA EBX,[ESI - SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER]
CMPB [EBX+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Name+0],'/'
JE .75:
; Module name is short, terminated with /.
SUB ECX,ECX ; Name size.
.70:CMPB [EBX+ECX],'/'
JE .80:
INC ECX
CMP CL,16
JB .70:
JMP .80: ; EBX,ECX is now the module name.
.75:; Module name is long, stored in Longnames member.
INC EBX
PUSH EAX,EDI
LodD EBX
ADD EAX,[%LongNames]
MOV EBX,EAX
GetLength$ EBX ; EBX,ECX is now the long module name.
POP EDI,EAX
.80:Invoke PfcoffLoadModule::,[%BasePgm],ESI,EAX,[%FileNamePtr],EBX,ECX,pgmoptLIBCOF
JMP .50: ; The next library member.
.SkipHeader:PROC ; Subprocedure to check the library member header.
; Input: EDI=^PFLIBCOF_ARCHIVE_MEMBER_HEADER, should be word aligned. EDX=^End of mapped file.
; Output:CF=0,EAX=module size, ESI=^module body, EDI=^PFLIBCOF_ARCHIVE_MEMBER_HEADER of the next member, word aligned.
; Error: CF=1, E7768 reported.
TEST EDI,1
JZ .L2:
INC EDI
.L2: LEA ESI,[EDI+SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER]
CMP ESI,EDX
JB .L5:
.E7768:SUB ESI,[%ObjBegin]
Msg '7768',[%FileNamePtr],ESI ; Invalid format of COFF library "!1$"[!2Hh].
STC
RET
.L5:LEA ESI,[EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Size]
LodD ESI ; Load decimal COFF module size to EAX.
LEA ESI,[EDI+SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER]
JC .E7768: ; Invalid format of COFF library "!1$"[!2Hh].
LEA EDI,[ESI+EAX]
RET
ENDP .SkipHeader:
.90:EndProcedure PflibcofLoadPgm
.Date, .UserId, .GroupId, .Mode. Rest of the Header is filled with spaces.
PflibcofInitHeader Procedure HeaderPtr, ModulePgm
MOV EDI,[%HeaderPtr]
MOV EBX,[%ModulePgm]
Clear EDI,Size=SIZE#PFLIBCOF_ARCHIVE_MEMBER_HEADER,Filler=0x20
MOVB [EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.UserId],'0'
MOVB [EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.GroupId],'0'
MOVD [EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Mode],'1006'
MOVW [EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Mode+4],'66'
MOVW [EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.EndHeader],0x0A60
MOV EAX,[Ea.Eaopt.TimeStamp::]
LEA EDI,[EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Date]
StoD Signed=no
EndProcedure PflibcofInitHeader
.Sig1, .Sig2, .Version, .Machine, TimeDateStamp.
PflibcofInitImport Procedure HeaderPtr, ModulePgm
MOV EDI,[%HeaderPtr]
MOV EBX,[%ModulePgm]
Clear EDI,Size=SIZE#PFLIBCOF_IMPORT_OBJECT_HEADER,Filler=0
MOVW [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Sig1],0
MOVW [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Sig2],-1
MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Machine],pfcoffFILE_MACHINE_I386
JNSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64, .50:
MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Machine],pfcoffFILE_MACHINE_AMD64
.50:MOV EAX,[EBX+PGM.Pgmopt.MajorLinkerVersion]
MOV EDX,[Ea.Eaopt.TimeStamp::]
MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Version],AX
MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.TimeDateStamp],EDX
EndProcedure PflibcofInitImport
PflibcofLoadImportModule reads the contents of one import library member in short COFF format
and converts it to a fresh new program, which then will be stored on
BasePgm.ModulePgmList. The program contains no segments and just one import symbol.
BasePgm.ModulePgmList as a new
PGM structure.
PflibcofLoadImportModule Procedure BasePgm, ImpBegin, ImpSize, FileNamePtr
ImpEndPtr LocalVar ; Pointer to end of import module.
SymbolDllNameSize LocalVar
SymbolDllNamePtr LocalVar
SymbolInterNamePtr LocalVar
SymbolInterNameSize LocalVar
SymbolNamePtr LocalVar
SymbolNameSize LocalVar
SymbolStatus LocalVar
SymbolOrdinal LocalVar
MOV ESI,[%ImpBegin]
MOV ECX,[%ImpSize]
ADD ECX,ESI
MOV [%ImpEndPtr],ECX
LEA EAX,[ESI+SIZE# PFLIBCOF_IMPORT_OBJECT_HEADER] ; EAX is now pointer to symbol name.
GetLength$ EAX ; ECX is now symbol name size.
MOV [%SymbolNamePtr],EAX
MOV [%SymbolNameSize],ECX
MOV [%SymbolInterNamePtr],EAX
MOV [%SymbolInterNameSize],ECX
LEA EDX,[EAX+ECX+1] ; EDX is now pointer to DLL name.
GetLength$ EDX
MOV [%SymbolDllNamePtr],EDX
MOV [%SymbolDllNameSize],ECX
LEA EAX,[EDX+ECX+1]
CMP EAX,[%ImpEndPtr]
LEA EAX,[%SymbolNamePtr] ; Prepare Msg parameter !1S.
Msg cc=A,'6952',EAX,[%FileNamePtr] ; Wrong import !1S in library "!2$".
MOVZXW EAX,[ESI+PFLIBCOF_IMPORT_OBJECT_HEADER.Ordinal]
MOV [%SymbolOrdinal],EAX
MOVZXW EAX,[ESI+PFLIBCOF_IMPORT_OBJECT_HEADER.Type]
MOV EDX,symImport+'N'
JSt EAX,pflibcofImportConst,.10:
MOV DL,'A'
.10:JSt EAX,pflibcofImportName|pflibcofImportNameNoprefix|pflibcofImportNameUndecorate,.20:
SetSt EDX,symImportedByOrd
.20:MOV [%SymbolStatus],EDX
SHR EAX,3 ; Shift out 2 bits of object type and the LSbit of name type.
JZ .50: ; If pflibcofImportName (leave symbol Name identical with InterName).
PUSHFD ; CF=0 if pflibcofImportNameNoprefix, CF=1 if pflibcofImportNameUndecorate.
; Noprefix. Remove the leading ?, @, _.
MOV ESI,[%SymbolInterNamePtr]
MOV ECX,[%SymbolInterNameSize]
LEA EDX,[ESI+ECX]
.25: CMP ESI,EDX
JNB .30:
LODSB
DEC ECX
CMP AL,'@'
JE .25:
CMP AL,'?'
JE .25:
CMP AL,'_'
JE .25:
DEC ESI
INC ECX
.30: MOV [%SymbolInterNamePtr],ESI
MOV [%SymbolInterNameSize],ECX
POPFD
JNC .50:
; Undecorate. Truncate at the first @ after having removed the leading ?, @, _.
MOV ESI,[%SymbolInterNamePtr]
MOV ECX,[%SymbolInterNameSize]
LEA EDX,[ESI+ECX]
.35:CMP ESI,EDX
JNB .40:
LODSB
CMP AL,'@'
JNE .35:
DEC ESI
.40:SUB ESI,[%SymbolInterNamePtr]
MOV [%SymbolInterNameSize],ESI
.50:Invoke PgmCreateImportModule::,[%BasePgm],[%SymbolDllNamePtr], [%SymbolDllNameSize],[%SymbolOrdinal], \
[%SymbolStatus],[%SymbolNamePtr], [%SymbolNameSize],[%SymbolInterNamePtr], [%SymbolInterNameSize]
EndProcedure PflibcofLoadImportModule
PFLIBCOF_ARCHIVE_HEADER.Name
as decimal number prefixed with slash /.
PflibcofStoreObjectModule Procedure ModuleStream, TemporaryStream, ModulePgm, \
SymbolBuffer, LongnameBuffer, ModuleIndex
ModHeader LocalVar Size=SIZE#PFLIBCOF_ARCHIVE_MEMBER_HEADER
LibSymbol LocalVar Size=SIZE#PFLIBOMF_SYMBOL
MOV EDX,[%ModuleIndex]
MOV [%ReturnEDX],EDX ; Prepare for the case of empty ModulePgm.
MOV EBX,[%ModulePgm]
SetSt [EBX+PGM.Status],pgmSelected ; Store object module ebx only if there's at least one public/export symbol.
.24:ListGetFirst [EBX+PGM.SymList]
JZ .90:
.25:JSt [EAX+SYM.Status],symPublic|symExport,.35:
.30:ListGetNext EAX
JNZ .25:
RstSt [EBX+PGM.Status],pgmSelected
JMP .90: ; Skip if there is nothing to publish/export.
.35:; Store object module EBX to ModuleStream.
LEA EDI,[%ModHeader]
Invoke PflibcofInitHeader,EDI,EBX
LEA EDI,[EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Name]
MOV ECX,[EBX+PGM.NameSize] ; Use PGM.Name as archive member name.
CMP ECX,16
JB .40: ; If module name is short.
PUSH ECX
BufferRetrieve [%LongnameBuffer]
MOV EAX,ECX ; Offset in LongnameBuffer.
POP ECX
MOV ESI,[EBX+PGM.NamePtr] ; ESI,ECX is long module name.
BufferStore [%LongnameBuffer],ESI,ECX
BufferStoreByte [%LongnameBuffer],0 ; Terminating zero.
MOVB [EDI],'/' ; Long name in ModHeader looks like "/123" where 123 is offset in LongnameBuffer.
INC EDI
StoD EDI ; Store offset of the module name in LongnameBuffer as a decadic number.
JMP .50:
.40:MOV ESI,[EBX+PGM.NamePtr] ; ESI,ECX is short module name.
REP MOVSB ; Store the short name to archive member header directly.
MOV AL,'/' ; Short name in ModHeader looks like "ShortName/".
STOSB
.50:LEA EDI,[%LibSymbol]
StreamGetSize [%ModuleStream] ; Size of all previously streamed hdr+modules (without 3 linker members).
TEST AL,1
JZ .60:
INC EAX
PUSH EAX
StreamStoreByte [%ModuleStream],0x10 ; Align each library member to WORD.
POP EAX
.60:MOV [EDI+PFLIBOMF_SYMBOL.ModPtr],EAX
MOV EDX,[%ReturnEDX]
INC EDX ; ModuleIndex.
MOV [%ReturnEDX],EDX
MOV [EDI+PFLIBOMF_SYMBOL.ModIndex],EDX
StreamClear [%TemporaryStream]
; Create module body, starting with PFCOFF_FILE_HEADER.
Invoke PfcoffCompile::,[%TemporaryStream],EBX
StreamGetSize [%TemporaryStream]
LEA ESI,[%ModHeader]
LEA EDI,[ESI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Size]
StoD EDI ; Member header ESI is now complete.
StreamStore [%ModuleStream],ESI,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER
StreamDump [%TemporaryStream], .Restream: ; Copy TemporaryStream to ModuleStream.
.Restream:PROC1 ; Callback of StreamDump.
StreamStore [%ModuleStream],ESI,ECX
RET
ENDPROC1 .Restream:
LEA EDI,[%LibSymbol]
; Now store PFLIBOMF_SYMBOL records for each published symbol, with identical ModPtr and ModIndex.
ListGetFirst [EBX+PGM.SymList]
.70:JNSt [EAX+SYM.Status],symPublic|symExport|symSe,.80:
MOV ESI,[EAX+SYM.NamePtr]
MOV ECX,[EAX+SYM.NameSize]
MOV [EDI+PFLIBOMF_SYMBOL.NamePtr],ESI
MOV [EDI+PFLIBOMF_SYMBOL.NameSize],ECX
BufferStore [%SymbolBuffer],EDI,SIZE# PFLIBOMF_SYMBOL
.80:ListGetNext EAX
JNZ .70:
.90:EndProcedure PflibcofStoreObjectModule
PFLIBCOF_ARCHIVE_HEADER.Name
as decimal number prefixed with slash /.
PflibcofStoreImportModule Procedure ModStream, ImportSymbol, BasePgm, \
SymbolBuf, LongnameBuf, ModIndex
ModHeader LocalVar Size=SIZE#PFLIBCOF_ARCHIVE_MEMBER_HEADER
ImportHeader LocalVar Size=SIZE#PFLIBCOF_IMPORT_OBJECT_HEADER
LibSymbol LocalVar Size=SIZE#PFLIBOMF_SYMBOL
MOV EDX,[%ImportSymbol]
LEA EDI,[%ModHeader] ; Create archive member header.
Invoke PflibcofInitHeader,EDI,[%BasePgm]
LEA EDI,[EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Name]
MOV ECX,[EDX+SYM.NameSize] ; Use symbol name as archive member name.
CMP ECX,16
JB .S4: ; If symbol name is short.
PUSH ECX
BufferRetrieve [%LongnameBuf]
MOV EAX,ECX ; Offset in LongnameBuf.
POP ECX
MOV ESI,[EDX+SYM.NamePtr]
BufferStore [%LongnameBuf],ESI,ECX
BufferStoreByte [%LongnameBuf],0 ; Terminating zero.
MOVB [EDI],'/' ; Long name in ModHeader looks like "/123" where 123 is offset in LongnameBuf.
INC EDI
StoD EDI ; Store offset of the module name in LongnameBuf as a decadic number.
JMP .S5:
.S4:MOV ESI,[EDX+SYM.NamePtr] ; ESI,ECX is short module/symbol name.
REP MOVSB ; Store the short name to archive member header directly.
MOV AL,'/' ; Short name in ModHeader looks like "ShortName/".
STOSB
.S5:LEA EDI,[%LibSymbol] ; Create record for the future library symbol.
StreamGetSize [%ModStream] ; Size of all previously streamed hdr+modules (without 3 linker members).
TEST AL,1
JZ .S6:
INC EAX
PUSH EAX
StreamStoreByte [%ModStream],0x10 ; Align each library member to WORD.
POP EAX
.S6:MOV [EDI+PFLIBOMF_SYMBOL.ModPtr],EAX
MOV EAX,[%ReturnEDX]
INC EAX ; ModIndex.
MOV [%ReturnEDX],EAX
MOV [EDI+PFLIBOMF_SYMBOL.ModIndex],EAX
MOV ESI,[EDX+SYM.NamePtr]
MOV ECX,[EDX+SYM.NameSize]
MOV [EDI+PFLIBOMF_SYMBOL.NamePtr],ESI
MOV [EDI+PFLIBOMF_SYMBOL.NameSize],ECX
BufferStore [%SymbolBuf],EDI,SIZE# PFLIBOMF_SYMBOL
LEA EDI,[%ModHeader]
MOV EAX,[EDX+SYM.DllNameSize]
TEST EAX
JNZ .S7:
MOV AL,%EuroasmDefaultDllNameSize
MOV [EDX+SYM.DllNameSize],EAX
MOVD [EDX+SYM.DllNamePtr],=B"%EuroasmDefaultDllName"
.S7:LEA EAX,[SIZE#PFLIBCOF_IMPORT_OBJECT_HEADER+ECX+1+EAX+1] ; ECX is symbol name size.
MOV ESI,EDI
LEA EDI,[EDI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Size]
StoD EDI
; Archive member header is complete now.
StreamStore [%ModStream],ESI,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER
LEA EDI,[%ImportHeader] ; Create and store import header of import symbol EDX.
Invoke PflibcofInitImport,EDI,[%BasePgm]
MOV EAX,[EDX+SYM.NameSize]
INC EAX ; Terminating zero.
ADD EAX,[EDX+SYM.DllNameSize]
INC EAX ; Terminating zero.
MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.SizeOfData],EAX
MOV EAX,[EDX+SYM.OrdinalNr]
MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Ordinal],AX
MOV AX,pflibcofImportOrdinal
JSt [EDX+SYM.Status],symImportedByOrd,.S8:
MOV AX,pflibcofImportName
.S8:MOV ECX,[EDX+SYM.Section]
TEST ECX
JNZ .S9:
OR AX,pflibcofImportConst
.S9:MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Type],AX
; Store compiled library member to ModStream.
StreamStore [%ModStream],EDI,SIZE# PFLIBCOF_IMPORT_OBJECT_HEADER
StreamStore [%ModStream],[EDX+SYM.NamePtr],[EDX+SYM.NameSize]
StreamStoreByte [%ModStream],0
StreamStore [%ModStream],[EDX+SYM.DllNamePtr],[EDX+SYM.DllNameSize]
StreamStoreByte [%ModStream],0
.90:EndProcedure PflibcofStoreImportModule
Pgm.ModulePgmList.
PflibcofCompile Procedure OutputStream, Pgm
ModStream LocalVar ; ^Stream for linked module headers+members (but not 3 linker members).
TempStream LocalVar ; ^Stream for one COFF module, used in PflibcofStoreObjectModule.
SymbolBuf LocalVar ; ^Buffer for PFLIBOMF_SYMBOL records.
StringBuf LocalVar ; ^Buffer for ASCIIZ strings with public names.
LongnameBuf LocalVar ; ^Buffer for 3rd linker member with module names longer than 15.
LinkerOffsBuf LocalVar ; ^Buffer for linker member DWORD offsets. The 1st one is NrOfOffsets.
LinkerIndBuf LocalVar ; ^Buffer for linker member WORD ordinals. The 1st DWORD is NrOfOrdinals.
Linker1stBuf LocalVar ; ^Buffer for the first linker member, including its header.
Linker2ndBuf LocalVar ; ^Buffer for the second linker member, including its header.
Linker3rdBuf LocalVar ; ^Buffer for the third linker member (longnames), including its header.
ModIndex LocalVar ; Number of modules stored in the library.
Header LocalVar Size=SIZE#PFLIBCOF_ARCHIVE_MEMBER_HEADER
; Initialize local variables.
MOV EBX,[%Pgm]
StreamCreate [EBX+PGM.Pool]
MOV [%ModStream],EAX
StreamCreate [EBX+PGM.Pool]
MOV [%TempStream],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%SymbolBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%StringBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%LongnameBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%LinkerOffsBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%LinkerIndBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%Linker1stBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%Linker2ndBuf],EAX
Invoke EaBufferReserve::,PflibcofCompile
MOV [%Linker3rdBuf],EAX
SUB EDX,EDX
MOV [%ModIndex],EDX
; Store short import module for each imported symbol from the base program EBX to ModStream.
ListGetFirst [EBX+PGM.SymList]
JZ .09:
.02:JNSt [EAX+SYM.Status],symImport,.08:
Invoke PflibcofStoreImportModule,[%ModStream],EAX,EBX,[%SymbolBuf],[%LongnameBuf],EDX
MOV [%ModIndex],EDX
.08:ListGetNext EAX ; The next import symbol.
JNZ .02:
.09:; Store object module from the base program EBX to ModStream.
Invoke PflibcofStoreObjectModule::,[%ModStream],[%TempStream],EBX,[%SymbolBuf],[%LongnameBuf],EDX
MOV [%ModIndex],EDX
; Enumerate loaded programs loaded to ModulePgmList of base program EBX.
ListGetFirst [EBX+PGM.ModulePgmList]
JZ .20:
.10:MOV EBX,EAX
; Store short import module for each imported symbol from the loaded program EBX to ModStream.
ListGetFirst [EBX+PGM.SymList]
JZ .14:
.11:JNSt [EAX+SYM.Status],symImport,.13:
Invoke PflibcofStoreImportModule,[%ModStream],EAX,EBX,[%SymbolBuf],[%LongnameBuf],EDX
MOV [%ModIndex],EDX
.13:ListGetNext EAX ; The next import symbol.
JNZ .11:
.14:; Store object module from the loaded program EBX to ModStream.
MOVB [EBX+PGM.Pgmopt.Status],pgmoptLIBCOF ; Prevent creating [.drectve] in library module.
Invoke PflibcofStoreObjectModule::,[%ModStream],[%TempStream],EBX,[%SymbolBuf],[%LongnameBuf],EDX
MOV [%ModIndex],EDX
ListGetNext EBX ; The next loaded module (program).
JNZ .10:
; All library modules are now stored in ModStream. SymbolBuf identifies published and imported symbols in the library.
.20:; Compile First Linker Member to Linker1stBuf.
BufferRetrieve [%SymbolBuf]
LEA EDX,[ESI+ECX] ; End of PFLIBOMF_SYMBOL records, sorted by module offsets.
BufferStoreDword [%LinkerOffsBuf],0 ; Number of symbols will be patched and BSWAPed later.
.30:CMP ESI,EDX
JNB .40: ; If no more symbols.
MOV EAX,[ESI+PFLIBOMF_SYMBOL.ModPtr] ; Order of elements in LinkerOffsBuf and StringBuf is synchronized.
BufferStoreDword [%LinkerOffsBuf],EAX ; To be elevated by the size of 3 linker members and BSWAPed later.
BufferStore [%StringBuf],[ESI+PFLIBOMF_SYMBOL.NamePtr],[ESI+PFLIBOMF_SYMBOL.NameSize]
BufferStoreByte [%StringBuf],0 ; Terminating zero.
ADD ESI,SIZE#PFLIBOMF_SYMBOL
JMP .30:
.40:BufferRetrieve [%LinkerOffsBuf] ; Calculate First Linker Member size to EAX.
MOV EAX,ECX
SHR ECX,2
DEC ECX
MOV [ESI],ECX ; Patch the number of symbols in First Linker Member.
BufferRetrieve [%StringBuf]
TEST CL,1 ; Alignment test.
JZ .45:
BufferStoreByte [%StringBuf],0x0A ; Linker members should be word aligned with LF.
INC ECX
.45:ADD EAX,ECX ; EAX is now the total size of First Linker Member without header.
LEA ESI,[%Header]
Invoke PflibcofInitHeader,ESI,EBX
MOVB [ESI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Name],'/'
LEA EDI,[ESI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Size]
StoD EDI ; Store member body size EAX as decimal digits.
BufferStore [%Linker1stBuf],ESI,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER
BufferRetrieve [%LinkerOffsBuf]
BufferStore [%Linker1stBuf],ESI,ECX
BufferRetrieve [%StringBuf]
BufferStore [%Linker1stBuf],ESI,ECX
; Compile Second Linker Member to Linker2ndBuf.
BufferClear [%LinkerOffsBuf] ; Reuse buffers used for the First Linker Member.
BufferClear [%StringBuf]
BufferRetrieve [%SymbolBuf]
LEA EDX,[ESI+ECX] ; End of PFLIBOMF_SYMBOL records, sorted by module index.
SUB EDI,EDI ; EDI will remember stored module index.
BufferStoreDword [%LinkerOffsBuf],EDI ; Number of members will be updated later.
BufferStoreDword [%LinkerIndBuf], EDI ; Number of symbols will be patched later.
.46:CMP ESI,EDX
JNB .49: ; If no more symbols.
CMP EDI,[ESI+PFLIBOMF_SYMBOL.ModIndex]
JE .48: ; Skip if module with index EDI already is in LinkerOffsBuf.
MOV EDI,[ESI+PFLIBOMF_SYMBOL.ModIndex]
MOV EAX,[ESI+PFLIBOMF_SYMBOL.ModPtr]
BufferStoreDword [%LinkerOffsBuf],EAX
.48:ADD ESI,SIZE#PFLIBOMF_SYMBOL
JMP .46:
.49:BufferRetrieve [%SymbolBuf]
MOV EAX,ECX ; Size of SymbolBuf.
MOV EDI,SIZE# PFLIBOMF_SYMBOL
SUB EDX,EDX
DIV EDI ; Get number of records in SymbolBuf to EAX.
ShellSort ESI,EAX,EDI,.BySymbolName: ; Sort by symbol names alphabetically.
BufferRetrieve [%SymbolBuf] ; Reread the sorted symbol buffer.
LEA EDX,[ESI+ECX] ; End of PFLIBOMF_SYMBOL records, sorted alphabetically.
.50:CMP ESI,EDX
JNB .60: ; If no more symbols.
MOV EAX,[ESI+PFLIBOMF_SYMBOL.ModIndex]
BufferStoreWord [%LinkerIndBuf],EAX ; Index buffer and string buffer are kept synchronized.
BufferStore [%StringBuf],[ESI+PFLIBOMF_SYMBOL.NamePtr],[ESI+PFLIBOMF_SYMBOL.NameSize]
BufferStoreByte [%StringBuf],0 ; Terminating zero.
ADD ESI,SIZE#PFLIBOMF_SYMBOL
JMP .50: ; The next symbol.
.60:BufferRetrieve [%LinkerOffsBuf] ; Calculate Second Linker Member size to EAX.
MOV EAX,ECX
SHR ECX,2
DEC ECX
MOV [ESI],ECX ; Patch the number of member offsets in Second Linker Member.
BufferRetrieve [%LinkerIndBuf]
ADD EAX,ECX
SHR ECX,1
DEC ECX
DEC ECX
MOV [ESI],ECX ; Patch the number of symbol indexes in Second Linker Member.
BufferRetrieve [%StringBuf]
TEST CL,1
JZ .63:
BufferStoreByte [%StringBuf],0x0A ; Word alignment of linker member.
INC ECX
.63:ADD EAX,ECX ; EAX is now the total size of Second Linker Member without header.
LEA ESI,[%Header] ; Prepare Second Linker Member header.
Invoke PflibcofInitHeader,ESI,EBX
MOVB [ESI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Name],'/'
LEA EDI,[ESI+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Size]
StoD EDI ; Store member body size EAX as decimal digits.
BufferStore [%Linker2ndBuf],ESI,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER
BufferRetrieve [%LinkerOffsBuf]
BufferStore [%Linker2ndBuf],ESI,ECX
BufferRetrieve [%LinkerIndBuf]
BufferStore [%Linker2ndBuf],ESI,ECX
BufferRetrieve [%StringBuf]
BufferStore [%Linker2ndBuf],ESI,ECX
; Compile Third Linker Member (Longnames) to Linker3rdBuf.
LEA EDX,[%Header]
Invoke PflibcofInitHeader,EDX,EBX
MOVW [EDX+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Name],'//'
LEA EDI,[EDX+PFLIBCOF_ARCHIVE_MEMBER_HEADER.Size]
BufferRetrieve [%LongnameBuf]
TEST ECX
JNZ .65:
BufferStoreByte [%LongnameBuf],0
INC ECX
.65:TEST CL,1
JZ .67:
BufferStoreByte [%LongnameBuf],0x0A
.67:BufferRetrieve [%LongnameBuf]
MOV EAX,ECX
StoD EDI
BufferStore [%Linker3rdBuf],EDX,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER
BufferStore [%Linker3rdBuf],ESI,EAX
BufferRetrieve [%Linker1stBuf] ; Three linker members are now stored in buffers. Get their total size.
LEA EAX,[8+ECX] ; Signature + First Linker Member size.
BufferRetrieve [%Linker2ndBuf]
ADD EAX,ECX ; + Second Linker Member Size.
BufferRetrieve [%Linker3rdBuf]
LEA EDX,[EAX+ECX] ; EDX is now total word-aligned size of signature plus three linker members.
BufferRetrieve [%Linker1stBuf] ; It will be used to elevate offsets in the First and Second Linker Member.
ADD ESI,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER ; Skip the header.
LODSD ; Number of symbols.
MOV ECX,EAX
BSWAP EAX ; Number of symbols in the First linker member is big-endian.
MOV [ESI-4],EAX
JECXZ .80:
.70:LODSD
ADD EAX,EDX ; Elevate file offset.
BSWAP EAX ; File offsets in the First Linker Member are big-endian.
MOV [ESI-4],EAX
LOOP .70:
.80:BufferRetrieve [%Linker2ndBuf]
ADD ESI,SIZE# PFLIBCOF_ARCHIVE_MEMBER_HEADER ; Skip the header.
LODSD ; Number of members.
MOV ECX,EAX
JECXZ .85:
.83:LODSD
ADD EAX,EDX ; Elevate file offset.
MOV [ESI-4],EAX
LOOP .83:
.85:; Compile LIBCOF file to OutputStream.
MOV EDI,[%OutputStream]
; Store LIBCOF signature.
StreamStoreDword EDI,0x72613C21 ; '!<ar'
StreamStoreDword EDI,0x0A3E6863 ; 'ch>\n'
; Store three Linker Members.
BufferRetrieve [%Linker1stBuf]
StreamStore EDI,ESI,ECX
BufferRetrieve [%Linker2ndBuf]
StreamStore EDI,ESI,ECX
BufferRetrieve [%Linker3rdBuf]
StreamStore EDI,ESI,ECX
; Store all COFF modules copying from ModStream.
StreamDump [%ModStream],.Restream:
PflibcofCompile.Restream:PROC1 ; Callback of StreamDump.
StreamStore [%OutputStream],ESI,ECX
RET
ENDPROC1 PflibcofCompile.Restream:
PflibcofCompile.BySymbolName:PROC1 ; Callback to compare symbol names.
; ESI and EDI points to two PFOMFLIB_SYMBOL records, whose .Name are being compared.
XCHG ESI,EDI ; Ascending order.
PUSH ECX ; This register must be preserved in callback.
MOV ECX,[ESI+PFLIBOMF_SYMBOL.NameSize]
MOV EDX,[EDI+PFLIBOMF_SYMBOL.NameSize]
CMP ECX,EDX
JBE .B2:
MOV ECX,EDX
.B2: JECXZ .B9: ; ECX is now the size of shorter name.
PUSH ESI,EDI
MOV ESI,[ESI+PFLIBOMF_SYMBOL.NamePtr]
MOV EDI,[EDI+PFLIBOMF_SYMBOL.NamePtr]
REPE CMPSB
POP EDI,ESI
JA .B9: ; Orded of records is OK. Return with CF=0.
JB .B5:
; When names match but have different sizes, the longer one goes latter.
MOV ECX,[ESI+PFLIBOMF_SYMBOL.NameSize]
CMP ECX,[EDI+PFLIBOMF_SYMBOL.NameSize]
JAE .B9: ; Orded of reocrd is OK. return with CF=0.
.B5: ; Swap is required.
%i %SETA SIZE# PFLIBOMF_SYMBOL / 4 ; Number of DWORDs in the record (four).
%WHILE %i
LODSD
MOV EDX,[EDI]
STOSD
MOV [ESI-4],EDX
%i %SETA %i-1
%ENDWHILE ; Perform the dword swap four times.
STC ; CF=1 signalizes that swap took place.
.B9:POP ECX
RET
ENDP1 PflibcofCompile.BySymbolName:
; Free all temporary buffers.
Invoke EaBufferRelease::,[%Linker3rdBuf]
Invoke EaBufferRelease::,[%Linker2ndBuf]
Invoke EaBufferRelease::,[%Linker1stBuf]
Invoke EaBufferRelease::,[%LinkerIndBuf]
Invoke EaBufferRelease::,[%LinkerOffsBuf]
Invoke EaBufferRelease::,[%LongnameBuf]
Invoke EaBufferRelease::,[%StringBuf]
Invoke EaBufferRelease::,[%SymbolBuf]
EndProcedure PflibcofCompile
ENDPROGRAM pflibcof