This source PF generates and loads EuroAssembler output object file in program format OMF (16bit or 32bit DOS or OS/2 object file).
EUROASM NOWARN=2101..2102 pfomf 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, \ ii.htm, \ msg.htm, \ pf.htm, \ pgm.htm, \ pgmopt.htm, \ reloc.htm, \ sss.htm, \ stm.htm, \ sym.htm, \ syswin.htm, \ ;;
pfomf HEAD ; Start module interface.
PfomfPayloadSize EQU 0 ; Variable netto size of carried data.
PFOMF_RECORD STRUC
.Type D B ; One of PfomfRecTypes.
.Size D W ; Size of .Payload plus .Checksum. Brutto record size = 3 + .Size.
.Payload D PfomfPayloadSize * B ; Data.
.Checksum D B ; Completes the sum of all bytes in record so that sum\256=0
.
ENDSTRUC PFOMF_RECORD
PFOMF_THREAD_TABLE STRUC .Frame0 D D ; Pointer to segment referred by frame thread 0. .Frame1 D D ; Pointer to segment referred by frame thread 1. .Frame2 D D ; Pointer to segment referred by frame thread 2. .Frame3 D D ; Pointer to segment referred by frame thread 3. .Target0 D D ; Pointer to segment referred by target thread 0. .Target1 D D ; Pointer to segment referred by target thread 1. .Target2 D D ; Pointer to segment referred by target thread 2. .Target3 D D ; Pointer to segment referred by target thread 3. ENDSTRUC PFOMF_THREAD_TABLE
pfomfRec32 = 0x0000_0001 ; Odd OMF record type (32bit, instead of 16bit). pfomfRecLi32 = 0x0000_0002 ; Odd OMF LIDATA record type (32bit, instead of 16bit). pfomfLiPending = 0x0000_0004 ; Unexpanded LIDATA is pending in LiInpEmitBuf and LiInpRelocBuf. pfomfImport = 0x0000_0010 ; OMF module is being imported rather than linked. pfomfByOrdinal = 0x0000_0020 ; Symbol is imported by ordinal rather than by name.
THEADR = 0x80 LHEADR = 0x82 COMENT = 0x88 MODEND = 0x8A MODEND32 = 0x8B EXTDEF = 0x8C TYPDEF = 0x8E PUBDEF = 0x90 PUBDEF32 = 0x91 LINNUM = 0x94 LINNUM32 = 0x95 LNAMES = 0x96 SEGDEF = 0x98 SEGDEF32 = 0x99 GRPDEF = 0x9A FIXUPP = 0x9C FIXUPP32 = 0x9D LEDATA = 0xA0 LEDATA32 = 0xA1 LIDATA = 0xA2 LIDATA32 = 0xA3 LIBHDR = 0xF0 LIBEND = 0xF1
pfomfThF0 = 010_000_00b ; Frame is specified by SEGDEF index. pfomfFxF0 = 0000_0000b pfomfThF1 = 010_001_00b ; Frame is specified by GRPDEF index. pfomfFxF1 = 0001_0000b pfomfThF2 = 010_010_00b ; Frame is specified by EXTDEF index. pfomfFxF2 = 0010_0000b pfomfThF3 = 010_011_00b ; Frame is specified by paragraph absolute address. Not supported. pfomfFxF3 = 0011_0000b pfomfThF4 = 010_100_00b ; Frame is specified by SEGDEF of previous L?DATA record. No frame index. pfomfFxF4 = 0100_0000b pfomfThF5 = 010_101_00b ; Frame equals to target. No frame index. pfomfFxF5 = 0101_0000b pfomfThT0 = 000_000_00b ; Target is specified by SEGDEF index. Displacement follows. pfomfFxT0 = 00000_000b pfomfThT1 = 000_001_00b ; Target is specified by GRPDEF index. Displacement follows. pfomfFxT1 = 00000_001b pfomfThT2 = 000_010_00b ; Target is specified by EXTDEF index. Displacement follows. pfomfFxT2 = 00000_010b pfomfThT3 = 000_011_00b ; Target is specified by paragraph absolute address. Not supported. pfomfFxT3 = 00000_011b pfomfThT4 = 000_100_00b ; Target is specified by SEGDEF index. No displacement. pfomfFxT4 = 00000_100b pfomfThT5 = 000_101_00b ; Target is specified by GRPDEF index. No displacement. pfomfFxT5 = 00000_101b pfomfThT6 = 000_110_00b ; Target is specified by EXTDEF index. No displacement. pfomfFxT6 = 00000_110b
ENDHEAD pfomf ; End of module interface.
NameSize should not exceed 255 characters.
Size of data in Buffer will not exceed 1020 bytes, obeying max.allowed OMF record size 1024. Should NameSize+BufferSize exceed 1020, the name is not written and CF is set.
PfomfStoreName Procedure Buffer, NamePtr, NameSize MOV EBX,[%Buffer] MOV EDI,[%NamePtr] MOV EDX,[%NameSize] MOV ECX,255 CMP EDX,ECX JC .10: LEA EAX,[%NamePtr] Msg '8513',EAX ; Segment or symbol name "!1S" exceeds 254 characters. Truncated in OMF. MOV EDX,ECX ; Truncate name. .10:BufferRetrieve EBX ; Get old buffer contents to ESI,ECX. ADD ECX,EDX CMP ECX,1021 CMC JC .90: ; Refuse if new record size too big. BufferStorePascalString EBX,EDI,Size=EDX CLC .90:EndProcedure PfomfStoreName
PfomfStoreRecord Procedure OutputStream, RecType, RecBuffer MOV EBX,[%RecType] ; BL is checksum accumulator, too. StreamStoreByte [%OutputStream],BL ; Store Record Type. BufferRetrieve [%RecBuffer] MOV EDI,ESI MOV EDX,ECX JECXZ .20: CMP ECX,1020 ; Maximal record size allowed by OMF specification. Msg cc=A,'9975',ECX,EBX ; Internal error: record size !1D exceeded 1024 in OMF record type 0x!2H. INC ECX ; +1 the checksum byte. ADD BL,CL ; Update checksum with Record Length lower byte. ADD BL,CH ; Update checksum with Record Length higher byte. DEC ECX .10:LODSB ADD BL,AL ; Update checksum with payload data. LOOP .10: .20:AND EDX,0x0000_FFFF INC EDX StreamStoreWord [%OutputStream],DX ; Store Record Length. DEC EDX StreamStore [%OutputStream],EDI,EDX ; Store Record payload. NEG BL StreamStoreByte [%OutputStream],BL ; Checksum byte. BufferClear [%RecBuffer] EndProcedure PfomfStoreRecord
PfomfStoreIndex Procedure Buffer, Index SUB ECX,ECX MOV EDX,[%Index] INC ECX CMP EDX,127 JNA .20: INC ECX .20:BufferNew [%Buffer],ECX ; Returns ptr to 1 or 2 allocated bytes in EAX. CMP CL,1 JE .80: CMP EDX,32767 JNA .50: Msg '8519' ; Number of indexed references in OMF exceeded 32767. Truncated. MOV DX,0xFFFF STC JMP .60: .50: OR DH,0x80 .60: MOV [EAX],DH LEA EAX,[EAX+1] .80: MOV [EAX],DL EndProcedure PfomfStoreIndex
EuroAssembler does not create iterated LIDATA records.
PfomfStoreData Procedure Stream, Segment DataBuf LocalVar ; Buffer for emitted data. DataPtr LocalVar ; Pointer to unstored data in Segment.EmitBuffer. Increased after each LEDATA store. DataEnd LocalVar ; Pointer to the end of data in Segment.EmitBuffer. OffsPtr LocalVar ; Offset corresponding to the 1st byte of current LEDATA record. Increased after each LEDATA store. OffsEnd LocalVar ; Offset behind the last byte of current LEDATA record. Fix16Buf LocalVar ; Buffer for 16bit fixup subrecords. Fix32Buf LocalVar ; Buffer for 32bit fixup subrecords. RelocPtr LocalVar ; Pointer to unstored RELOC in Segment.RelocBuffer. Increased after each subrecord store. RelocEnd LocalVar ; Pointer to end of RELOCs in Segment.RelocBuffer. Invoke EaBufferReserve::,PfomfStoreData MOV [%DataBuf],EAX Invoke EaBufferReserve::,PfomfStoreData MOV [%Fix16Buf],EAX Invoke EaBufferReserve::,PfomfStoreData MOV [%Fix32Buf],EAX MOV EBX,[%Segment] StreamGetSize [%Stream] MOV [EBX+SSS.BottomFA],EAX BufferRetrieve [EBX+SSS.EmitBuffer] ; Load all emitted data. JECXZ .90: ; If there are no data in segment. MOV [%DataPtr],ESI ; Start with the 1st data byte. ADD ECX,ESI MOV [%DataEnd],ECX BufferRetrieve [EBX+SSS.RelocBuffer] ; Load all RELOC records. MOV [%RelocPtr],ESI ADD ECX,ESI MOV [%RelocEnd],ECX MOV EDX,[EBX+SSS.BottomLow] MOV [%OffsPtr],EDX ; Keep storing LEDATA records in the loop .10:...80:, optionally followed with FIXUP record(s). ; The width of LEDATA record (0xA0 or 0xA1) depends on segment width. .10:Invoke PfomfStoreIndex,[%DataBuf],[EBX+SSS.SegmIndex] ; LEDATA segment index. JSt [EBX+SSS.Status],sssWidth16,.15: BufferStoreDword [%DataBuf],EDX ; LEDATA32 offset. JMP .20: .15:BufferStoreWord [%DataBuf],EDX ; LEDATA offset. .20:MOV EAX,[%DataEnd] ; Compute maximal OffsEnd due to the limited OMF record size (1024). SUB EAX,[%DataPtr] CMP EAX,1014 JNA .25: MOV EAX,1014 .25:ADD EAX,[%OffsPtr] MOV [%OffsEnd],EAX ; Data between OffsPtr..OffsEnd are prepared for LEDATA. ; OffsEnd may be decreased later if some relocation spans over it or if correspoding fixup subrecord overflows FIXUP record size. .30:MOV ESI,[%RelocPtr] CMP ESI,[%RelocEnd] JNB .60: ; If there are no more relocations for this segment. MOV EAX,[ESI+RELOC.OrgLow] CMP EAX,[%OffsPtr] JB .40: ; If RELOC doesn't belong to the current LEDATA chunk. MOV ECX,relocWidthMask AND ECX,[ESI+RELOC.Status] SAR ECX,19 ; Convert relocWidth (16,32,64) to 2,4,8 bytes. ADD ECX,EAX ; End-of-location offset of relocation ESI. CMP ECX,[%OffsEnd] JA .50: ; If relocated target does not fit to data between OffsPtr..OffsEnd. ; Relocation ESI is relevant to LEDATA chunk, it will be stored. MOV EAX,[%Fix16Buf] ; Decide what width (16 or 32) FIXUPP should be used. JSt [ESI+RELOC.Status],relocWidth16,.35: MOV EAX,[%Fix32Buf] .35:Invoke PfomfStoreFixup,EAX,ESI,[%OffsPtr],EBX ; It is our fixup. JC .50: ; If fixup couldn't be stored because its OMF record is full. .40:ADD ESI,SIZE#RELOC ; Try the next relocation if fixup subrecord was successfully stored. MOV [%RelocPtr],ESI JMP .30: ; Check if the next RELOC corresponds with LEDATA, too. .50:; Relocation ESI could not be stored because FixBuf is full or because the relocated location spans over OffsEnd. MOV EAX,[ESI+RELOC.OrgLow] ; The whole location will be omitted from LEDATA. CMP EAX,[%OffsEnd] JAE .60: ; If already omitted. MOV [%OffsEnd],EAX .60:; OffsEnd is finalized, now it's time to flush LEDATA and FIXUP records. MOV EDX,[%OffsEnd] SUB EDX,[%OffsPtr] ; EDX is now LEDATA data netto size. JNA .90: ; If there are no more data in segment. BufferStore [%DataBuf],[%DataPtr],EDX ADD [%DataPtr],EDX ; Prepare pointers for the next LEDATA record. ADD [%OffsPtr],EDX MOV AL,LEDATA ; Record type A0 or A1. JSt [EBX+SSS.Status],sssWidth16,.65: INC EAX ; LEDATA32 = 0xA1. .65:Invoke PfomfStoreRecord,[%Stream],EAX,[%DataBuf] ; Store LEDATA. BufferRetrieve [%Fix16Buf] JECXZ .70: ; Skip if there are no 16bit fixups for this LEDATA chunk. Invoke PfomfStoreRecord,[%Stream],FIXUPP,[%Fix16Buf] ; Store FIXUPP16. .70:BufferRetrieve [%Fix32Buf] JECXZ .80: ; Skip if there are no 32bit fixups for this LEDATA chunk. Invoke PfomfStoreRecord,[%Stream],FIXUPP32,[%Fix32Buf] ; Store FIXUPP32. .80:JMP .10: ; Go and store the next LEDATA/FIXUP pair. .90:Invoke EaBufferRelease::,[%Fix32Buf] Invoke EaBufferRelease::,[%Fix16Buf] Invoke EaBufferRelease::,[%DataBuf] EndProcedure PfomfStoreData
relocWidth
flag in Reloc.Status
specifies if the
currently stored OMF FIXUPP record is 16bit or 32bit.
THREAD subrecords are not generated by EuroAssembler.
PfomfStoreFixup Procedure FixBuffer, Reloc, Offset, SegmPtr BufferRetrieve [%FixBuffer] ; Examine buffer size occupied by previous subrecords. CMP ECX,1021-11 ; Size of the fixup subrecord in the worst case may be 11 bytes. CMC JC .90: ; Refuse this subrecord if FixBuffer is full. MOV ESI,[%Reloc] MOV EDX,[ESI+RELOC.OrgLow] SUB EDX,[%Offset] TEST EDX,~0x3FF ; EDX is now the address 0..1023 relative to the payload in previous LEDATA. JNZ .F9975: ; Internal error: record size !1D exceeded 1024 in OMF record type 0x!2H. ; Construct 16bit FIXUP subrecord field Locat in DX. XCHG DH,DL ; Locat is big endian. MOV EAX,[ESI+RELOC.Status] JSt EAX,relocIgnore,.90: AND EAX,relocTypeMask ; Dispatch relocation type Far,Para,Rel,Abs. Dispatch EAX,relocAbsVA,relocRel,relocPara,relocFar .F9974:Msg '9974',[ESI+RELOC.Status],[%SegmPtr],[ESI+RELOC.OrgLow] ; Internal error: unhandled relocation type 0x!1W at [!2S]:!3Hh.',0 .Err:JMP .90: .W3831:Msg '3831',[%SegmPtr],[ESI+RELOC.OrgLow] ; Self-relative relocation to an absolute VA at [!1S]:!2Hh is not linkable. JMP .Err: .W3832:Msg '3832',[%SegmPtr],[ESI+RELOC.OrgLow] ; Far relocation to an absolute VA at [!1S]:!2Hh is not linkable. JMP .Err: .F9975:Msg '9975',EDX,0x9C ; Internal error: record size !1D exceeded 1024 in OMF record type 0x!2H JMP .Err: .relocAbsVA:JSt [ESI+RELOC.Status],relocWidth32,.05: OR DL,11_0001_00b ; Segment-relative, Location=1 (16bit offset). JMPS .30: .05:OR DL,11_1001_00b ; Segment-relative, Location=9 (32bit offset). JMPS .30: .relocFar:JSt [ESI+RELOC.Status],relocWidth32,.10: OR DL,11_0011_00b ; Segment-relative, Location=3 (segment:16bit offset). JMPS .30: .10:OR DL,11_1011_00b ; Segment-relative, Location=11 (segment:32bit offset). JMPS .30: .relocPara: OR DL,11_0010_00b ; Segment-relative, Location=2 (base segment). JMPS .30: .relocRel:MOV EAX,2 ; IP-relative 16bit relocation OMF correction. JSt [ESI+RELOC.Status],relocWidth32,.20: OR DL,10_0001_00b ; IP-relative, Location=1 (16bit offset). JMPS .25: .20:OR DL,10_1001_00b ; IP-relative, Location=9 (32bit offset). ADD EAX,2 ; IP-relative 32bit relocation OMF correction. .25:ADD [ESI+RELOC.AddendLow],EAX ADC [ESI+RELOC.AddendHigh],0 .30:BufferStoreWord [%FixBuffer],EDX ; Store field Locat. ; Construct 8bit FIXUP subrecord field FixData in DL. MOV ECX,[ESI+RELOC.Symbol] JECXZ .40: MOV EDI,[ECX+SYM.Section] ; Target SSS object (segment|group|extern). TEST EDI JNZ .45: ; Skip when target symbol ECX is not scalar. .40:JSt [ESI+RELOC.Status],relocRel,.W3831: ; Self-relative relocation to an absolute VA at [!1S]:!2Hh is not linkable. JSt [ESI+RELOC.Status],relocFar,.W3832: ; Far relocation to an absolute VA at [!1S]:!2Hh is not linkable. JMP .F9974: ; Internal error: unhandled relocation type 0x!1W at [!2S]:!3Hh. .45:MOV ECX,[EDI+SSS.SegmPtr] JECXZ .47: MOV EDI,ECX .47:;;;MOV ECX,[EDI+SSS.GroupPtr] ;;;JECXZ .48: ;;;MOV EDI,ECX .48:MOV EAX,[EDI+SSS.Status] ; EAX is now the type of target SSS object. MOV ECX,[ESI+RELOC.AddendLow] ; ECX is additional displacement of relocated object (usually 0). JSt EAX,sssGroup,.sssGroup: JSt EAX,sssSegment,.sssSegment: JSt EAX,sssExtern,.sssExtern: JMP .F9974: ; Internal error: unhandled relocation type 0x!1W at [!2S]:!3Hh. .StoreFixDat: BufferStoreByte [%FixBuffer],EDX RET .sssExtern: MOV DL,0101_0110b ; Frame is determined by Target EXTDEF. F5,T6,no displacement. JECXZ .50: ; Skip when no additional displacement is present. AND DL,1111_1011b ; Frame is determined by Target EXTDEF. F5,T2,displacement present. .50:CALL .StoreFixDat: Invoke PfomfStoreIndex,[%FixBuffer],[EDI+SSS.SegmIndex] ; TargetDatum EXTDEF or GRPDEF. JMP .StoreTargetDisplacement: .sssGroup: MOV DL,0101_0101b ; Frame is determined by Target GRPDEF. F5,T5,no displacement. JECXZ .50: AND DL,1111_1011b ; Frame is determined by Target GRPDEF. F5,T1,displacement present. JMP .50: .sssSegment: ; Group membership is ignored in fixup. Target segment EDI does not belong to any group. MOV DL,0101_0100b ; Frame is determined by Target SEGDEF. F5,T4,no displacement. JECXZ .75: AND DL,1111_1011b ; Frame is determined by Target SEGDEF. F5,T0,displacement present. .75:CALL .StoreFixDat: .80:Invoke PfomfStoreIndex,[%FixBuffer],[EDI+SSS.SegmIndex] ; TargetDatum SEGDEF. .StoreTargetDisplacement: ; Store the displacement ECX as a word or dword, depending on P-bit in DL. TEST DL,0000_0100b ; P-bit in FixDat field. JNZ .90: ; Skip if P=1, no target displacement. JSt [ESI+RELOC.Status],relocWidth16,.85: BufferStoreDword [%FixBuffer],ECX JMP .90: .85:BufferStoreWord [%FixBuffer],ECX .90:EndProcedure PfomfStoreFixup
PfomfCompile Procedure OutputStream, Pgm Invoke PfomfStoreModule, [%OutputStream],[%Pgm] EndProcedure PfomfCompile
PfomfStoreModule Procedure OutputStream, Pgm RecBuf LocalVar ; Buffer for the netto contents of one OMF record (without record type, length, checksum). NameIndex LocalVar ; Ordinal number of segment name in LNAMES (1,2,3,,,). SegIndex LocalVar ; Ordinal number of segment in GRPDEF (1,2,3,,,). Kept in SSS.SegmIndex. GrpIndex LocalVar ; Ordinal number of group in PUBDEF (1,2,3,,,). Kept in SSS.SegmIndex. ExtIndex LocalVar ; Ordinal number of extern in PUBDEF (1,2,3,,,). Kept in SSS.SegmIndex. MOV EDX,[%Pgm] ; Initialize temporary data structures. Invoke EaBufferReserve::,PfomfStoreModule MOV [%RecBuf],EAX Invoke PgmOrderSegments::,EDX ; Create OMF records. MOV EAX,LHEADR ; Assume library member. JSt [EDX+PGM.Status],pgmIsModule,.10: MOV EAX,THEADR ; Assume OMF module. .10: CALL .THEADR: ; Module name. CALL .COMENT_00: ; Compiler info. ; If message "I0010 EuroAssembler version !1S started." is suppressed, ; do not store the version info in COMENT_00 and skip the dependency info in COMENT_E9. ; This is used in €ASM tests where the produced object file should not depend on €ASM version. TESTB [Ea.Eaopt.NoWarn:: + 0010/8],0x01<<(0010\8) ; >> Test if NOWARN=0010. JNZ .20: ; Skip when NOWARN=0010. CALL .COMENT_E9: ; File dependency. .20:CALL .COMENT_9D: ; CPU and model info. CALL .COMENT_A0_01: ; Imported symbols. CALL .COMENT_A0_02: ; Exported symbols. CALL .LNAMES: ; Name declarations. CALL .SEGDEF: ; Segment definitions. CALL .EXTDEF: ; Extern definitions. CALL .GRPDEF: ; Group definitions. CALL .PUBDEF16: ; Public definitions. CALL .PUBDEF32: ; Public with offset above 64KB. ; Emitted contents and relocations are handled with records ; LEDATA and FIXUPP called via PfomfStoreData. MOV EDX,[%Pgm] BufferRetrieve [EDX+PGM.SegOrdBuffer] SHR ECX,2 JZ .70: .30:LODSD JNSt [EAX+SSS.Status],sssSegment,.50: JSt [EAX+SSS.Purpose],sssPurposeBSS,.50: ; Do not emit. JSt [EAX+SSS.Purpose],sssPurposeCODE|sssPurposeDATA|sssPurposeRODATA,.40: ; Always emit. JNSt [EAX+SSS.Status],sssNotBSS,.50: ; Emit stack segment only if it contains initialized data. .40:Invoke PfomfStoreData,[%OutputStream],EAX ; Store OMF records LEDATA and FIXUPP of segment EAX. .50:LOOP .30: ; The next segment. .70:CALL .MODEND: ; End of OMF file. .90:Invoke EaBufferRelease::,[%RecBuf] Invoke PgmResizeGroups::,[%Pgm] EndProcedure PfomfStoreModule ; OMF records handlers write %Pgm information to %RecBuf and then store one OMF record ; into %OutputStream, using the procedure PfomfStoreRecord. PfomfStoreModule.THEADR: PROC ; Record of type EAX (THEADR or LHEADR) with module name. MOV ESI,[%Pgm] BufferStorePascalString [%RecBuf],[ESI+PGM.NamePtr],Size=[ESI+PGM.NameSize] ; Pgm name. Invoke PfomfStoreRecord,[%OutputStream],EAX,[%RecBuf] RET ENDP PfomfStoreModule.THEADR: PfomfStoreModule.COMENT_00: PROC ; Record with compiler info, e.g. "EuroAssembler 20161016 Win" BufferStoreWord [%RecBuf],0 ; 0x88 comment class 00, purge, list. BufferStore [%RecBuf],=B"EuroAssembler",13 ; If the message "I0010 EuroAssembler version !1S started." is suppressed, skip further info in record. TESTB [Ea.Eaopt.NoWarn:: +0010/8],0x01<<(0010\8) ; >> Test if NOWARN=0010. JNZ .c1: BufferStoreByte [%RecBuf],' ' ; Otherwise append €ASM version and OS info. BufferStore [%RecBuf],Ea.Version::,8 BufferStoreByte [%RecBuf],' ' MOV ESI,Ea.EuroasmOS:: GetLength$ ESI BufferStore [%RecBuf],ESI,ECX .c1:Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] RET ENDP PfomfStoreModule.COMENT_00: PfomfStoreModule.COMENT_9D: PROC ; Record with CPU and MODEL info (Xenix). MOV EDX,[%Pgm] BufferStoreWord [%RecBuf],0x9D00 ; Comment class 9D, purge, list. MOV EDI,[Ea.Eaopt.Machine::] MOV AL,'0' AND EDI,iiCPU_CpuMask JZ .c2: ; If iiCPU_086, leave AL='0'. BSR ECX,EDI ; ECX is now 6..12 for CPU=186..X64. SUB CL,5 ADD AL,CL ; AH is now '0'..'7' for CPU=086..X64. .c2:MOV EDI,[EDX+PGM.Pgmopt.Status] AND EDI,pgmoptModelMask Invoke DictSearchByData::,DictProgramModels::,EDI ; Returns ESI=ptr to "SMALL","COMPACT" etc. MOV AH,'?' JC .c5: ; Skip if PROGRAM MODEL= is not specified. MOV ESI,[ESI] ; Let ESI point to the model name. MOV AH,[ESI] ; Load the first letter of model specification. OR AH,'s'^'S' ; Convert to lowercase. .c5:XCHG EAX,EDI ; Temporary save EAX to EDI. BufferNew [%RecBuf],2 XCHG EDI,EAX STOSW ; CPU and model info. Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] RET ENDP PfomfStoreModule.COMENT_9D: PfomfStoreModule.COMENT_E9: PROC ; Record(s) with dependency files info (Borland). BufferStoreWord [%RecBuf],0xE940 ; 0x88 comment class 0xE9, purge, nolist. ; First store records of the main source file. BufferStore [%RecBuf],Ea.SrcTime::,4 ; DosDateTime of source file. LEA EAX,[Ea.SrcFile.Name::] BufferStorePascalString [%RecBuf],EAX ; Pascal-formated string with ASCIIZ filename. Msg cc=C,'8512',EAX ; Length of linked file name "!1$" exceeds 254 characters. Invoke PfomfStoreRecord,[%OutputStream],0x88,[%RecBuf] ; Now store records of all included files. %RecBuf was cleared. SUB EDI,EDI ; Index in PGM.Incl*Tables. MOV EDX,[%Pgm] .c2:BufferStoreWord [%RecBuf],0xE940 ; 0x88 comment class 0xE9, purge, nolist. CMP EDI,[EDX+PGM.InclFilesNr] ; How many files are included in this program source. JAE .c8: ; If no more files. MOV ESI,[EDX+PGM.InclFileTimeTable] ; ESI=^array of dwords with DosDateTime. LEA ESI,[ESI+4*EDI] BufferStore [%RecBuf],ESI,4 ; DosDateTime of included file. MOV ESI,[EDX+PGM.InclFilesTable] ; ESI=^array of pointers to FILE structure. MOV EAX,[ESI+4*EDI] ; EAX=^FILE. LEA EAX,[EAX+FILE.Name] BufferStorePascalString [%RecBuf],EAX ; Pascal-formated string with filename. Msg cc=C,'8512',EAX ; Length of linked file name "!1$" exceeds 254 characters. Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] INC EDI JMP .c2: ; The next included file name. .c8:Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] ; The last empty COMENT 0xE9 signalizes end of dependencies. RET ENDP PfomfStoreModule.COMENT_E9: PfomfStoreModule.COMENT_A0_01: PROC ; Import definitions, encoded as COMENT class A0 type 01. MOV EDX,[%Pgm] MOV ECX,0xFF00_0000 ; ImportedByOrd marker. ListGetFirst [EDX+PGM.SymList] ; Enumerate program symbols. JZ .i9: .i1:MOV EBX,EAX JNSt [EBX+SYM.Status],symImport,.i8: MOV EAX,[EBX+SYM.DllNameSize] TEST EAX JNZ .i2: MOV [EBX+SYM.DllNamePtr],=B"%EuroasmDefaultDllName" MOV [EBX+SYM.DllNameSize],%EuroasmDefaultDllNameSize .i2:MOV EAX,0x0001A080 ; Comment class A0,nopurge,list,subtype 01,ImportedByName. JNSt [EBX+SYM.Status],symImportedByOrd,.i3: OR EAX,ECX ; Change the ByOrdinal flag from 00 to FF. .i3:BufferStoreDword [%RecBuf],EAX MOV EDI,[EBX+SYM.InterNamePtr] MOV EDX,[EBX+SYM.InterNameSize] TEST EDX JNZ .i4: MOV EDI,[EBX+SYM.NamePtr] MOV EDX,[EBX+SYM.NameSize] .i4:Invoke PfomfStoreName,[%RecBuf],EDI,EDX Invoke PfomfStoreName,[%RecBuf],[EBX+SYM.DllNamePtr],[EBX+SYM.DllNameSize] TEST EAX,ECX JNZ .i6: ; If ImportedByOrd. Invoke PfomfStoreName,[%RecBuf],[EBX+SYM.NamePtr],[EBX+SYM.NameSize] ; ImportedByName. JMP .i7: .i6:MOV EAX,[EBX+SYM.OrdinalNr] BufferStoreWord [%RecBuf],EAX, ; Store WORD ordinal/name. .i7:Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] .i8:ListGetNext EBX ; The next symbol. JNZ .i1: .i9:RET ENDP PfomfStoreModule.COMENT_A0_01: PfomfStoreModule.COMENT_A0_02: PROC ; Export definitions, encoded as COMENT class A0 type 02. MOV EDX,[%Pgm] ListGetFirst [EDX+PGM.SymList] ; Enumerate program symbols. JZ .x9: .x1:MOV EBX,EAX JNSt [EBX+SYM.Status],symExport,.x8: MOV EAX,0x0002A080 ; Comment class A0,nopurge,list,subtype 02,ExportedByName. ; €ASM does not support export by ordinal. BufferStoreDword [%RecBuf],EAX Invoke PfomfStoreName,[%RecBuf],[EBX+SYM.NamePtr],[EBX+SYM.NameSize] ; Exported name. MOV ESI,[EBX+SYM.InterNamePtr] MOV ECX,[EBX+SYM.InterNameSize] JECXZ .x5: Compare [EBX+SYM.NamePtr],[EBX+SYM.NameSize],ESI,ECX JE .x5: ; Exported by a different name. Invoke PfomfStoreName,[%RecBuf],ESI,ECX JMP .x7: .x5:; Internal name equals to exported name. Store as NULL Pascal string. BufferStoreByte [%RecBuf],0 .x7:Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] .x8:ListGetNext EBX ; The next symbol. JNZ .x1: .x9:RET ENDP PfomfStoreModule.COMENT_A0_02: PfomfStoreModule.COMENT_A1: PROC ; Marker New OMF extension (CodeView). BufferStoreWord [%RecBuf],0xA140 ; Comment class 0xA1, purge, nolist. Invoke PfomfStoreRecord,[%OutputStream],COMENT,[%RecBuf] RET ENDP PfomfStoreModule.COMENT_A1: PfomfStoreModule.LNAMES: PROC ; Names of segments and their classes will be stored to LNAMES records. ; Segment name index is written to SSS.SegmIndex. Segment class index is 1 if empty, otherwise SSS.SegmIndex+1. Invoke PfomfStoreName,[%RecBuf],0,0 ; The first stored name (%NameIndex=1) is always empty. MOVD [%NameIndex],1 MOV EDX,[%Pgm] BufferRetrieve [EDX+PGM.SegOrdBuffer] SHR ECX,2 JZ .ln9: .ln2:LODSD MOV EBX,EAX JNSt [EBX+SSS.Status],sssSegment|sssGroup,.ln8: MOV EDI,[EBX+SSS.NamePtr] MOV EDX,[EBX+SSS.NameSize] Invoke PfomfStoreName,[%RecBuf],EDI,EDX JNC .ln4: ; %NameBuf is full, we need to flush it to LNAMES record and clear it. Invoke PfomfStoreRecord,[%OutputStream],0x96,[%RecBuf] Invoke PfomfStoreName,[%RecBuf],EDI,EDX ; This time it must succeed. .ln4:MOV EAX,[%NameIndex] INC EAX MOV [EBX+SSS.NameIndex],EAX MOV [%NameIndex],EAX MOV EDX,[EBX+SSS.ClassSize] MOV EDI,[EBX+SSS.ClassPtr] TEST EDX JZ .ln8: .ln5:Invoke PfomfStoreName,[%RecBuf],EDI,EDX JNC .ln7: ; %NameBuf is full, we need to flush it to LNAMES record. Invoke PfomfStoreRecord,[%OutputStream],0x96,[%RecBuf] Invoke PfomfStoreName,[%RecBuf],EDI,EDX ; This time it must succeed. .ln7:INCD [%NameIndex] ; NameIndex of CLASS= attribute is always segment.NameIndex+1. .ln8:DEC ECX JNZ .ln2: ; The next segment|group. .ln9:Invoke PfomfStoreRecord,[%OutputStream],LNAMES,[%RecBuf] ; Flush %NameBuf to LNAMES record. RET ENDP PfomfStoreModule.LNAMES: PfomfStoreModule.SEGDEF:PROC ; Segment definitions will be stored to SEGDEF records. MOVD [%SegIndex],0 MOV EDX,[%Pgm] BufferRetrieve [EDX+PGM.SegOrdBuffer] SHR ECX,2 JZ .s99: .s10:LODSD PUSH ECX MOV EBX,EAX MOV EAX,[EBX+SSS.Status] JNSt EAX,sssSegment,.s90: ; Segment ordinal in GRPDEF. MOV ECX,[%SegIndex] INC ECX MOV [EBX+SSS.SegmIndex],ECX MOV [%SegIndex],ECX ; Put segment attribute A (alignment) to CL bits 5..7. MOV EAX,[EBX+SSS.Alignment] ; 0,1,2,4,8,16,,, MOV CL,1<<5 ;>> A=1 (BYTE). BSR EDX,EAX ; EDX is now 0..9 (alignment 1..256). JZ .s20: ; If no alignment (BYTE). CMP DL,1 ; ALIGN=WORD? JB .s20: MOV CL,2<<5 ;>> A=2 (WORD). JE .s20: MOV CL,5<<5 ;>> A=5 (DWORD). CMP DL,2 ; ALIGN=DWORD? JE .s20: MOV CL,3<<5 ;>> A=3 (OWORD). CMP DL,5 ; ALIGN=32? JB .s20: MOV CL,4<<5 ;>> A=4 (256). .s20:; Put segment attribute C (combine) to DL bits 2..4. MOV EAX,[EBX+SSS.Status] JSt EAX,sssPrivate,.s30: MOV DL,5<<2 ;>> C=5 (STACK). JSt EAX,sssStack,.s25: JSt [EBX+SSS.Purpose],sssPurposeSTACK,.s25: ; If PURPOSE=STACK, force COMBINE=STACK in this format. MOV DL,6<<2 ;>> C=6 (COMMON). JSt EAX,sssCommon,.s25: MOV DL,2<<2 ;>> C=2 (PUBLIC). .s25:OR CL,DL .s30:JSt EAX,sssWidth16,.s40: ; 32bit segment. OR CL,0x01 ; Set ACBP segment attribute P (use32). MOV EAX,[EBX+SSS.TopLow] MOV EDX,[EBX+SSS.TopHigh] SUB EAX,[EBX+SSS.BottomLow] SBB EDX,[EBX+SSS.BottomHigh] TEST EDX JZ .s35: Msg '8524',EBX ; OMF 32bit segment [!1S] size exceeded 4GB. Truncated. OR CL,0x02 ; Set ACBP segment attribute B. SUB EAX,EAX .s35:PUSH EAX ; Save segment size EAX. BufferNew [%RecBuf],1+4 ; ACBP+dword segment size. MOV EDI,EAX MOV EAX,ECX STOSB ; Store ACBP attribute. POP EAX STOSD ; Store 32bit segment length. JMP .s70: .s40:; 16bit segment. MOV EAX,[EBX+SSS.TopLow] MOV EDX,[EBX+SSS.TopHigh] SUB EAX,[EBX+SSS.BottomLow] SBB EDX,[EBX+SSS.BottomHigh] TEST EDX JNZ .s45: CMP EAX,64k JE .s50: JB .s60: .s45:Msg '8523',EBX,EAX ; OMF 16bit segment [!1S] size !2K exceeded 64KB. Truncated. .s50:OR CL,0x02 ; Set ACBP segment attribute B. SUB EAX,EAX .s60:PUSH EAX BufferNew [%RecBuf],1+2 ; ACBP+word segment size. MOV EDI,EAX MOV EAX,ECX STOSB ; Store ACBP attribute. POP EAX STOSW ; Store 16bit segment length. .s70:; Common continuation for 16bit and 32bit segments. MOV EDX,[EBX+SSS.NameIndex] Invoke PfomfStoreIndex,[%RecBuf],EDX MOV ECX,[EBX+SSS.ClassSize] MOV EAX,1 JECXZ .s80: ; If segment class is empty, store ClassIndex=1, ADD EAX,EDX ; otherwise store NameIndex+1. .s80:Invoke PfomfStoreIndex,[%RecBuf],EAX Invoke PfomfStoreIndex,[%RecBuf],0 ; OverlayIndex is not used. MOV AL,SEGDEF JSt [EBX+SSS.Status],sssWidth16,.s85: MOV AL,SEGDEF32 .s85:Invoke PfomfStoreRecord,[%OutputStream],EAX,[%RecBuf] .s90:POP ECX DEC ECX JNZ .s10: ; The next segment. .s99:RET ENDP PfomfStoreModule.SEGDEF: PfomfStoreModule.GRPDEF: PROC ; Segment group definitions are stored to GRPDEF record(s). MOVD [%GrpIndex],0 MOV EDX,[%Pgm] BufferRetrieve [EDX+PGM.SegOrdBuffer] SHR ECX,2 JZ .g90: .g10: LODSD PUSH ECX MOV EBX,EAX JNSt [EBX+SSS.Status],sssGroup,.g80: MOV ECX,[%GrpIndex] ; Create GRPDEF record for the group EBX. INC ECX MOV [%GrpIndex],ECX MOV [EBX+SSS.SegmIndex],ECX Invoke PfomfStoreIndex,[%RecBuf],[EBX+SSS.NameIndex] MOV EDX,[%Pgm] ListGetFirst [EDX+PGM.SssList] ; Find segments of the group EBX. JZ .g60: .g20:MOV EDX,EAX JNSt [EDX+SSS.Status],sssSegment,.g50: CMP [EDX+SSS.GroupPtr],EBX JNE .g50: ; Skip if this segment does not belong to group EBX. BufferStoreByte [%RecBuf],0xFF ; Grouptype field, always 0xFF. Invoke PfomfStoreIndex,[%RecBuf],[EDX+SSS.SegmIndex] .g50:ListGetNext EDX JNZ .g20: .g60:Invoke PfomfStoreRecord,[%OutputStream],GRPDEF,[%RecBuf] .g80:POP ECX DEC ECX JNZ .g10: .g90:RET ENDP PfomfStoreModule.GRPDEF: PfomfStoreModule.EXTDEF:PROC ; Extern symbols definitions. MOVD [%ExtIndex],0 MOV EDX,[%Pgm] ListGetFirst [EDX+PGM.SymList] ; Enumerate program symbols. JZ .e9: .e1:MOV EBX,EAX JNSt [EBX+SYM.Status],symExtern|symImport,.e8: JSt [EBX+SYM.Status],symResolved,.e8: MOV ESI,[EBX+SYM.Section] MOV ECX,[%ExtIndex] ; Create EXTDEF record for the external pseudosegment ESI. INC ECX MOV [%ExtIndex],ECX MOV [ESI+SSS.SegmIndex],ECX MOV EDI,[EBX+SYM.InterNamePtr] MOV EDX,[EBX+SYM.InterNameSize] TEST EDX JNZ .e5: MOV EDI,[EBX+SYM.NamePtr] MOV EDX,[EBX+SYM.NameSize] MOV [EBX+SYM.InterNamePtr],EDI MOV [EBX+SYM.InterNameSize],EDX .e5:MOV [ESI+SSS.NamePtr],EDI MOV [ESI+SSS.NameSize],EDX Invoke PfomfStoreName,[%RecBuf],EDI,EDX ; Pascal-string name of external symbol. Invoke PfomfStoreIndex,[%RecBuf],0 ; Symbol CodeView datatype is not used. Invoke PfomfStoreRecord,[%OutputStream],EXTDEF,[%RecBuf] ; Flush extern symbols from %RecBuf. .e8:ListGetNext EBX JNZ .e1: ; The next symbol. .e9:RET ENDP PfomfStoreModule.EXTDEF: PfomfStoreModule.PUBDEF16:PROC ; Public 16bit symbols definitions. MOV EDX,[%Pgm] ListGetFirst [EDX+PGM.SymList] ; Enumerate program symbols. JZ .p9: .p1:MOV EBX,EAX JNSt [EBX+SYM.Status],symPublic|symExport,.p8: MOV EDX,[EBX+SYM.OffsetHigh] MOV EAX,[EBX+SYM.OffsetLow] TEST EDX JNZ .p8: ; Skip 64bit symbol. TEST EAX,0xFFFF_0000 JNZ .p8: ; Skip 32bit symbol. MOV ECX,[EBX+SYM.Section] JECXZ .p2: MOV ECX,[ECX+SSS.SegmPtr] JECXZ .p2: MOV ECX,[ECX+SSS.SegmIndex] .p2:Invoke PfomfStoreIndex,[%RecBuf],0 ; Base group index. Invoke PfomfStoreIndex,[%RecBuf],ECX ; Base segment index. TEST ECX JNZ .p3: ; Skip base frame when base segment is defined. BufferStoreWord [%RecBuf],0 ; Base frame when segment=0. .p3:MOV EDI,[EBX+SYM.NamePtr] MOV EDX,[EBX+SYM.NameSize] Invoke PfomfStoreName,[%RecBuf],EDI,EDX BufferStoreWord [%RecBuf],[EBX+SYM.OffsetLow] Invoke PfomfStoreIndex,[%RecBuf],0 ; Symbol CodeView datatype is not used. Invoke PfomfStoreRecord,[%OutputStream],PUBDEF,[%RecBuf] ; Write PUBDEF record. .p8:ListGetNext EBX JNZ .p1: .p9:RET ENDP PfomfStoreModule.PUBDEF16: PfomfStoreModule.PUBDEF32:PROC ; Public 32bit symbols definitions. MOV EDX,[%Pgm] ListGetFirst [EDX+PGM.SymList] ; Enumerate program symbols. JZ .p9: .p1:MOV EBX,EAX JNSt [EBX+SYM.Status],symPublic|symExtern,.p8: MOV EDX,[EBX+SYM.OffsetHigh] MOV EAX,[EBX+SYM.OffsetLow] TEST EDX Msg cc=NZ,'8527',EBX ; Offset of public symbol "!1S" exceeded 4 GB, not suported in OMF. JNZ .p8: ; Skip 64bit symbol. TEST EAX,0xFFFF_0000 JZ .p8: ; Skip 16bit symbol (it was already exported in .PUBDEF16. SUB EDI,EDI ; Base group index if symbol is in no group. MOV ECX,[EBX+SYM.Section] JECXZ .p2: MOV ECX,[ECX+SSS.SegmPtr] JECXZ .p2: MOV ECX,[ECX+SSS.SegmIndex] .p2:Invoke PfomfStoreIndex,[%RecBuf],0 ; Base group index. Invoke PfomfStoreIndex,[%RecBuf],ECX ; Base segment index. TEST ECX JNZ .p3: ; Skip base frame when base segment is defined. BufferStoreWord [%RecBuf],0 ; Base frame when segment=0 .p3:MOV EDI,[EBX+SYM.NamePtr] MOV EDX,[EBX+SYM.NameSize] Invoke PfomfStoreName,[%RecBuf],EDI,EDX BufferStoreDword [%RecBuf],[EBX+SYM.OffsetLow] Invoke PfomfStoreIndex,[%RecBuf],0 ; Symbol CodeView datatype is not used. Invoke PfomfStoreRecord,[%OutputStream],PUBDEF32,[%RecBuf] ; Write PUBDEF record. .p8:ListGetNext EBX JNZ .p1: .p9:RET ENDP PfomfStoreModule.PUBDEF32: PfomfStoreModule.MODEND:PROC ; Module end marker, entry definition. MOV EDX,[%Pgm] LEA EDI,[EDX+PGM.EntryExp] MOV ECX,[EDX+PGM.Pgmopt.EntrySize] JECXZ .e0: Invoke PgmEvalEntry::,EDX Invoke ExpReportError::,EDI JC .NoEntry: ; On error emit no entry. .e0: MOV ECX,[EDI+EXP.Status] LEA EBX,[EDI+EXP.Low] ; EBX is now pointer to the displacement. JECXZ .NoEntry: Dispatch CL,'A','N','F' ; EDI is valid expression with program entry. LEA EAX,[EDX+PGM.Pgmopt.EntryPtr] ; Prepare error Msg !1S argument. Msg '7711',EAX ; Invalid program entry point "!1S". .NoEntry: BufferClear [%RecBuf] ; Remove any data when ENTRY is absent or wrong and should be aborted. BufferStoreByte [%RecBuf],0 ; Module type=0. JMP .e7: .F: ; Entry is specified as immediate far pointer, e.g. ENTRY=0x0040:1234h. MOV ECX,[EDI+EXP.Seg] .F1:Msg '2921',EAX ; Nonrelocable entry point "!1S" is not supported by many linkers. BufferNew [%RecBuf],6 MOVW [EAX+0],0x33C1 ; Module type C1,F3,T3,explicit frame segment value with displacement. MOV [EAX+2],CX ; Explicit frame segment value. MOV [EAX+4],CX ; Explicit target segment value. MOV EAX,[EBX] ; Displacement (entry offset). TEST EAX,0xFFFF_0000 JNZ .e6: ; 32bit displacement. JMP .e7: ; 16bit displacement. .N: ; Entry is specified as absolute offset (no segment), e.g. ENTRY=100h. SUB ECX,ECX JMP .F1: .A: ; Entry is specified as a symbol, e.g. ENTRY=Start: BufferNew [%RecBuf],2 MOVB [EAX+0],0xC1 ; Module type. MOV ESI,[EDI+EXP.Seg] ; Section or segment of entry point. MOV ECX,[ESI+SSS.GroupPtr] JECXZ .e2: ; Entry is in a grouped segment. MOVB [EAX+1],0x10 ; FixData F1,T0,displacement. Invoke PfomfStoreIndex,[%RecBuf],[ECX+SSS.SegmIndex] ; Frame group. Invoke PfomfStoreIndex,[%RecBuf],[ESI+SSS.SegmIndex] ; Target segment. JMP .e6: ; When GROUP is used, DWORD displacement is not supported. .e2: ; Entry is in nongrouped segment. MOVB [EAX+1],0x00 ; FixData F0,T0,displacement. JSt [ESI+SSS.Status],sssSegment,.e3: LEA EAX,[EDX+PGM.Pgmopt.EntryPtr] ; Prepare error Msg !1S argument. Msg '7713',EAX ; Unresolved external entry point "!1S". Ignored. JMP .NoEntry: .e3:Invoke PfomfStoreIndex,[%RecBuf],[ESI+SSS.SegmIndex] ; Frame segment. Invoke PfomfStoreIndex,[%RecBuf],[ESI+SSS.SegmIndex] ; Target segment. .e4:JSt [ESI+SSS.Status],sssWidth16, .e6: BufferStore [%RecBuf],EBX,4 ; DWORD displacement. JMP .e7: .e6:BufferStore [%RecBuf],EBX,2 ; WORD displacement. .e7:JNSt [EDX+PGM.Status],pgmIsModule,.e9: BufferRetrieve [%RecBuf] ; MODEND will padd the module to OWORD. StreamGetSize [%OutputStream] ; Let EAX=bytes emitted so far. LEA EAX,[EAX+ECX+4] NEG EAX MOV ECX,0x0000_000F AND ECX,EAX ; Size of OWORD alignment stuff. JZ .e9: .e8:BufferStoreByte [%RecBuf],0 LOOP .e8: .e9:JNSt [EDX+PGM.Pgmopt.Status],pgmoptWidth32,.eA: Invoke PfomfStoreRecord,[%OutputStream],MODEND32,[%RecBuf] RET .eA:Invoke PfomfStoreRecord,[%OutputStream],MODEND,[%RecBuf] RET ENDP PfomfStoreModule.MODEND:
PfomfLoadName Procedure NameBuf, IndexPtr, Pgm MOV ESI,[%IndexPtr] SUB EAX,EAX MOV [%ReturnEAX],EAX MOV [%ReturnECX],EAX LODSB TEST AL,80h JZ .20: XOR AL,80h XCHG AH,AL LODSB .20: MOV [%ReturnESI],ESI TEST EAX JZ .90: ; Index 0 represents no name. BufferRetrieve [%NameBuf] SHR ECX,2 CMP EAX,ECX JA .90: ; If wrong index. DEC EAX MOV ESI,[ESI+4*EAX] SUB EAX,EAX LODSB ; Pascal string size. MOV ECX,EAX JECXZ .90: MOV EDX,[%Pgm] PoolNew [EDX+PGM.Pool],ECX MOV [%ReturnEAX],EAX MOV [%ReturnECX],ECX XCHG EAX,EDI REP MOVSB .90: EndProcedure PfomfLoadName
PfomfLoadRecord Procedure RecPtr, FileStart, FileEnd, FNptr MOV ESI,[%RecPtr] MOV ECX,[%FileEnd] MOV [%ReturnESI],ESI SUB ECX,ESI JZ .20: JB .E8532: CMP ECX,4 JB .E8532: MOVZXW ECX,[ESI+1] ADD ECX,3 ; Brutto record size. .20:MOV [%ReturnECX],ECX JECXZ .90: LEA EDX,[ESI+ECX] CMP EDX,[%FileEnd] JA .E8532: DEC ECX ; Omit the checksum byte. MOV AH,[ESI+ECX] ; Load checksum byte. TEST AH JZ .90: ; Checksum 0 is tolerated. .50:LODSB ADD AH,AL LOOP .50: TEST AH JZ .90: ; Checksum is OK. .E8532: MOV ESI,[%RecPtr] MOV AL,[ESI] SUB ESI,[%FileStart] MOV ECX,[%FNptr] JECXZ .80: Msg '8532',EAX,ECX,ESI ; Wrong checksum of OMF record type !1Bh at "!2$"[!3Hh]. .80:STC .90:EndProcedure PfomfLoadRecord
PfomfLoadSegment Procedure SegdefBuf, IndexPtr MOV ESI,[%IndexPtr] SUB EAX,EAX MOV [%ReturnEAX],EAX LODSB TEST AL,80h JZ .20: XOR AL,80h XCHG AH,AL LODSB .20: MOV [%ReturnESI],ESI TEST EAX STC JZ .90: ; Index 0 represents no segment. BufferRetrieve [%SegdefBuf] SHR ECX,2 CMP ECX,EAX JC .90: ; If wrong index. DEC EAX MOV EDX,[ESI+4*EAX] MOV [%ReturnEAX],EDX CLC .90:EndProcedure PfomfLoadSegment
PfomfLoadGroup Procedure GrpdefBuf, IndexPtr MOV ESI,[%IndexPtr] SUB EAX,EAX MOV [%ReturnEAX],EAX LODSB TEST AL,80h JZ .20: XOR AL,80h XCHG AH,AL LODSB .20: MOV [%ReturnESI],ESI TEST EAX STC JZ .90: ; Index 0 represents no group. BufferRetrieve [%GrpdefBuf] SHR ECX,2 CMP ECX,EAX JC .90: ; If wrong index. DEC EAX MOV EDX,[ESI+4*EAX] MOV [%ReturnEAX],EDX CLC .90:EndProcedure PfomfLoadGroup
PfomfLoadExtern Procedure ExtdefBuf, IndexPtr MOV ESI,[%IndexPtr] SUB EAX,EAX MOV [%ReturnEAX],EAX LODSB TEST AL,80h JZ .20: XOR AL,80h XCHG AH,AL LODSB .20: MOV [%ReturnESI],ESI TEST EAX STC JZ .90: ; Index 0 represents no group. BufferRetrieve [%ExtdefBuf] SHR ECX,2 CMP ECX,EAX JC .90: ; If wrong index. DEC EAX MOV EDX,[ESI+4*EAX] MOV [%ReturnEAX],EDX CLC .90:EndProcedure PfomfLoadExtern
RELOC.Symbol, .Frame, .Addend
in relocation record..Symbol, .Addend
.
PfomfLoadFixData Procedure FixDataPtr, RelocPtr, ThreadTabPtr, LastSegPtr,SegdefBuffer, GrpdefBuffer, ExtdefBuffer, Status32
MOV ESI,[%FixDataPtr]
MOV EDX,[%RelocPtr]
MOV EBX,[%ThreadTabPtr]
LODSB ; AL=FixData byte.
SUB ECX,ECX
; Find the frame.
TEST AL,1000_0000b ; FixData.F bit specifies the thread.
JZ .10:
; F=1, frame is specified by previous frame thread at EBX.
MOV CL,0011_0000b ; Isolate thread number.
AND CL,AL
SHR ECX,2
MOV EDI,[EBX+0+ECX] ; Pointer to the segment refered by frame thread ECX.
JMP .30:
.10: ; F=0, frame is specified by method F0..F5 in this subrecord.
MOV CL,0111_0000b
AND CL,AL
XCHG EAX,EDI ; Temporary save FixData AL.
Dispatch CL,pfomfFxF5,pfomfFxF0,pfomfFxF1,pfomfFxF2,pfomfFxF3,pfomfFxF4
JMP .Error:
.pfomfFxF0:Invoke PfomfLoadSegment,[%SegdefBuffer],ESI ; Frame is specified by SEGDEF index.
JMP .20:
.pfomfFxF1:Invoke PfomfLoadGroup,[%GrpdefBuffer],ESI ; Frame is specified by GRPDEF index.
JMP .20:
.pfomfFxF2:Invoke PfomfLoadExtern,[%ExtdefBuffer],ESI ; Frame is specified by EXTDEF index.
JMP .20:
.pfomfFxF4:MOV EAX,[%LastSegPtr] ; Frame is specified by previous LEDATA segment.
JMP .20:
.pfomfFxF3:LODSW ; Frame is specified by an absolute PARA address. Not supported.
JMP .20:
.pfomfFxF5:XOR EAX,EAX ; Zero signalizes that the frame is identical with target.
.20: XCHG EDI,EAX ; Move the loaded frame segment to EDI, restore FixData to AL.
JC .Error: ; If wrong index (PfomfLoad* failed).
.30: TEST EDI
JZ .35: ; Skip when frame=0, i.e. specified by the target.
JNSt [EDI+SSS.Status],sssExtern,.35:
MOV EDI,[EDI+SSS.SymPtr]
MOV [EDX+RELOC.Symbol],EDI
XOR EDI,EDI
.35: ;;;;;;;; MOV [EDX+RELOC.Frame],EDI ; Frame is now specified.
; Find the target.
TEST AL,0000_1000b
JZ .40:
; T=1, target is specified by the previous target thread.
MOV CL,0000_0011b ; Target field.
AND CL,AL ; ECX is now target thread number 0..3.
MOV EDI,[EBX+16+4*ECX] ; Pointer to the segment referred by target thread ECX.
JMP .60:
.40: ; T=0, target is specified by method T0..T6 in this subrecord.
MOV CL,00000_011b ; Target method mask pfomfFxT0..pfomfFxT3
.
AND CL,AL
XCHG EDI,EAX ; Temporary save FixData to EDI.
Dispatch CL,pfomfFxT0,pfomfFxT1,pfomfFxT2
JMP .Error: ; If wrong method.
.pfomfFxT0:Invoke PfomfLoadSegment,[%SegdefBuffer],ESI ; Target is specified by SEGDEF index.
JMP .50:
.pfomfFxT1:Invoke PfomfLoadGroup,[%GrpdefBuffer],ESI ; Target is specified by GRPDEF index.
JMP .50:
.pfomfFxT2:Invoke PfomfLoadExtern,[%ExtdefBuffer],ESI ; Target is specified by EXTDEF index.
;JMP .50:
.50: XCHG EAX,EDI ; Move the loaded target segment to EDI, restore FixData to AL.
JC .Error: ; If wrong index (PfomfLoad* failed).
.60: ;;;MOV [EDX+RELOC.Frame],EDI ; Frame of target segment is now specified. FixData is in AL.
MOV EDI,[EDI+SSS.SymPtr]
MOV [EDX+RELOC.Symbol],EDI
TEST AL,0000_0100b
MOV EAX,0
JNZ .80: ; If P=1, no displacement is present. RELOC.Addend=0.
; Load the target displacement (signed WORD or DWORD at ESI).
JSt [%Status32],1,.70:
LODSW ; Displacement is a signed WORD in 16bit OMF.
MOVSX EAX,AX
JMP .80:
.Error:STC
JMP .90:
.70: LODSD ; Displacement is a signed DWORD in 32bit OMF.
.80: JNSt [EDX+RELOC.Status],relocRel,.85:
SUB EAX,2 ; IP-relative relocation OMF correction.
JNSt [%Status32],1,.85:
SUB EAX,2 ; EIP-relative relocation OMF correction.
.85: MOV EDI,EDX
CDQ
MOV [EDI+RELOC.AddendLow],EAX
MOV [EDI+RELOC.AddendHigh],EDX
.90: MOV [%ReturnESI],ESI ; ESI points behind the target's displacement.
EndProcedure PfomfLoadFixData
pfomfRecLi32
whether the RepeatCount is 16bit or 32bit.PfomfLoadDataBlock Procedure DbStart,DbPtr,DbEnd,OutEmitBuffer,InpRelocBuffer,OutRelocBuffer,StatusPtr RepeatCount LocalVar ; DataBlock members. BlockCount LocalVar DataStart LocalVar ; Pointer to netto data inside DataBlock (inside LIDATA record mapped in memory). DataSize LocalVar DataEnd LocalVar DbOutEmitBuf LocalVar ; Temporary local buffers. DbInpRelocBuf LocalVar DbOutRelocBuf LocalVar EaStackCheck Invoke EaBufferReserve::,PfomfLoadDataBlock MOV [%DbOutEmitBuf],EAX Invoke EaBufferReserve::,PfomfLoadDataBlock MOV [%DbInpRelocBuf],EAX Invoke EaBufferReserve::,PfomfLoadDataBlock MOV [%DbOutRelocBuf],EAX MOV ESI,[%DbPtr] MOV EDX,[%DbEnd] SUB EAX,EAX SUB EDX,ESI CMP EDX,5 JNA .Error: JSt [%StatusPtr],pfomfRecLi32,.10: LODSW JMP .15: .10:LODSD .15:MOV [%RepeatCount],EAX TEST EAX JZ .Error: SUB EAX,EAX LODSW MOV [%BlockCount],EAX TEST EAX JNZ .70: ; BlockCount=0. It is final DataBlock. Pascal data string follows. LODSB MOV [%DataStart],ESI MOV [%DataSize],EAX ADD EAX,ESI MOV [%DataEnd],EAX ; ESI..EAX specifies netto data in LIDATA record, perhaps subjected to fixup. MOV [%ReturnESI],EAX ; Inspect whether origin of some relocation(s) in %InpRelocBuffer concerns our netto data %DataStart..%DataEnd ; and copy such relocations to %DbInpRelocBuf. BufferRetrieve [%InpRelocBuffer] JECXZ .50: .20:MOV EAX,[ESI+RELOC.OrgLow] ; Related to %DbStart. ADD EAX,[%DbStart] CMP EAX,[%DataStart] JB .40: ; Skip this relocation. ADD EAX,2 JNSt [ESI+RELOC.Status],relocWidth32,.30: ADD EAX,2 .30:CMP EAX,[%DataEnd] JA .40: ; Skip this relocation. ; Relocation ESI concerns this DataBlock. BufferStore [%DbInpRelocBuf],ESI,SIZE#RELOC .40:ADD ESI,SIZE#RELOC SUB ECX,SIZE#RELOC JA .20: ; If more than one LIDATA relocation exist. .50: ; Relevant relocation(s) were copied to %DbInpRelocBuf. MOV EAX,[%DbStart] SUB EAX,[%DataStart] Invoke RelocRelocInBuffer::,[%DbInpRelocBuf],EAX ; Origins are now related to the start of netto data. .60:; Loop to duplicate emit and reloc. BufferStore [%DbOutEmitBuf],[%DataStart],[%DataSize] BufferRetrieve [%DbInpRelocBuf] BufferStore [%DbOutRelocBuf],ESI,ECX Invoke RelocRelocInBuffer::,[%DbInpRelocBuf],[%DataSize] ; Prepare RELOC.Org for the next RepeatCount. DECD [%RepeatCount] JNZ .60: ; Export emitted data and relocations. BufferRetrieve [%OutEmitBuffer] MOV EDX,ECX ; Parent Db emitted size. Invoke RelocRelocInBuffer::,[%DbOutRelocBuf],EDX ; Relocate our relocation(s). BufferRetrieve [%DbOutEmitBuf] ; Our emitted data. BufferStore [%OutEmitBuffer],ESI,ECX ; Append to parent's. BufferRetrieve [%DbOutRelocBuf] BufferStore [%OutRelocBuffer],ESI,ECX ; Append our relocations to parent's. JMP .90: ; CF=0. .Error: MOV ESI,[%DbEnd] MOV [%ReturnESI],ESI STC JMP .90: .70: ; BlockCount > 0. Another DataBlocks follow at ESI. Invoke PfomfLoadDataBlock,[%DbStart],ESI,[%DbEnd],[%DbOutEmitBuf],[%InpRelocBuffer],[%DbInpRelocBuf],[%StatusPtr] JC .Error: DECD [%BlockCount] JNZ .70: .80:; Start to duplicate emit and reloc RepeatCount times. BufferRetrieve [%DbOutEmitBuf] MOV EDX,ECX ; DataBlock emitted size. BufferStore [%OutEmitBuffer],ESI,ECX BufferRetrieve [%DbInpRelocBuf] BufferStore [%OutRelocBuffer],ESI,ECX Invoke RelocRelocInBuffer::,[%DbInpRelocBuf],EDX ; Prepare relocations for the next repeat. DECD [%RepeatCount] JNZ .80: .90:PUSHFD Invoke EaBufferRelease::,[%DbOutEmitBuf] Invoke EaBufferRelease::,[%DbInpRelocBuf] Invoke EaBufferRelease::,[%DbOutRelocBuf] POPFD EndProcedure PfomfLoadDataBlock
Pgm.ModulePgmList
and marked as pgmUsed
.
The actual job is performed by PfomfLoadModule, a common procedure used by PflibomfLoadPgm and PfomfLoadPgm.
BasePgm.ModulePgmList
.
PfomfLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
MOV EBX,[%BasePgm]
MOV ESI,[%ObjBegin]
MOV ECX,[%ObjSize]
LEA EDX,[ESI+ECX]
Invoke PfomfLoadModule,EBX,ESI,ESI,EDX,[%FileNamePtr],pgmoptOMF
JZ .90:
; Unlike library modules from format LIBOMF, object files in format OMF explicitly requested with
; LINK "file.obj"
will be always selected, i.e. statically linked to BasePgm.
SetSt [EAX+PGM.Status],pgmSelected
; If the module width was not specified, it will be copied from its regular segments.
MOV EDX,pgmoptWidthMask
AND EDX,[EAX+PGM.Pgmopt.Status]
JNZ .90:
ListGetFirst [EAX+PGM.SssList]
JZ .90:
.50:JNSt [EAX+SSS.Status],sssSegment,.70:
JNSt [EAX+SSS.Purpose],sssPurposeRegular,.70:
MOV ECX,sssWidthMask
AND ECX,[EAX+SSS.Status]
SetSt [EBX+PGM.Pgmopt.Status],ECX
.70:ListGetNext EAX
JNZ .50:
.90:EndProcedure PfomfLoadPgm
BaseProgram.ModulePgmList
. The module starts with THEADR or LHEADR record
and it terminates with MODEND record.BaseProgram.ModulePgmList
.PfomfLoadModule Procedure BaseProgram, FileBegin, ModBegin, ModEnd, FileName$, Format ModPtr LocalVar ; Pointer to the next OMF record. RecPtr LocalVar ; Pointer to the currently processed OMF record. DataPtr LocalVar ; Pointer to the volatile LEDATA data withing the record. DataSize LocalVar ; Size of data at %DataPtr. DataOffs LocalVar ; Pointer to the recent LEDATA data within the EmitBuffer. LastSegm LocalVar ; Pointer to the recent SSS segment of LEDATA. NamePtr LocalVar ; Pointer to the recent symbol name. NameSize LocalVar ; Size of the recent symbol name. DllNamePtr LocalVar ; Pointer to the recent DLL name. DllNameSize LocalVar ; Size of the recent DLL name. InterNamePtr LocalVar ; Pointer to the recent internal import name. InterNameSize LocalVar ; Size of the recent internal import name. OrdinalNr LocalVar ; Ordinal number if imported symbol or 0 when imported by name. LnamesBuf LocalVar ; Pointer to BUFFER with dword pointers to Pascal string with SSS name (volatile). SegdefBuf LocalVar ; Pointer to BUFFER with dword pointers to SSS segments located on program pool. GrpdefBuf LocalVar ; Pointer to BUFFER with dword pointers to SSS groups located on program pool. ExtdefBuf LocalVar ; Pointer to BUFFER with dword pointers to SSS externs located on program pool. LiOutEmitBuf LocalVar ; Pointer to BUFFER with expanded LIDATA data. LiInpRelocBuf LocalVar ; Pointer to BUFFER with relocations in %LiInpEmitBuf. LiOutRelocBuf LocalVar ; Pointer to BUFFER with relocations in %LiOutEmitBuf. LiDbStart LocalVar ; Pointer to the data block in LIDATA record. LiDbEnd LocalVar ; Pointer to the end of data block in LIDATA record (to the checksum byte). LdataOffs LocalVar ; 10bit offset or relocation within LEDATA netto data or within LIDATA DataBlock. OmfStatus LocalVar ; Binary flags, see PfomfEnc. Sss LocalVar Size=SIZE#SSS ; Currently processed segment or group of linked program. Reloc LocalVar Size=SIZE#RELOC ; Currently processed relocation. Sym LocalVar Size=SIZE#SYM ; Currently processed symbol of linked program. ModulePgm LocalVar Size=SIZE#PGM ; Currently processed linked program in the form of PGM object. ThreadTab LocalVar Size=SIZE#PFOMF_THREAD_TABLE ; Frame and target fixup threads 0..3. ; Initialize local data structures ClearLocalVar SUB EAX,EAX MOV [%ReturnEAX],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%LnamesBuf],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%SegdefBuf],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%GrpdefBuf],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%ExtdefBuf],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%LiOutEmitBuf],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%LiInpRelocBuf],EAX Invoke EaBufferReserve::,PfomfLoadModule MOV [%LiOutRelocBuf],EAX MOV ESI,[%ModBegin] MOV [%ModPtr],ESI ; Preinitialize loaded module (PGM object). It will inherit some properties ; from %BaseProgram rather than initializing the whole PGM structure with PgmCreate. LEA EDI,[%ModulePgm] MOV EBX,[%BaseProgram] MOV EDX,[EBX+PGM.Pool] MOV [EDI+PGM.Pool],EDX ListCreate EDX,SIZE#SYM MOV [EDI+PGM.SymList],EAX ListCreate EDX,SIZE#SSS MOV [EDI+PGM.SssList],EAX MOV ESI,[%Format] Invoke PgmoptSetLinkProp::,ESI CMP ESI,pgmoptOMF JE .05: ; Do not set pgmoptLibMember when PfomfLoadModule was SetSt EAX,pgmoptLibMember ; invoked by PfomfLoadPgm (and not by PfomflibLoadPgm). .05:MOV [EDI+PGM.Pgmopt.Status],EAX MOV ESI,[%ModBegin] MOV [%ModPtr],ESI ; OMF record to start with. .NextRecord: ; The main loop: read and handle OMF records. MOV EBX,[%BaseProgram] MOV ESI,[%ModPtr] MOV [%RecPtr],ESI Invoke PfomfLoadRecord, ESI,[%FileBegin],[%ModEnd],[%FileName$] JC .80: ; Abort if the file is invalid. ADD [%ModPtr],ECX ; Prepare %ModPtr for the next OMF record. JNSt [%OmfStatus],pfomfLiPending,.20: JECXZ .10: ; Previous LIDATA record needs expansion, even at the end of module. MOV AL,[ESI] ; Type of just loaded OMF record. CMP AL,FIXUPP JE .20: CMP AL,FIXUPP32 JE .20: ; Do not expand LIDATA while they are followed by their fixups. .10:PUSH ECX,ESI CALL .ExpandLIDATA: POP ESI,ECX RstSt [%OmfStatus],pfomfLiPending .20:TEST ECX ; OMF record brutto size. JZ .70: ; End of module. SUB ECX,4 ; Omit record type, length, checksum. ECX=0 when the record is empty. JB .90: ; Abandon wrong object file. SUB EAX,EAX LODSB ; Record type. ADD ESI,2 ; Skip the record size (it was already processed by PfomfLoadRecord). LEA EDI,[%ModulePgm] Dispatch AL,LNAMES,EXTDEF,LEDATA,LEDATA32,FIXUPP,FIXUPP32,SEGDEF,SEGDEF32,PUBDEF,PUBDEF32, \ GRPDEF,COMENT,THEADR,LHEADR,LIDATA,LIDATA32,MODEND,MODEND32 JMP .NextRecord: ; Silently ignore other record types. ; Record handlers input: ; EBX=^%BaseProgram, ; EDI=^%ModulePgm (linked program), ; ESI=pointer to the record body (%RecPtr+3), ; ECX=record body netto size (may be 0), ; EAX=record type in PfomfRecTypes encoding. ; Handlers may destroy any GPR but EBP. They continue with .NextRecord or abort with .E8533. .LHEADR: .THEADR: ; ESI,ECX is Pascal string with module name. JECXZ .NextRecord: LODSB ; Pascal string size. DEC ECX CMP EAX,ECX JA .h2: MOV ECX,EAX .h2: PoolStore [EDI+PGM.Pool],ESI,ECX MOV [EDI+PGM.NamePtr],EAX MOV [EDI+PGM.NameSize],ECX JMP .NextRecord: .COMENT: CMP ECX,2 JNA .NextRecord: INC ESI ; Ignore COMENT type flags (purge, list). LODSB Dispatch AL,0x9D,0xA0 ; Comment class. JMP .NextRecord: ; Ignore other comment classes. .0xA0: ; COMENT class A0 - OMF extensions. LODSB ; OMF extension number. Dispatch AL,0n1,0n2 ; Using alternative number notation to avoid conflict in labels. JMP .NextRecord: ; Ignore other extensions. .0n1: ; COMENT class A0 extension 1 - IMPDEF. ; Import definition creates symImport in the module EDI. RstSt [%OmfStatus],pfomfByOrdinal XOR EAX,EAX MOV [%OrdinalNr],EAX ; First assume import by name. LODSB ; A byte which specifies the kind of import(ByOrdinal/ByName). TEST AL JZ .i1: SetSt [%OmfStatus],pfomfByOrdinal .i1:LODSB MOVZX ECX,AL ; ESI,ECX is now volatile internal imported symbol name, e.g. "__imp_Function". MOV [%InterNamePtr],ESI MOV [%InterNameSize],ECX MOV [%NamePtr],ESI ; Prepare for the case when name === internal name. MOV [%NameSize],ECX ADD ESI,ECX LODSB MOVZX ECX,AL ; ESI,ECX is now library name e.g. "kernel32.dll". MOV [%DllNamePtr],ESI MOV [%DllNameSize],ECX ADD ESI,ECX ; ESI now points to the symbol name or to a word with ordinal number. JNSt [%OmfStatus],pfomfByOrdinal,.i2: LODSW MOV [%OrdinalNr],EAX INC ESI ; Skip record checksum. CMP ESI,[%ModPtr] ; ESI should be at the end of record. JE .i5: .E8533:MOV ESI,[%RecPtr] ; Abort linking due to error in file. MOV CL,[ESI] SUB ESI,[%FileStart] ; Get the file address of bad record. Msg '8533',ECX,[%FileName$],ESI ; Invalid OMF record type !1Bh at "!2$"[!3Hh]. JMP .80: ; Abort file load. .i2:; ESI now points to imported Pascal name. LODSB MOVZX ECX,AL ; ESI,ECX is now symbol name e.g. "Function". Or is is NULL (identical with InterName). JECXZ .i3: CMP AL,1 JNE .i4: CMP [ESI],CH ; Is the first character NULL? JNE .i4: .i3:MOV ESI,[%InterNamePtr] MOV ECX,[%InterNameSize] .i4:MOV [%NamePtr],ESI MOV [%NameSize],ECX .i5:; Imported symbol will be stored to the module EDI. MOV ESI,[%NamePtr] MOV ECX,[%NameSize] Invoke SymFindByName::,symImport|symExtern,ESI,ECX,EDI MOV EBX,EAX JNC .i6: ; Symbol named ESI,ECX wasn't found in module. Let's store it there. ListNew [EDI+PGM.SymList],Zeroed=Yes MOV EBX,EAX PoolStore [EDI+PGM.Pool],ESI,ECX ; Make the new name nonvolatile. MOV [EBX+SYM.NamePtr],EAX MOV [EBX+SYM.NameSize],ECX MOV [EBX+SYM.InterNamePtr],EAX MOV [EBX+SYM.InterNameSize],ECX .i6:MOV ESI,[%InterNamePtr] MOV ECX,[%InterNameSize] JECXZ .i7: Compare [EBX+SYM.NamePtr],[EBX+SYM.NameSize],ESI,ECX JE .i7: PoolStore [EDI+PGM.Pool],ESI,ECX MOV [EBX+SYM.InterNamePtr],EAX MOV [EBX+SYM.InterNameSize],ECX .i7:JNSt [%OmfStatus],pfomfByOrdinal,.i8: SetSt [EBX+SYM.Status],symImportedByOrd MOV EAX,[%OrdinalNr] MOV [EDI+SYM.OrdinalNr],EAX .i8:MOV ESI,[%DllNamePtr] MOV ECX,[%DllNameSize] PoolStore [EDI+PGM.Pool],ESI,ECX ; Make the DLL name nonvolatile. MOV [EBX+SYM.DllNamePtr],EAX MOV [EBX+SYM.DllNameSize],ECX SetSt [EBX+SYM.Status],symImport+symUsed MOVB [EBX+SYM.Status],'A' Invoke SssCreateExtern::,EBX,EDI JMP .NextRecord: .0n2: ; COMENT class A0 extension 2 - EXPDEF. ; Export definition creates symExport in module EDI. RstSt [%OmfStatus],pfomfByOrdinal XOR EAX,EAX MOV [%OrdinalNr],EAX ; First assume import by name. LODSB ; A byte which specifies the kind of export(ByOrdinal/ByName). TEST AL,0x80 JZ .x1: SetSt [%OmfStatus],pfomfByOrdinal .x1:LODSB MOVZX ECX,AL ; ESI,ECX is now the volatile exported symbol name. MOV [%NamePtr],ESI MOV [%NameSize],ECX MOV [%InterNamePtr],ESI MOV [%InterNameSize],ECX ADD ESI,ECX LODSB MOVZX ECX,AL ; ESI,ECX is now the volatile internal name. JECXZ .x3: MOV [%InterNamePtr],ESI MOV [%InterNameSize],ECX .x3:ADD ESI,ECX JNSt [%OmfStatus],pfomfByOrdinal,.x4: LODSW MOV [%OrdinalNr],EAX .x4:INC ESI ; Skip record checksum. CMP ESI,[%ModPtr] ; ESI should be at the end of record. JNE .E8533: ; Otherwise abort linking due to error in file. ; Exported symbol will be stored to the module EDI. MOV ESI,[%NamePtr] MOV ECX,[%NameSize] Invoke SymFindByName::,symPublic|symExport,ESI,ECX,EDI ; It shouldn't be there. Msg cc=NC,'6611',EAX,[%FileName$],[EAX+SYM.LinePtr] ; Symbol "!1S" exported from "!2$" was already declared at !3@. ListNew [EDI+PGM.SymList],Zeroed=Yes ; Create new exported symbol in module EDI. MOV EBX,EAX PoolStore [EDI+PGM.Pool],ESI,ECX ; Make the new name nonvolatile. MOV [EBX+SYM.NamePtr],EAX MOV [EBX+SYM.NameSize],ECX MOV EAX,[%InterNamePtr] MOV ECX,[%InterNameSize] Compare [EBX+SYM.NamePtr],[EBX+SYM.NameSize],EAX,ECX JE .x6: PoolStore [EDI+PGM.Pool],EAX,ECX .x6:MOV [EBX+SYM.InterNamePtr],EAX MOV [EBX+SYM.InterNameSize],ECX .x7:MOV EAX,[%OrdinalNr] MOV [EBX+SYM.OrdinalNr],EAX SetSt [EBX+SYM.Status],symExport MOVB [EBX+SYM.Status],'A' JMP .NextRecord: .0x9D: ; COMENT class 9D - memory model. INC ESI,ESI SUB ECX,2 JNA .NextRecord: XOR EDX,EDX .c1:LODSB Dispatch AL,'s','m','c','l','h','f' LOOP .c1: JMP .NextRecord: .s: SetSt EDX,pgmoptSMALL JMP .c2: .m: SetSt EDX,pgmoptMEDIUM JMP .c2: .c: SetSt EDX,pgmoptCOMPACT JMP .c2: .l: SetSt EDX,pgmoptLARGE JMP .c2: .h: SetSt EDX,pgmoptHUGE JMP .c2: .f: SetSt EDX,pgmoptFLAT .c2:OR [EDI+PGM.Pgmopt+PGMOPT.Status],EDX JMP .NextRecord: .LNAMES: JECXZ .NextRecord: .n2:PUSH ESI ; Pointer to a Pascal string. MOV EAX,ESP BufferStore [%LnamesBuf],EAX,4 POP ESI SUB EAX,EAX LODSB ; Length of Pascal string. DEC ECX ADD ESI,EAX SUB ECX,EAX JNZ .n2: JMP .NextRecord: .SEGDEF32: SetSt [%OmfStatus],pfomfRec32 JMP .s0: .SEGDEF: RstSt [%OmfStatus],pfomfRec32 .s0:CMP ECX,6 JB .NextRecord: ; Record is too short, ignore. LEA EDX,[%Sss] Clear EDX,Size=SIZE#SSS LODSB ; Load segment attributes ACBP. JSt [%OmfStatus],pfomfRec32, .s1: TEST AL,0000_0010b ; Big segment size? JZ .s1: MOV [EDX+SSS.TopLow],0x0001_0000 .s1:MOV EDI,sssSegment+sssWidth32 TEST AL,0000_0001b ; USE32? JNZ .s2: MOV EDI,sssSegment+sssWidth16 .s2:MOV CL,000_111_00b AND CL,AL ; Field C - combine property. Dispatch CL,000_000_00b,000_101_00b,000_110_00b OR EDI,sssPublic JMP .s3: .000_000_00b: ; C=0 private. OR EDI,sssPrivate JMP .s3: .000_101_00b: ; C=5 stack. OR EDI,sssStack SetSt [EDX+SSS.Purpose],sssPurposeSTACK JMP .s3: .000_110_00b: ; C=6 common. OR EDI,sssCommon ;JMP .s3: .s3:SetSt [EDX+SSS.Status],EDI SHR EAX,5 ; Field A - alignment property. Dispatch AL,2,3,4,5,6 XOR EDI,EDI INC EDI ; Default segment alignment = BYTE. JMP .s4: .2: MOV EDI,2 ; WORD. JMP .s4: .3: MOV EDI,16 ; OWORD. JMP .s4: .4: MOV EDI,256 ; PAGE 256 bytes. JMP .s4: .5: MOV EDI,4 ; DWORD. JMP .s4: .6: MOV EDI,4K ; PAGE 4K bytes. ;JMP .s4: .s4:MOV [EDX+SSS.Alignment],EDI XOR EAX,EAX ; Load segment size. JSt [%OmfStatus],pfomfRec32,.s5: LODSW JMP .s6: .s5:LODSD .s6:MOV [EDX+SSS.TopLow],EAX Invoke PfomfLoadName,[%LnamesBuf],ESI,[%BaseProgram] ; Load segment name by index. MOV [EDX+SSS.NamePtr],EAX MOV [EDX+SSS.NameSize],ECX JECXZ .E8533: ; Name must not be empty. Invoke PfomfLoadName,[%LnamesBuf],ESI,[%BaseProgram] ; Load class name by index. MOV [EDX+SSS.ClassPtr],EAX MOV [EDX+SSS.ClassSize],ECX ; Invoke PfomfLoadName,[%LnamesBuf],ESI,[%BaseProgram] ; Overlay name index (ignored). LEA EDI,[%ModulePgm] MOV EBX,[EDI+PGM.Pool] MOV [EDX+SSS.PgmPool],EBX MOV ECX,[EDX+SSS.TopLow] ADD ECX,32 ; Estimate EmitBuffer size. BufferCreate EBX,Size=ECX MOV [EDX+SSS.EmitBuffer],EAX SAR ECX,1 ; Estimate RelocBuffer size. ADD ECX,32 BufferCreate EBX,Size=ECX MOV [EDX+SSS.RelocBuffer],EAX Invoke SssGuessPurpose::,EDX ListStore [EDI+PGM.SssList],EDX ; Save the segment into the loaded/imported module EDI. MOV [EAX+SSS.SegmPtr],EAX Invoke SymCreateSe::,EAX,EDI MOV [EAX+SSS.SegmPtr],EAX BufferStoreDword [%SegdefBuf],EAX JMP .NextRecord: .GRPDEF: LEA EDX,[%Sss] Clear EDX,Size=SIZE#SSS SetSt [EDX+SSS.Status],sssGroup+sssWidth16+sssPublic Invoke PfomfLoadName,[%LnamesBuf],ESI,[%BaseProgram] ; Load group name by index. MOV [EDX+SSS.NamePtr],EAX MOV [EDX+SSS.NameSize],ECX JECXZ .E8533: ; Name must not be empty. LEA EDI,[%ModulePgm] ListStore [EDI+PGM.SssList],EDX MOV [EAX+SSS.GroupPtr],EAX Invoke SymCreateSe::,EAX,EDI PUSH EAX MOV EAX,ESP BufferStore [%GrpdefBuf],EAX,4 POP EBX ; Ptr to the group on linked Pgm.SssList. .g2:MOV ECX,[%ModPtr] ; End of this record. SUB ECX,3 CMP ESI,ECX JA .NextRecord: LODSB ; Load 0xFF marker. CMP AL,0xFF JNE .g2: Invoke PfomfLoadSegment,[%SegdefBuf],ESI ; Load segment pointer by index. JC .E8533: MOV [EAX+SSS.GroupPtr],EBX ; Add the segment EAX to group EBX. JMP .g2: .EXTDEF: XOR EAX,EAX MOV [%DllNamePtr],EAX MOV [%DllNameSize],EAX .e1:MOV EAX,[%ModPtr] DEC EAX CMP ESI,EAX JNB .NextRecord: ; If there are no more external definitions in EXTDEF. LODSB ; External name size. MOVZX ECX,AL ; ESI,ECX is now and external symbol name or imported external symbol internal name. JECXZ .E8533: LEA EBX,[%ModulePgm] Invoke SymFindByName::,symExtern|symImport,ESI,ECX,EBX MOV EDX,EAX JNC .e4: ; Skip if external symbol already exists in loaded module. Invoke SymFindByInterName::,symExtern|symImport,ESI,ECX,EBX MOV EDX,EAX JNC .e4: CALL .ExternSymbolAndSegmentCreate: .e4:; EDX is now the extern symbol with name ESI,ECX. MOV EDI,[EDX+SYM.Section] ; Extern pseudosection was already stored in this module. ADD ESI,ECX ; Skip symExtern name in EXTDEF record. MOV EAX,[%OrdinalNr] MOV [EDX+SYM.OrdinalNr],EAX ; Update extern symbol in case it's defined within IMPDEF record. JSt [EDX+SYM.Status],symImport,.e6: MOV EAX,[%DllNamePtr] MOV ECX,[%DllNameSize] MOV [EDX+SYM.DllNamePtr],EAX MOV [EDX+SYM.DllNameSize],ECX .e6:PUSH EDI ; External pseudosection. MOV EAX,ESP BufferStore [%ExtdefBuf],EAX,4 ; Pointer to sssExtern. POP EDI .e9:LODSB ; Skip unused type index. TEST AL,0x80 JZ .e1: LODSB JMP .EXTDEF: ; More extern definitions may follow. .PUBDEF32: SetSt [%OmfStatus],pfomfRec32 JMP .p0: .PUBDEF: RstSt [%OmfStatus],pfomfRec32 .p0:CMP ECX,7 JB .NextRecord: ; Record is too short, ignore. LEA EDX,[%Sym] Clear EDX,Size=SIZE#SYM ; Public record creates symPublic. Invoke PfomfLoadGroup,[%GrpdefBuf],ESI ; Group is ignored. Invoke PfomfLoadSegment,[%SegdefBuf],ESI MOV [EDX+SYM.Section],EAX TEST EAX JNZ .p2: ADD ESI,2 ; Skip Base frame when the public symbol is at absolute segment. .p2:MOV EAX,[%ModPtr] ; The next OMF record. SUB EAX,6 CMP ESI,EAX JNB .NextRecord: ; If no more public definitions in the record. LODSB ; Public name size. MOVZXB ECX,AL ; ESI,ECX is now the public name. PoolStore [EDI+PGM.Pool],ESI,ECX ADD ESI,ECX ; ESI is now at the offset behind the symbol name. MOV [EDX+SYM.NamePtr],EAX MOV [EDX+SYM.NameSize],ECX SetSt [EDX+SYM.Status],symPublic .p5:JSt [%OmfStatus],pfomfRec32,.p7: XOR EAX,EAX LODSW JMP .p8: .p7:LODSD .p8:MOV [EDX+SYM.OffsetLow],EAX LEA EDI,[%ModulePgm] ListStore [EDI+PGM.SymList],EDX LODSB ; Skip unused type index. TEST AL,0x80 JZ .p2: LODSB JMP .p2: .LEDATA32: SetSt [%OmfStatus],pfomfRec32 JMP .l0: .LEDATA: RstSt [%OmfStatus],pfomfRec32 .l0:MOV EDX,ESI ; Temporary save start of the record position. Invoke PfomfLoadSegment,[%SegdefBuf],ESI JC .E8533: MOV EDI,EAX ; Segment which the data are emitted to. SetSt [EDI+SSS.Status],sssNotBSS JSt [EDI+SSS.Purpose],sssPurposeCODE|sssPurposeRODATA|sssPurposeDATA|sssPurposeDRECTVE,.l2: SetSt [EDI+SSS.Purpose],sssPurposeCODE+sssPurposeRODATA+sssPurposeDATA ; Presence of LEDATA specifies purpose. .l2:MOV [%LastSegm],EAX XOR EAX,EAX JSt [%OmfStatus],pfomfRec32,.l3: LODSW JMP .l4: .l3:LODSD .l4:MOV [%DataOffs],EAX ; EAX is data offset within segment. SUB EDX,ESI ; Negative delta in record position. ADD ECX,EDX ; ESI,ECX is now record size minus segment index and data offset - netto data. MOV [%DataPtr],ESI MOV [%DataSize],ECX MOV EDX,ECX BufferRetrieve [EDI+SSS.EmitBuffer] ; ESI,ECX is now previous data contents, EAX is offset of new data in segment. ADD EDX,EAX ; EDX is now the offset of end of new data within segment. SUB EDX,ECX ; How many bytes needs the buffer be increased. JBE .l5: ; If buffer is already large enough. PUSH EAX BufferNew [EDI+SSS.EmitBuffer],EDX ; Increase the buffer. BufferRetrieve [EDI+SSS.EmitBuffer] POP EAX .l5:LEA EDI,[ESI+EAX] ; Position of new data in EmitBuffer. MOV [%DataOffs],EDI ; Save the pointer for later fixups. MOV ESI,[%DataPtr] MOV ECX,[%DataSize] REP MOVSB JMP .NextRecord: .LIDATA32: SetSt [%OmfStatus],pfomfRecLi32 JMP .d1: .LIDATA: RstSt [%OmfStatus],pfomfRecLi32 .d1:LEA EDX,[ESI+ECX] MOV [%LiDbEnd],EDX Invoke PfomfLoadSegment,[%SegdefBuf],ESI JC .E8533: MOV EDI,EAX ; Segment which the data are emitted to. SetSt [EDI+SSS.Status],sssNotBSS JSt [EDI+SSS.Purpose],sssPurposeCODE|sssPurposeDATA|sssPurposeDRECTVE,.d2: SetSt [EDI+SSS.Purpose],sssPurposeCODE+sssPurposeDATA ; Presence of LEDATA specifies purpose. .d2:MOV [%LastSegm],EAX XOR EAX,EAX JSt [%OmfStatus],pfomfRecLi32,.d3: LODSW JMP .d4: .d3:LODSD ; EAX is expanded data offset within segment. .d4:MOV [%DataOffs],EAX ; Save the pointer for later fixups. MOV [%LiDbStart],ESI ; Expansion of LIDATA datablock is postponed to .ExpandLIDATA ; until all following FIXUPP records have been processed. BufferClear [%LiOutEmitBuf] ; Prepare expansion buffers for .ExpandLIDATA. BufferClear [%LiInpRelocBuf] BufferClear [%LiOutRelocBuf] SetSt [%OmfStatus],pfomfLiPending JMP .NextRecord: .FIXUPP32: SetSt [%OmfStatus],pfomfRec32 JMP .NextSubrecord: .FIXUPP: RstSt [%OmfStatus],pfomfRec32 .NextSubrecord: MOV EAX,[%ModPtr] ; The next record. DEC EAX ; Omit checksum byte of the current record. CMP ESI,EAX JNB .NextRecord: ; If there are no more fixup/thread subrecords. XOR EAX,EAX LODSB ; Subrecord 1st byte. TEST AL,1000_0000b JNZ .FixupSubrecord: .ThreadSubrecord: MOVZX ECX,AL LEA EDI,[%ThreadTab] AND CL,0000_0011b ; ECX is now the thread number 0..3. AND AL,1111_1100b ; Get rid of thread number. Dispatch AL,pfomfThF0,pfomfThF1,pfomfThF2,pfomfThF4,pfomfThF5,pfomfThT0,pfomfThT1,pfomfThT2,pfomfThT3,pfomfThT4,pfomfThT5,pfomfThT6, JMP .E8533: .pfomfThT4: .pfomfThT0:Invoke PfomfLoadSegment,[%SegdefBuf],ESI ; Target is specified by SEGDEF index. JMP .t1: .pfomfThT5: .pfomfThT1:Invoke PfomfLoadGroup,[%GrpdefBuf],ESI ; Target is specified by GRPDEF index. JMP .t1: .pfomfThT6: .pfomfThT2:Invoke PfomfLoadExtern,[%ExtdefBuf],ESI ; Target is specified by EXTDEF index. JMP .t1: .pfomfThT3:LODSW ; Target is specified by explicit PARA segment address. Not supported. SUB EAX,EAX .t1:MOV [EDI+16+4*ECX],EAX ; Store target segment to the thread table JMP .NextSubrecord: .pfomfThF0:Invoke PfomfLoadSegment,[%SegdefBuf],ESI ; Frame is specified by SEGDEF index. JMP .h1: .pfomfThF1:Invoke PfomfLoadGroup,[%GrpdefBuf],ESI ; Frame is specified by GRPDEF index. JMP .h1: .pfomfThF2:Invoke PfomfLoadExtern,[%ExtdefBuf],ESI ; Frame is specified by EXTDEF index. JMP .h1: .pfomfThF4:MOV EAX,[%LastSegm] ; Frame is specified by LEDATA segment. JMP .h1: .pfomfThF5:XOR EAX,EAX ; Frame is identical with target. .h1:MOV [EDI+0+4*ECX],EAX ; Store frame segment to the thread table. JMP .NextSubrecord: .FixupSubrecord: LEA EDX,[%Reloc] Clear EDX,Size=SIZE#RELOC ; Specify relocation type [EDX+RELOC.Status]. MOV EBX,relocAbsVA TEST AL,0100_0000b ; relocAbsVA or relocRel? JNZ .f1: ; If segment-relative (absolute relocation). MOV EBX,relocRel .f1:MOVZX ECX,AL SHR ECX,2 AND CL,0x0F ; ECX is now Location type 0d..15d. AND AL,0x03 ; Two most significant bits of fixup position within LEDATA. SHL EAX,8 LODSB ; EAX is now 10bit position in previous LEDATA record. MOV [%LdataOffs],EAX Dispatch CL,1d,2d,3d,5d,9d,11d,13d ; Field "Location" specifies relocation type. JMP .E8533: ; Unsupported location value. ; Location handlers. CL=location 0..15, ESI=^FixData, EDX=^RELOC, EBX=relocRel/relocAbsVA. .2d:MOV EBX,relocPara+relocWidth16 ; 16bit base selector. JMP .f2: .3d:MOV EBX,relocFar+relocWidth16 ; 32bit far pointer. JMP .f2: .11d:MOV EBX,relocFar+relocWidth32 ; 48bit far pointer. JMP .f2: .13d: .9d:OR EBX,relocWidth32 ; 32bit offset. JMP .f2: .1d: ; Abs16 or Rel16. ; 16bit offset. .5d: ; Abs16 or Rel16, resolved at load time. OR EBX,relocWidth16 .f2:MOV [EDX+RELOC.Status],EBX ; Specify RELOC members .Addend, .Section, .Symbol. LEA ECX,[%ThreadTab] Invoke PfomfLoadFixData,ESI,EDX,ECX,[%LastSegm],[%SegdefBuf],[%GrpdefBuf],[%ExtdefBuf],[%OmfStatus] JC .E8533: ; Specify relocation .Org (offset of relocated word/dword). JSt [%OmfStatus],pfomfLiPending,.f8: ; LIDATA fixups are treated differently. ; LEDATA fixup. RELOC.Org is related to data in segment .EmitBuf. Reloc is stored to segment's .RelocBuf. PUSH ESI ; Save pointer to the next FIXUPP subrecord. MOV EDI,[%LastSegm] ; Segment whose data are fixed up. MOV EAX,[%DataOffs] ; Pointer to the recent LEDATA data within the .EmitBuffer. BufferRetrieve [EDI+SSS.EmitBuffer] ; ESI is now at the start of .EmitBuffer contents. SUB EAX,ESI POP ESI ADD EAX,[%LdataOffs] ; Add 10bit offset or relocation within previous LEDATA record. MOV [EDX+RELOC.OrgLow],EAX MOV [EDX+RELOC.Section],EDI BufferStore [EDI+SSS.RelocBuffer],EDX,SIZE#RELOC; Relocation EDX is complete now. JMP .NextSubrecord: .f8: ; LIDATA fixup. RELOC.Org is related to DataBlock. Relocs are accumulated in %LiRelocBuf. MOV EAX,[%LdataOffs] ; 0..1023 offset of fixup related to %LiDbStart. MOV [EDX+RELOC.OrgLow],EAX BufferStore [%LiInpRelocBuf],EDX,SIZE#RELOC ; Relocation EDX is complete now. JMP .NextSubrecord: .MODEND32: SetSt [%OmfStatus],pfomfRec32 JMP .m1: .MODEND: RstSt [%OmfStatus],pfomfRec32 .m1:JSt [%OmfStatus],pfomfImport,.70: ; If MODEND ends one of imported modules. .m4:CMP ECX,1 ; MODEND ends the linkable module. JNA .70: ; If there is no entry in this program. LODSB ; Modend type byte. TEST AL,0100_0000b JZ .70: ; If there is no entry in this program. LEA EDX,[%Reloc] ; Room for the relocation of entry point. Clear EDX,Size=SIZE#RELOC JSt [%OmfStatus],pfomfRec32, .m5: SetSt [EDX+RELOC.Status],relocWidth16+relocAbsVA JMP .m6: .m5:SetSt [EDX+RELOC.Status],relocWidth32+relocAbsVA .m6:LEA ECX,[%ThreadTab] Invoke PfomfLoadFixData,ESI,EDX,ECX,[%LastSegm],[%SegdefBuf],[%GrpdefBuf],[%ExtdefBuf],[%OmfStatus] JC .E8533: ; Entry point loaded from MODEND record to RELOC EDX will be converted to the source Entry= value. MOV ESI,[EDX+RELOC.Symbol] MOV ECX,[ESI+SYM.NameSize] MOV ESI,[ESI+SYM.NamePtr] LEA EAX,[ECX+12] ; Room for entry symbol name + addend. PoolNew [EDI+PGM.Pool],EAX,Align=Byte MOV [EDI+PGM.Pgmopt.EntryPtr],EAX PUSH EBX,EDI MOV EDI,EAX MOV EBX,EAX REP MOVSB ; Symbol name, e.g. CODE. MOV EAX,[EDX+RELOC.AddendLow] TEST EAX JZ .m8: JS .m7: MOVB [EDI],'+' INC EDI .m7: StoD EDI,Signed=Yes,Size=12,Align=Left ; Symbol offset, e.g. +256. .m8: MOV ECX,EDI SUB ECX,EBX POP EDI,EBX MOV [EDI+PGM.Pgmopt.EntrySize],ECX .70:LEA ESI,[%ModulePgm] ; ModulePgm is completely loaded, store it to BaseProgram.ModulePgmList. Invoke PfDrectveDestroy::,ESI ; An alternative way to specify EXPORT/IMPORT in OMF format using [DRECTVE] pseudosegment. Invoke PgmDetectImportModule::,ESI ; Set pgmImpLibMember flag when it's a pure import module. MOV EBX,[%BaseProgram] JNSt [ESI+PGM.Status],pgmImpLibMember,.79: ; If it is an ordinary object module (with emitted contents). ; The just loaded module is pure import library member. Import module will be created instead. ListGetFirst [ESI+PGM.SymList] JZ .79: .71:JSt [EAX+SYM.Status],symImport,.72: ListGetNext EAX JNZ .71: JMP .79: .72:Invoke PgmCreateImportModule::,EBX,[EAX+SYM.DllNamePtr],[EAX+SYM.DllNameSize], \ [EAX+SYM.OrdinalNr],[EAX+SYM.Status],[EAX+SYM.NamePtr],[EAX+SYM.NameSize], \ [EAX+SYM.InterNamePtr],[EAX+SYM.InterNameSize] JMP .80: .ExternSymbolAndSegmentCreate: PROC ; Used in .EXTDEF: and .IMPDEF: handlers. ; Input: Unique name of nonexisting external symbol: ; ESI,ECX=external symbol and segment name. ; [%OmfStatus] flags pfomfImport and pfomfByOrdinal. ; [%ModulePgm] Linked or imported program. ; Output:New symbol and segment are stored on .SymList and .SssList of [%ModulePgm]. ; EDX=pointer to the new symbol. ; EDI=pointer to the new segment. ; ESI,ECX unchanged. ; EBX=Pointer to the linked/imported PGM at %ModulePgm. ; EAX=? LEA EBX,[%ModulePgm] ListNew [EBX+PGM.SymList],Zeroed=yes MOV EDX,EAX ; New symbol symSe on the list. ListNew [EBX+PGM.SssList],Zeroed=yes MOV EDI,EAX ; New extern pseudosection sssExtern. MOV EAX,symExtern+'A' ; Loaded extern symbol status. JNSt [%OmfStatus],pfomfImport,.c5: ; Skip when the loaded file is statically linked rather than imported. JSt [%OmfStatus],pfomfByOrdinal,.c4: ; If this IMPDEF specifies import by ordinal. MOV EAX,symExtern+symImport+'A' JMPS .c5: .c4:MOV EAX,symExtern+symImport+symImportedByOrd+'A' .c5:MOV [EDX+SYM.Status],EAX SetSt [EDI+SSS.Status],sssExtern+sssPublic JNSt [%OmfStatus],pfomfImport,.c6: SetSt [EDI+SSS.Purpose],sssPurposeIMPORT .c6:PoolStore [EBX+PGM.Pool],ESI,ECX,Align=BYTE ; Make symbol+section name nonvolatile. MOV [%InterNamePtr],EAX MOV [%InterNameSize],ECX MOV [EDX+SYM.NamePtr],EAX MOV [EDX+SYM.NameSize],ECX MOV [EDX+SYM.InterNamePtr],EAX MOV [EDX+SYM.InterNameSize],ECX MOV [EDX+SYM.Section],EDI MOV [EDI+SSS.NamePtr],EAX MOV [EDI+SSS.NameSize],ECX MOV [EDI+SSS.SymPtr],EDX ; Pointer to the symbol in imported program.SymList. MOV [EDI+SSS.SegmPtr],EDI ; Let extern pseudosegment.SegmPtr point to itself. RET ENDP .ExternSymbolAndSegmentCreate: .ExpandLIDATA: PROC ; Postponed expansion of DataBlock at [%LiDbStart]..[%LiDbEnd]. ; Relocations are stored in [%LiRelocBuf], their .Org related to [%LiDbStart]. Invoke PfomfLoadDataBlock,[%LiDbStart],[%LiDbStart],[%LiDbEnd],[%LiOutEmitBuf], \ [%LiInpRelocBuf],[%LiOutRelocBuf],[%OmfStatus] ; Expanded data are returned in [%LiOutEmitBuf]. ; Expanded relocations are returned in [%LiOutRelocBuf], ; their .Org related to expanded data (starting from 0). MOV EDI,[%LastSegm] BufferRetrieve [%LiOutEmitBuf] BufferStore [EDI+SSS.EmitBuffer],ESI,ECX Invoke RelocRelocInBuffer::,[%LiOutRelocBuf],[%DataOffs] BufferRetrieve [%LiOutRelocBuf] BufferStore [EDI+SSS.RelocBuffer],ESI,ECX RET ENDP .ExpandLIDATA: .79:ListStore [EBX+PGM.ModulePgmList],ESI MOV [%ReturnEAX],EAX .80:Invoke EaBufferRelease::,[%LiInpRelocBuf] Invoke EaBufferRelease::,[%LiOutRelocBuf] Invoke EaBufferRelease::,[%LiOutEmitBuf] Invoke EaBufferRelease::,[%ExtdefBuf] Invoke EaBufferRelease::,[%GrpdefBuf] Invoke EaBufferRelease::,[%SegdefBuf] Invoke EaBufferRelease::,[%LnamesBuf] .90:MOV EAX,[%ReturnEAX] TEST EAX ; Set ZF=1 if aborted. EndProcedure PfomfLoadModule
ENDPROGRAM pfomf