EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

pflibomf.htm
Class
PFLIBOMF_SYMBOL
Procedures
PflibomfCompile
PflibomfLoadPgm
PflibomfStoreModule

This source PFLIBOMF creates and loads object and import library in OMF standard.


         EUROASM NOWARN=2101
pflibomf 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,      \
pfomf.htm,    \
pgm.htm,     \
pgmopt.htm,  \
reloc.htm,   \
sss.htm,     \
stm.htm,     \
sym.htm,     \
syswin.htm,  \
;;
 pflibomf HEAD ; Start module interface.
↑ PFLIBOMF_SYMBOL
€ASM internal structure which describes symbol names in LIBOMF and LIBCOF dictionary. The dictionary contains records for each public symbol.
In LIBOMF the member .ModPtr is OWORD aligned and it represents file address of the module (of its LIBHDR record) from the start of library file. Member .ModIndex is unused.
In LIBCOF the member .ModPtr is WORD aligned and it temporarily represents offset of the module (of its archive header) from the first module. The offset will be elevated by the size of COFF-archive signature plus size of both linker members plus size of longnames member, before it is stored to LIBCOF dictionary, i.e. to linker members.
PFLIBOMF_SYMBOL STRUC
.NamePtr  D D ; Pointer to the name of public symbol from the module.
.NameSize D D ; Netto size of the symbol name.
.ModPtr   D D ; Pointer to the archive member header followed with object module.
.ModIndex D D ; 1-based ordinal number of object module in the COFF library.
ENDSTRUC PFLIBOMF_SYMBOL
 ENDHEAD pflibomf  ; End of module interface.
↑ PflibomfLoadPgm BasePgm, ObjBegin, ObjSize, FileNamePtr

PflibomfLoadPgm reads all modules from an OMF library file and converts it to PGM structures which then will be stored on BasePgm.ModulePgmList.
The module starts with LHEADR or THEADR record and it terminates with MODEND or MODEND32 record.

The actual job is performed by PfomfLoadModule, a common procedure used by PflibomfLoadPgm and PfomfLoadPgm.

Input
BasePgm is pointer to an existing PGM to which the library is linked/imported.
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 imported file name (used in error reports).
Output
Linked/imported modules in the form of PGM are stored on BasePgm.ModulePgmList.
Error
Errors are reported with macro Msg.
Invokes
PfomfLoadModule PfomfLoadRecord
Tested by
t8206
PflibomfLoadPgm Procedure  BasePgm, ObjBegin, ObjSize, FileNamePtr
ObjEnd   LocalVar                      ; Pointer to the end of object file mapped in memory.
ModBegin LocalVar                      ; Pointer to the 1st module record (LHEADR or THEADR).
    MOV ESI,[%ObjBegin]
    MOV ECX,[%ObjSize]
    XOR EAX,EAX
    ADD ECX,ESI
    MOV [%ModBegin],EAX
    MOV [%ObjEnd],ECX
    MOV EDI,ESI
.NextRecord:                           ; Check OMF record which starts at EDI.
    Invoke PfomfLoadRecord::,EDI,[%ObjBegin],[%ObjEnd],[%FileNamePtr]
    JC .90:                            ; Abort on error. E8532 was already reported.
    MOV EDI,ESI                        ; The current record.
    TEST ECX
    JZ .90:                            ; If there are no more records in file.
.20:MOV AL,[ESI]                       ; Get the record type.
    LEA EDI,[ESI+ECX]                  ; Let EDI point to the next OMF record.
    Dispatch AL,THEADR,LHEADR,MODEND,MODEND32,LIBHDR,LIBEND
    JMP .NextRecord:                   ; Other record types are irrelevant here.

    ; Record handlers
    ; Input: ESI=^current record.
    ;        ECX=curent record brutto size.
    ;        EDI=^next record.
