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 used in this source.
ea.htm,eaopt.htm,exp.htm,ii.htm,msg.htm,pf.htm,pgm.htm,pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.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.
TEST ECX
JZ .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.
TEST ECX
JZ .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:
TEST ECX
JZ .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
TEST ECX
JZ .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
TEST ECX
JZ .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.
TEST ECX
JZ .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