EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

pflibcof.htm
Classes
PFLIBCOF_ARCHIVE_MEMBER_HEADER
PFLIBCOF_IMPORT_OBJECT_HEADER
Encodings
PflibcofObjectTypeEnc
PflibcofNameTypeEnc
Procedures
PflibcofCompile
PflibcofInitHeader
PflibcofInitImport
PflibcofLoadImportModule
PflibcofLoadPgm
PflibcofStoreImportModule
PflibcofStoreObjectModule

This source PFLIB creates and imports object and import library in COFF standard.


pflibcof PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
 pflibcof HEAD ; Start module interface.
↑ PFLIBCOF_ARCHIVE_MEMBER_HEADER
Structure which describes object header in COFF library.
All structure members are in decimal human-readable characters, left aligned, padded with spaces (0x20).
Archive member headers in COFLIB file are word-aligned. Header is immediately followed with the actual COFF object.
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
Structure which describes imported symbol header in COFF short import library.
The import object header is followed with two ASCIIZ strings:
  1. imported symbol name
  2. dynamic link library (DLL) name from which it is imported.
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
↑ PflibcofObjectTypeEnc
Encoding of PFLIBCOF_IMPORT_OBJECT_HEADER.Type.
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.
↑ PflibcofNameTypeEnc
Encoding of PFLIBCOF_IMPORT_OBJECT_HEADER.NameType.
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.
↑ PflibcofLoadPgm BasePgm, ObjBegin, ObjSize, FileNamePtr
PflibcofLoadPgm reads the contents of COFF library and converts each module to a fresh new program (PGM), which will be allocated on BasePgm.Pool and stored on BasePgm.ModulePgmList.
Input
BasePgm is pointer to an existing PGM to which the library will be linked.
ObjBegin is pointer to the contents of library file mapped in memory by the caller.
ObjSize is number of bytes in the file.
FileNamePtr is pointer to zero-terminated file name (used in error reports).
Output
Imported modules in the form of PGM are stored on BasePgm.ModulePgmList.
Error
Errors are reported with macro Msg.
Invokes
PfcoffLoadModule PflibcofLoadImportModule
Tested by
t7022 t7049 t7112 t7139 t7202 t7229 t7253 t7316 t7343 t7367 t7430 t7469 t7484 t7511 t7541 t7577 t7607
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>.
.SkipHeader:PROC1 ; 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:
             LEA EDI,[ESI+EAX]
             RET
            ENDP1 .SkipHeader:
    ; 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 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.
.90:EndProcedure PflibcofLoadPgm
↑ PflibcofInitHeader HeaderPtr, ModulePgm
PflibcofInitHeader initializes Header members .Date, .UserId, .GroupId, .Mode. Rest of the Header is filled with spaces.
Input
HeaderPtr is pointer to PFLIBCOF_ARCHIVE_MEMBER_HEADER , allocated by caller.
ModulePgm is pointer to PGM from which will be the archive member created.
Output
Header is initialized.
Error
-
Invoked by
PflibcofCompile PflibcofStoreImportModule PflibcofStoreObjectModule
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
↑ PflibcofInitImport HeaderPtr, ModulePgm
PflibcofInitImport clears and initializes import header members .Sig1, .Sig2, .Version, .Machine, TimeDateStamp.
Input
HeaderPtr is pointer to PFLIBCOF_IMPORT_OBJECT_HEADER , allocated by caller.
ModulePgm is pointer to PGM from which will be the import created.
Output
Import header is initialized.
Error
-
Invoked by
PflibcofStoreImportModule
Invokes
PgmGetCoffMachine
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
     Invoke PgmGetCoffMachine::,EBX
     MOV [EDI+PFLIBCOF_IMPORT_OBJECT_HEADER.Machine],AX
     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 BasePgm, ImpBegin, ImpSize, FileNamePtr

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.

