| Index | Manual | Download | Source | Macros | Embedded word Case ins.
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.

             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
  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.
Invoked from
  PfLoad
Invokes
  PfcoffLoadModule PflibcofLoadImportModule

    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

↑ 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

    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 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]
        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

↑ 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 an 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,%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

↑ PflibcofCompile OutputStream, Pgm
  PflibcofCompile is constructor of object/import library in linkable/importable format PECOFF as specified in [MS_PECOFF].
  The base Pgm plus each module loaded on Pgm.ModulePgmList will create one member in the output library.
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
  t9050

    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

▲Back to the top▲