.LIBHDR:                               ; alias MSLIBR identifies a file of OMF modules followed by library dictionary.
    CMP ECX,12
    JB .E8533:                         ; LIBHDR record must be 16..512 bytes long.
    MOV EAX,[ESI+3]                    ; Get dictionary offset (dictionary is ignored by €ASM).
    ADD EAX,[%ObjBegin]
    MOV [%ObjEnd],EAX                  ; Update the end of loaded contents.
    TESTB [ESI+9],1                    ; Library flag "case sensitive".
    Msg cc=Z,'3653'                    ; Case insensitivity of linked and imported symbols is not supported.
.LIBEND:                               ; This should be the last record in file. Ignore.
    JMP .NextRecord:

.W3656:                                ; Module started with record type !1Bh at "!2$"[!3Hh] is not terminated with MODEND. Ignored.
    MOV EAX,[%ModBegin]
    MOV CL,[EAX]
    SUB EAX,[%ObjBegin]
    Msg '3656',ECX,[%FileNamePtr],EAX
    JMP .NextRecord:

.E8533:                                ; Abort linking due to error in file at record ESI.
    MOV CL,[ESI]
    SUB ESI,[%ObjBegin]
    Msg '8533',ECX,[%FileNamePtr],ESI  ; Invalid OMF record type !1Bh at "!2$"[!3Hh].
    JMP .90:                           ; Abort the loading of file.

.LHEADR:
.THEADR:
   MOV EAX,[%ModBegin]
   TEST EAX
   JNZ .W3656:                         ; Previous module started at EAX but wasn't closed by MODEND yet.
   MOV [%ModBegin],ESI
   JMP .NextRecord:

.MODEND32:
.MODEND:
    MOV EAX,[%ModBegin]
    TEST EAX
    JZ .50:                            ; MODEND terminates module which wasn't introduced by THEADR/LHEADR. Ignore.
    Invoke PfomfLoadModule::,[%BasePgm],[%ObjBegin],EAX,EDI,[%FileNamePtr],pgmoptLIBOMF
.50:XOR EAX,EAX
    MOV [%ModBegin],EAX
    ; In OMF library MODEND may be followed by 0x00 alignment bytes. Skip them now.
.60:CMP EDI,[%ObjEnd]                  ; EDI should point to the record which follows MODEND.
    JNB .90:
    CMPB [EDI],0                       ; Is it the intermodule alignment stuff?
    JNE .NextRecord:
    INC EDI
    JMP .60:
.90: EndProcedure PflibomfLoadPgm
↑ PflibomfCompile OutputStream, Pgm

PflibomfCompile is constructor for object/import library of OMF modules.
This procedure will create OMF library file with one module created from the base program, if not empty, and with one module created from each linked program loaded on Pgm.ModulePgmList.

Each library member starts with LHEADR record and it ends with MODEND/MODEND32 record. Library page size (alignment of LHEADR records) is fixed at 16.

Library modules are followed by hashed dictionary of public/exported names, as specified in [OMF], Appendix 2.

