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. INCLUDEHEAD \ ; Include headers of another modules used in this module. 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, \ syswin.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 formShortName/
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