Input
BasePgm is pointer to an existing PGM to which the member is being loaded.
ImpBegin is pointer to the short import library member in PFLIBCOF_IMPORT_OBJECT_HEADER form, immediately followed with two ASCIIZ strings with symbol name and DLL name.
ImpSize is the size of import object header plus brutto size of both ASCIIZ strings.
FileNamePtr is pointer to zero-terminated file name (used in error reports).
Output
Loaded program is stored on BasePgm.ModulePgmList as a new PGM structure.
Error
Error E7766 reported with macro Msg.
Invoked by
PflibcofLoadPgm
Invokes
PgmCreateImportModule
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
↑ PflibcofStoreObjectModule ModuleStream, TemporaryStream, ModulePgm, SymbolBuffer, LongnameBuffer, ModuleIndex
PflibcofStoreObjectModule creates library module in COFF format from ModulePgm, and writes archive member header plus completed COFF-formated object to ModuleStream.
Header and object are incorporated into library only if it exports or publishes at least one symbol.
Offset and ModuleIndex of each module in ModuleStream are then stored to SymbolBuffer for each published or exported symbol found in the module.
All streams and buffers must be allocated by the caller.
Input
ModuleStream is pointer to a STREAM where the archive header and COFF object module will be written.
TemporaryStream is pointer to a reusable STREAM where the COFF object module (file header, section headers, raw data, symbol table, string table) will be constructed by PfcoffCompile . Its contents will be restreamed later to ModuleStream together with library member header.
ModulePgm is pointer to an input PGM from which the archive member is being created.
SymbolBuffer is pointer to an output BUFFER where a PFLIBOMF_SYMBOL record will be written for each public and exported symbol.
LongnameBuffer is pointer to an output BUFFER where library member ASCIIZ name is stored when its size exceeds 15 characters. Offset within this buffer is then stored to PFLIBCOF_ARCHIVE_HEADER.Name as decimal number prefixed with slash /.
ModuleIndex is number of modules previously stored in ModuleStream. PflibcofStoreObjectModule will increment the number for each archive member stored in ModuleStream.
When there's no import/export/public symbol in ModulePgm, returned EDX=ModuleIndex.
Output
EDX= is equal to ModuleIndex incremented for each stored library module.
SymbolBuffer is updated with import, export and public symbols which were stored to ModuleStream.
Error
-
See also
PflibcofStoreImportModule
Invoked by
PflibcofCompile
Invokes
PfcoffCompile PflibcofInitHeader
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]
   ; Store object module only if there's at least one public/export symbol.
    SetSt [EBX+PGM.Status],pgmSelected
.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
    ; Copy TemporaryStream to ModuleStream.
    StreamDump [%TemporaryStream], .Restream:
.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,.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
↑ PflibcofStoreImportModule ModStream, ImportSymbol, BasePgm, SymbolBuf, LongnameBuf, ModIndex
PflibcofStoreImportModule creates import library module in short COFF format from ImportSymbol, and stores archive member header + short COFF format to ModuleStream.
All streams and buffers must be allocated by the caller.
Input
ModStream is pointer to a STREAM where the archive header and COFF import module will be written.
ImportSymbol is pointer to and import SYM from which the archive member is being created.
BasePgm is pointer to PGM (compiled COFF library).
SymbolBuf is pointer to an output BUFFER where a PFLIBOMF_SYMBOL record will be written for the imported symbol.
LongnameBuf is pointer to an output BUFFER where library member ASCIIZ name is stored when its size exceeds 15 characters. Offset within this buffer is then stored to PFLIBCOF_ARCHIVE_HEADER.Name as decimal number prefixed with slash /.
ModIndex is number of modules previously stored in ModStream.
Output
EDX= is equal to ModIndex incremented by one.
SymbolBuffer is updated with import symbol which was stored to ModStream.
Error
-
See also
PflibcofStoreObjectModule
Invoked by
PflibcofCompile
Invokes
PflibcofInitHeader PflibcofInitImport
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,%EaDefaultDllNameSize
    MOV [EDX+SYM.DllNameSize],EAX
    MOVD [EDX+SYM.DllNamePtr],=B"%EaDefaultDllName"
.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
↑ PflibcofCompile OutputStream, Pgm
PflibcofCompile is constructor of object/import library in linkable/importable format ECOFF as specified in [MS_PECOFF].
Input
OutputStream is pointer to an empty STREAM for the output file contents.
Pgm is pointer to a base PGM representing the completely assembled program with modules loaded in Pgm.ModulePgmList.
Output
OutputStream is filled with output file contents.
Error
Errors are reported with macro Msg.
Invoked from
PfOutput
Invokes
EaBufferRelease EaBufferReserve PflibcofInitHeader PflibcofStoreImportModule PflibcofStoreObjectModule
Tested by
t7304 t7307 t7310 t7313 t7316 t7319 t7325 t7331 t7337 t7343 t7349 t7361 t7367 t7412 t7415
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:; Calculate First Linker Member size to EAX.
    BufferRetrieve [%LinkerOffsBuf]
    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.
.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 .BySymbolName:
    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:; Calculate Second Linker Member size to EAX.
    BufferRetrieve [%LinkerOffsBuf]
    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
    ; Three linker members are now stored in buffers. Get their total size.
    BufferRetrieve [%Linker1stBuf]
    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.
    ; It will be used to elevate offsets in the First and Second Linker Member.
    BufferRetrieve [%Linker1stBuf]
    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:
.Restream:PROC1 ; Callback of StreamDump.
            StreamStore [%OutputStream],ESI,ECX
            RET
          ENDPROC1 .Restream:
    ; 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

▲Back to the top▲