Input
OutputStream is pointer to an empty STREAM for the output file contents.
Pgm is pointer to a base PGM which may be empty or which represents a completely assembled module. Other library modules are loaded on Pgm.ModulePgmList.
Output
OutputStream is filled with output file contents.
Error
Errors are reported with macro Msg.
Invoked from
PfOutput
Invokes
EaBufferRelease EaBufferReserve EaStreamAlign ExpGetNextPrime PflibomfStoreModule PfomfStoreRecord
Tested by
t8206 t8550
PflibomfCompile Procedure OutputStream, Pgm
RecBuffer     LocalVar ; Buffer for the contents of one OMF record (without record type, length, checksum).
SymBuffer     LocalVar ; Buffer for PFLIBOMF_SYMBOL records.
NrOfModules   LocalVar ; Number of modules in library.
DirPtr        LocalVar ; Pointer to 1st directory block on Pgm.Pool.
NrOfBlocks    LocalVar ; Prime number of used directory blocks, 512 bytes each.
FileAddr      LocalVar ; File-address of symbol's module. Always OWORD aligned.
NameSize      LocalVar ; Number of bytes in the name of the symbol inserted to dictionary (+1).
FwdPtr        LocalVar ; Pointer to the first character of symbol name.
BwdPtr        LocalVar ; Pointer behind the last  character of symbol name.
BucketX       LocalVar ; Ordinal number of bucket 0..36.
BucketD       LocalVar ; Overflow delta bucket 1..36.
BlockX        LocalVar ; Ordinal number of block 0..[%NrOfBlocks]-1.
BlockD        LocalVar ; Overflow delta block    1..[%NrOfBlocks]-1.
BlockXstart   LocalVar ; Ordinal number of block 0..[%NrOfBlocks]-1 before delta applied.
    Invoke EaBufferReserve::,PflibomfCompile
    MOV [%RecBuffer],EAX
    Invoke EaBufferReserve::,PflibomfCompile
    MOV [%SymBuffer],EAX
    MOV EBX,[%Pgm]
    ; LIBHDR library header. It is 16 bytes long.
    BufferStoreDword [%RecBuffer],0             ; Padding.
    BufferStoreDword [%RecBuffer],0             ; The actual contents of LIBHDR will be
    BufferStoreDword [%RecBuffer],0             ;   patched later, at .40: and .85:,
    Invoke PfomfStoreRecord::,[%OutputStream],LIBHDR,[%RecBuffer]
    ; First store module from the base program EBX.
    SetSt [EBX+PGM.Status],pgmIsModule
    MOV EDX,pgmoptWidthMask+pgmoptModelMask
    AND EDX,[EBX+PGM.Pgmopt.Status]
    Invoke PflibomfStoreModule::,[%OutputStream],EBX,[%SymBuffer]
    Invoke EaStreamAlign::,[%OutputStream],16,0
.27:; Then store a module from each linked program.
    ListGetFirst [EBX+PGM.ModulePgmList]
    JZ .36:
.33:MOV EDI,EAX
    SetSt [EDI+PGM.Status],pgmIsModule
    SetSt [EDI+PGM.Pgmopt.Status],EDX           ; Use module properties MODEL= and WIDTH= from the base LIBOMF program.
    Invoke PflibomfStoreModule::,[%OutputStream],EDI,[%SymBuffer]
    Invoke EaStreamAlign::,[%OutputStream],16,0
.34:ListGetNext EDI                             ; The next linked program.
    JNZ .33:
.36:; LIBEND record. Its size will align the output to 512.
    StreamGetSize [%OutputStream]
    ADD EAX,3+1
    NEG EAX
    MOV ECX,0x0000_01FF
    AND ECX,EAX                                 ; Size of 512 alignment stuff.
    JZ .40:
    BufferResize [%RecBuffer],ECX
.40:Invoke PfomfStoreRecord::,[%OutputStream],LIBEND,[%RecBuffer]
    ; The library body is written, now patch the LIBHDR record on OutputStream.
    MOV EBX,[%OutputStream]
    StreamGetSize EBX                           ; EAX is now the dictionary offset, 512-aligned.
    MOV EDI,[EBX+STREAM.ReadPtr]                ; EDI now points to the beginning of streamed file data.
    MOV [EDI+3],EAX                             ; Patch the file address of dictionary inside LIBHDR record.
    ; Compile library directory.  Dictionary size will be patched later, at .85:.
    BufferRetrieve [%SymBuffer]                 ; Direcory contains FA and symbol name of each module,
    LEA EDX,[ESI+ECX]                           ;     as stored by PflibomfStoreModule at .35:.
    ; Initialize the directory. First try to guess the required number of blocks.
    SUB EAX,EAX                                 ; EAX will keep the estimated total size of names.
.43:CMP ESI,EDX
    JNB .46:
    ADD EAX,[ESI+PFLIBOMF_SYMBOL.NameSize]
    ADD EAX,1+2+1                               ; Add PascalSize byte + WORD of module paragraph FA + alignment.
    ADD ESI,SIZE# PFLIBOMF_SYMBOL               ; The next record.
    JMP .43:
.46:SUB EDX,EDX
    MOV ECX,512-38                              ; Block room for names.
    DIV ECX                                     ; Get required number of blocks.
    TEST EAX
    JNZ .47:
    INC EAX
.47:MOVD [%NrOfBlocks],EAX                      ; Estimation based on total name size.
.48:Invoke ExpGetNextPrime::,[%NrOfBlocks]      ; Used number of blocks must be prime.
    MsgUnexpected cc=C
    MOV [%NrOfBlocks],EAX                       ; Round the NrOfBlocks up to the nearest prime number.
    SAL EAX,9                                   ; Each block is 29 = 512 bytes long.
    MOV ECX,EAX
    MOV EBX,[%Pgm]
    PoolNew [EBX+PGM.Pool],EAX,Align=WORD       ; Allocate %NrOfBlocks * 512 bytes.
    MOV [%DirPtr],EAX
    MOV EDI,EAX
    MOV ESI,EAX
    SAR ECX,2
    XOR EAX,EAX
    REP STOSD                                   ; Clear all blocks.
    MOV ECX,[%NrOfBlocks]                       ; At least 2.
.50:MOVB [ESI+37],38/2                          ; Initialize byte-pointer to the free position in block.
    ADD ESI,512
    LOOP .50:                                   ; The next block.
    ; Populate directory blocks with public symbol names from %SymBuffer.
    BufferRetrieve [%SymBuffer]
    LEA EDX,[ESI+ECX]                           ; End of PFLIBOMF_SYMBOL records.
.53:CMP ESI,EDX
    JNB .85:                                    ; If there are no more symbols in library.
    MOV EAX,[ESI+PFLIBOMF_SYMBOL.ModPtr]
    MOV [%FileAddr],EAX
    MOV EDI,[ESI+PFLIBOMF_SYMBOL.NamePtr]
    MOV [%FwdPtr],EDI
    MOV EAX,[ESI+PFLIBOMF_SYMBOL.NameSize]      ; Symbol netto NameSize. Never exceeds 255.
    MOV [%NameSize],EAX
    ADD EAX,EDI
    MOV [%BwdPtr],EAX
    PUSH EDX,ESI
      ; Initialize the hash engine.
      MOV EDI,[%BwdPtr]
      MOV ESI,[%FwdPtr]
      MOV EAX,[%NameSize]
      OR AL,0x20                                ; Pascal-size byte is converted to lowercase, too (sic!).
      MOV [%BlockX],EAX
      MOV [%BucketD],EAX
      XOR EAX,EAX
      MOV [%BlockD],EAX
      MOV [%BucketX],EAX
      ; Compute hash.
.58:  DEC EDI
      MOV AL,[EDI]                              ; Read backward.
      OR AL,0x20                                ; Convert character to lower case.
      MOV ECX,[%BucketX]
      MOV EDX,[%BlockD]
      ROR CX,2
      ROL DX,2
      XOR ECX,EAX
      XOR EDX,EAX
      MOV [%BucketX],ECX
      MOV [%BlockD],EDX
      CMP EDI,[%FwdPtr]
      JBE .60:
      LODSB                                     ; Read forward.
      OR AL,0x20                                ; Convert character to lower case.
      MOV ECX,[%BlockX]
      MOV EDX,[%BucketD]
      ROL CX,2
      ROR DX,2
      XOR ECX,EAX
      XOR EDX,EAX
      MOV [%BlockX],ECX
      MOV [%BucketD],EDX
      JMP .58:
.60:  MOV ECX,37
      MOV EAX,[%BucketX]
      SUB EDX,EDX
      DIV ECX
      MOV [%BucketX],EDX
      MOV EAX,[%BucketD]
      SUB EDX,EDX
      DIV ECX
      TEST EDX
      JNZ .63:
      INC EDX
 .63: MOV [%BucketD],EDX
      MOV ECX,[%NrOfBlocks]
      MOV EAX,[%BlockX]
      SUB EDX,EDX
      DIV ECX
      MOV [%BlockX],EDX
      MOV [%BlockXstart],EDX
      MOV EAX,[%BlockD]
      SUB EDX,EDX
      DIV ECX
      TEST EDX
      JNZ .66:
      INC EDX
.66:  MOV [%BlockD],EDX                         ; Hashes are computed now.
      ; Toss the symbol name to dictionary. First calculate required record size.
      MOV ECX,[%NameSize]
      ADD ECX,1+2+1                             ; Byte PascalName size + word FileAddr + optional alignment.
      AND ECX,-2                                ; ECX is now required aligned record size.
.68:  MOV EDI,[%BlockX]
      MOV EBX,[%BucketX]                        ; 0..36.
      SAL EDI,9
      ADD EDI,[%DirPtr]                         ; EDI now points to the directory block selected by BlockX.
.70:  MOVZXB EAX,[EDI+EBX]                      ; Look if the bucket EBX is free.
      TEST EAX
      JZ .76:                                   ; If bucket is unoccupied.
      ADD EBX,[%BucketD]                        ; Otherwise apply bucket delta hash.
      MOV EAX,EBX
      SUB EDX,EDX
      MOV EBX,37
      DIV EBX                                   ; Modulo the bucket ordinal by 37.
      MOV EBX,EDX
      CMP EBX,[%BucketX]
      JNE .70:                                  ; Go to try another bucket in the same block EDI.
      ; Starting bucket was reached again, ergo all buckets in block EDI are occupied.
.72:  MOVB [EDI+37],0xFF                        ; Mark the block as full.
.73:  ; Block EDI is full, try another one.
      MOV EDI,[%BlockX]                         ; Current block ordinal 0..[%NrOfBlocks]-1.
      ADD EDI,[%BlockD]                         ; Add delta to block ordinal.
      MOV EAX,EDI
      SUB EDX,EDX
      MOV EBX,[%NrOfBlocks]
      DIV EBX                                   ; Modulo the block ordinal by [%NrOfBlocks].
      MOV [%BlockX],EDX                         ; Store as the new current block ordinal.
      CMP EDX,[%BlockXstart]
      JNE .68:                                  ; Try to find a free bucket in the new block EDI.
      ; This is a rare case when NrOfBlocks was underestimated.
      ; Allocated space for blocks will be abandoned
      ;    and building of the directory starts from scratch with bigger NrOfBlocks.
      JMP .48:                                  ; Increase %NrOfBlocks to the nearest prime and start again.
.76:  ; Bucket EBX is free. Inspect if there's enough free space for the required size ECX.
      MOV AL,[EDI+37]                           ; Free word offset in block.
      CMP AL,0xFF
      JE .73:                                   ; If block EDI is full, go to apply %BlockD and try another one.
      SAL EAX,1                                 ; EAX is now block offset of free space.
      LEA EDX,[EAX+ECX]                         ; Block offset of potential end of name.
      CMP EDX,512
      JA .72:                                   ; If overflow.
      JB .78:
      ; This was the last symbol, no more free space left. Mark the block as full.
      DEC EDX                                   ; EDX is now 0x1FF which will signalize full block at pseudobucket 37.
.78:  SAR EDX,1                                 ; Block EDI with bucket EBX will be used.
      MOV [EDI+37],DL                           ; New free word offset in block.
      LEA EDX,[EDI+EAX]                         ; Pointer to the free space.
      SAR EAX,1
      MOV [EDI+EBX],AL                          ; Write the word address to bucket EBX.
      MOV EAX,[%NameSize]                       ; Never above 255.
      MOV [EDX],AL                              ; Pascal name size byte.
      INC EDX
      CopyTo EDX,[%FwdPtr],Size=EAX             ; Transfer the symbol name.
      ADD EDX,EAX
      MOV EAX,[%FileAddr]
      SHR EAX,4                                 ; Convert FileAddr to paragraph file address of module (LHEADR).
      MOV [EDX],AX
.80:POP ESI,EDX
    ADD ESI,SIZE# PFLIBOMF_SYMBOL
    JMP .53:                                    ; Go to fetch the next symbol.
.85:; NrOfSymbols is finally known, patch the LIBHDR record on OutputStream.
    MOV EBX,[%OutputStream]
    MOV EDI,[EBX+STREAM.ReadPtr]                ; EDI is now beginning of streamed file data.
    MOV EAX,[%NrOfBlocks]
    MOV [EDI+7],AX                              ; Patch the dictionary size in blocks inside LIBHDR record.
    MOVB [EDI+9],0000_0001b                     ; Flag as case-sensitive.
    MOVB [EDI+15],0                             ; Checksum is no longer valid, change it to 0.
    MOV ESI,[%DirPtr]
    MOV ECX,[%NrOfBlocks]
    SAL ECX,9
    StreamStore [%OutputStream],ESI,ECX
.90:Invoke EaBufferRelease::,[%SymBuffer]
    Invoke EaBufferRelease::,[%RecBuffer]
    EndProcedure PflibomfCompile
↑ PflibomfStoreModule Stream, Module, SymbolBuf
PflibomfStoreModule will store one OMF module to the Stream if it contains at least one public/export/import symbol.
Module file address and name of its public/exported symbol(s) will be stored to SymbolBuf.
Input
Stream is pointer to a STREAM for the output library file contents. The stream may already contain previously stored library modules.
Module is pointer to a PGM representing the module being added to library.
SymbolBuf is pointer to the output BUFFER where module name will be stored in the form of PFLIBOMF_SYMBOL record.
Output
OutputStream is filled with OMF module contents (records LIBHDR..MODEND).
Error
Errors are reported with macro Msg.
Invokes
PfomfStoreModule
Invoked by
PflibomfCompile
PflibomfStoreModule Procedure Stream, Module, SymbolBuf
LibSymbol  LocalVar Size=SIZE# PFLIBOMF_SYMBOL
     MOV EBX,[%Module]
     SetSt [EBX+PGM.Status],pgmIsModule
     ; Fill SymbolBuf with global symbol identificators.
     LEA EDI,[%LibSymbol]
     StreamGetSize [%Stream]                     ; Previously stored modules?
     MOV [EDI+PFLIBOMF_SYMBOL.ModPtr],EAX
     MOVD [EDI+PFLIBOMF_SYMBOL.ModIndex],0       ; Module index is not employed in LIBOMF format.
     RstSt [EBX+PGM.Status],pgmSelected
     ListGetFirst [EBX+PGM.SymList]
     JZ .90:
.10: JNSt [EAX+SYM.Status],symPublic|symExport|symImport,.30:
     SetSt [EBX+PGM.Status],pgmSelected          ; At least one global symbol exists.
     MOV ESI,[EAX+SYM.NamePtr]
     MOV ECX,[EAX+SYM.NameSize]
     MOV [EDI+PFLIBOMF_SYMBOL.NamePtr],ESI
     XOR EDX,EDX
     DEC DL                                      ; EDX=255.
     CMP ECX,EDX
     JBE .20:
     Msg '3654',EAX                              ; Name of symbol "!1S" exceeds 255 characters. Truncated.
     XCHG ECX,EDX
.20: MOV [EDI+PFLIBOMF_SYMBOL.NameSize],ECX
     BufferStore [%SymbolBuf],EDI,SIZE# PFLIBOMF_SYMBOL
.30: ListGetNext EAX                             ; The next symbol.
     JNZ .10:
.40: JNSt [EBX+PGM.Status],pgmSelected,.90:
     Invoke PfomfStoreModule::,[%Stream],EBX
.90:EndProcedure PflibomfStoreModule
  ENDPROGRAM pflibomf

▲Back to the top▲