EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

pfmz.htm
Structures
PFMZ_DOS_HEADER
Procedures
PfmzCompile
PfmzDefaultStack
PfmzLoadPgm

This source generates EuroAssembler output object file in program format MZ (16bit or 32bit DOS executable program).


     EUROASM NOWARN=2101
pfmz 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.
dict.htm,    \
ea.htm,      \
eaopt.htm,   \
exp.htm,     \
msg.htm,     \
pf.htm,      \
\pfpe.htm,    \
pgm.htm,     \
pgmopt.htm,  \
reloc.htm,   \
sss.htm,     \
stm.htm,     \
sym.htm,     \
syswin.htm,  \
;;
 pfmz HEAD ; Start module interface.
↑ PFMZ_DOS_HEADER
Header of DOS executable format MZ.
PFMZ_DOS_HEADER STRUC  ; DOS .EXE header
                          ; +00h.
 .e_magic    D WORD       ; Magic number "MZ".
 .e_cblp     D WORD       ; Bytes on the last page of MZ file (0..511).
 .e_cp       D WORD       ; 512-byte pages in MZ file, including the incomplete last one.
 .e_crlc     D WORD       ; Number of relocations.
 .e_cparhdr  D WORD       ; Size of header in 16-byte paragraphs (PFMZ_DOS_HEADER + relocations).
 .e_minalloc D WORD       ; Minimum extra paragraphs needed (trailing BSS sections).
 .e_maxalloc D WORD       ; Maximum extra paragraphs needed.
 .e_ss       D WORD       ; Initial (image relative) SS value.
                          ; +10h.
 .e_sp       D WORD       ; Initial SP value.
 .e_csum     D WORD       ; Word checksum of the whole file, or 0.
 .e_ip       D WORD       ; Initial IP value.
 .e_cs       D WORD       ; Initial (image relative) CS value.
 .e_lfarlc   D WORD       ; File offset of relocation table (usually 64).
 .e_ovno     D WORD       ; Overlay number, not supported in €ASM (0).
 .e_res      D 2*WORD     ; Reserved.
                          ; +20h.
             D 2*WORD     ; Reserved.
 .e_oemid    D WORD       ; OEM identifier (for e_oeminfo).
 .e_oeminfo  D WORD       ; OEM information (e_oemid specific).
 .e_res2     D 4*WORD     ; Reserved.
                          ; +30h.
             D 6*WORD     ; Reserved.
 .e_lfanew   D DWORD      ; File offset of PE, LE or NE header.
 ENDSTRUC PFMZ_DOS_HEADER ; SIZE# PFMZ_DOS_HEADER = 40h = 64.
 ENDHEAD pfmz  ; End of module interface.
↑ PfmzCompile OutputStream, Pgm
PfmzCompile is constructor of output file image in format MZ (16bit DOS executable).
Input
OutputStream is pointer to a STREAM for the output image contents.
Pgm is pointer to PGM representing the completely assembled and combined program.
Output
OutputStream is filled with output file contents.
Error
Errors are reported with macro Msg.
Invoked from
PfOutput
Invokes
EaBufferAlign EaBufferRelease EaBufferReserve PfmzDefaultStack PgmEvalEntry PgmGroupByModel PgmLink PgmOrderSegments PgmRelocResolve PgmStreamImage RelocReportUnresolved SymReportUnresolved
Tested by
t7921 t7922 t7923 t7924 t7925 t7926
PfmzCompile Procedure OutputStream, Pgm
;;;ParaRelocNr     LocalVar                         ; Number of PARA# relocations.
ParaRelocBuffer LocalVar                         ; ^BUFFER for DWORD pointers to RELOC records with relocPara|relocFar.
MzRelocBuffer   LocalVar                         ; ^BUFFER for 16+16bit far pointers to the image base relocations.
StubSize        LocalVar                         ; Size of MZ header + MZ relocations, aligned to 32 bytes.
EmittedSize     LocalVar                         ; Total size of emitted image (CODE+RODATA+DATA).
AllocatedSize   LocalVar                         ; Total size of allocated image (%EmittedSize+BSS+STACK).
MzDosHeader     LocalVar Size=SIZE# PFMZ_DOS_HEADER ; Room for the MZ header (64 bytes).
                ClearLocalVar
    Invoke EaBufferReserve::,%^PROC
    MOV [%ParaRelocBuffer],EAX
    Invoke EaBufferReserve::,%^PROC
    MOV [%MzRelocBuffer],EAX
    MOV EBX,[%Pgm]
    Invoke PfmzDefaultStack::,EBX
    Invoke SymReportUnresolved::,EBX
    Invoke PgmGroupByModel::,EBX
    Invoke PgmOrderSegments::,EBX                ; Groups and segments will be ordered in Pgm.SegOrdBuffer.

    ; Copy pointers to unresolved paragraph relocations from all segments to %ParaRelocBuffer.
;;;;    XOR EDX,EDX                                  ; Count the number of PARA relocations in EDX.
    BufferRetrieve [EBX+PGM.SegOrdBuffer]        ; Pointers to segments in image order.
    SHR ECX,2
    JZ .32:
.22:LODSD
    JNSt [EAX+SSS.Status],sssSegment,.30:
    MOV EDI,EAX                                  ; Segment whose words are relocated.
    PUSH ECX,ESI
      BufferRetrieve [EDI+SSS.RelocBuffer]
      JECXZ .28:                                 ; If there are no relocations in segment EDI.
.24:  MOV EAX,[ESI+RELOC.Status]
      JSt EAX,relocIgnore,.26:
      JSt EAX,relocPara|relocFar,.25:
      JNSt EAX,relocAbsVA,.26:
      MOV EDX,relocExtAttr
      AND EDX,EAX
      CMP EDX,dictAttrPARA<<16                    ; >>
      JNE .26:
      RstSt EAX,relocAbsVA
      SetSt EAX,relocPara
      MOV [ESI+RELOC.Status],EAX
.25:  BufferStoreDword [%ParaRelocBuffer],ESI    ; Pointer to relocations which requires resolving at load time.
.26:  ADD ESI,SIZE# RELOC
      SUB ECX,SIZE# RELOC
      JA .24:                                    ; The next relocation.
.28:POP ESI,ECX
.30:LOOP .22:                                    ; The next segment.
.32:BufferRetrieve [%ParaRelocBuffer]
    MOV EDX,ECX
    SHR ECX,2
    CMP ECX,64K                                  ; Number of relocations.
    Msg cc=NB,'7923',ECX                         ; Number of relocations (!1D) exceeded 64K.
    ADD EDX,1Fh                                 ; Each MZ relocation is FAR PTR (4 bytes).
    AND EDX,~1Fh                                ; Align MZ relocation block to even paragraphs (32 bytes).
    ADD EDX,SIZE# PFMZ_DOS_HEADER               ; Compute StubSize (MZ header + MZ relocations).
    MOV [%StubSize],EDX
    Invoke PgmLink::,EBX,EDX,0
    Invoke PgmRelocResolve::,EBX
    ; Preformat MzDosHeader.
    LEA EDI,[%MzDosHeader]
    MOVW [EDI+PFMZ_DOS_HEADER.e_magic],"MZ"
    MOVW  [EDI+PFMZ_DOS_HEADER.e_lfarlc],SIZE# PFMZ_DOS_HEADER
    BufferRetrieve [%ParaRelocBuffer]            ; Count MZ relocations.
    SHR ECX,2
    MOV [EDI+PFMZ_DOS_HEADER.e_crlc],CX          ; Number of relocations.
    SHR EDX,4                                    ; Convert the header (stub) size to 16-bytes paragraphs.
    MOV [EDI+PFMZ_DOS_HEADER.e_cparhdr],DX       ; Header size (including the relocation table).
    ; Compute emitted image size and virtual size.
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    ADD ECX,ESI
.36:CMP ESI,ECX
    JNB .37:
    LODSD
    JNSt [EAX+SSS.Status],sssSegment,.36:
    MOV EDX,[EAX+SSS.TopLow]
    MOV [%AllocatedSize],EDX
    JNSt [EAX+SSS.Status],sssNotBSS,.36:
    MOV [%EmittedSize],EDX                       ; Segment EAX is initialized.
    JMP .36:
.37:MOV EAX,[%StubSize]
    ADD [%AllocatedSize],EAX
    ADD [%EmittedSize],EAX
    ; Update MzDosHeader.
.46:MOV EAX,[%AllocatedSize]
    SUB EAX,[%EmittedSize]
    ADD EAX,15
    SAR EAX,4                                    ; Convert the reserved size to paragraphs.
    MOV [EDI+PFMZ_DOS_HEADER.e_minalloc],AX      ; Minimal BSS allocation required to execute.
    AND EAX,0xFFFF_0000
    Msg cc=NZ,'8521'                             ; MZ image size exceeded 1 MB.
    MOV EAX,[%EmittedSize]
    MOV ECX,EAX                                  ; EAX and ECX is now the total file size.
    AND EAX,0x01FF
    MOV [EDI+PFMZ_DOS_HEADER.e_cblp],AX          ; Number of bytes on the last page.
    ADD ECX,0x01FF
    SHR ECX,9
    MOV [EDI+PFMZ_DOS_HEADER.e_cp],CX            ; Number of pages in the file.
    MOV EAX,[EBX+PGM.Pgmopt.SizeOfHeapCommitLow] ; Suggested maximal memory allocation size for the image (in bytes).
    MOV EDX,0xFFFF                               ; Maximal possible value in paragraphs for realmode programs.
    SAR EAX,4                                    ; Convert the size to paragraphs.
    CMP EAX,EDX
    JBE .48:
    XCHG EAX,EDX                                 ; Maximal possible value for realmode programs.
.48:MOV [EDI+PFMZ_DOS_HEADER.e_maxalloc],AX
    ; Find STACK group or segment to EDX.
    XOR EDX,EDX
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    SHR ECX,2
    JZ .W3922:                                   ; Missing segment with PURPOSE=STACK.
.50:LODSD
    JNSt [EAX+SSS.Status],sssGroup,.52:
    JNSt [EAX+SSS.Purpose],sssPurposeSTACK,.52:
    MOV EDX,EAX
.52:LOOP .50:
    TEST EDX
    JNZ .58:
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    SHR ECX,2
.54:LODSD
    JNSt [EAX+SSS.Status],sssSegment,.56:
    JNSt [EAX+SSS.Purpose],sssPurposeSTACK,.56:
    MOV EDX,EAX
.56:LOOP .54:
    TEST EDX
    JZ .W3922:                                   ; Missing segment with PURPOSE=STACK.
.58:MOV EAX,[EDX+SSS.BottomLow]
    MOV ECX,[EDX+SSS.TopLow]
    TEST EAX,0xFFF0_0000
    Msg cc=NZ,'7714'                             ; Stack above 1 MB is not encodable in this program format.
    TEST EAX,0x0000_000F
    Msg cc=NZ,'3843',EDX                         ; Stack segment [!1S] is not paragraph aligned.
    AND EAX,0x000F_FFF0
    SUB ECX,EAX
    SHR EAX,4
    MOV [EDI+PFMZ_DOS_HEADER.e_ss],AX            ; Initial SS: RVA paragraph address of the stack bottom.
    MOV [EDI+PFMZ_DOS_HEADER.e_sp],CX            ; Initial SP: size of the stack segment.
    JMP .60:
.W3922:Msg '3922'                                ; Missing segment with PURPOSE=STACK.

.60: ; Entry point which may refer to unresolved external symbol.
    Invoke PgmEvalEntry::,EBX
    LEA EDX,[EBX+PGM.EntryExp]
    MOV ECX,[EDX+EXP.Status]
    LEA EAX,[EBX+PGM.Pgmopt.EntryPtr]            ; ENTRY= value in case of E7711.
    Dispatch CL,'A','N','F',00
    Msg '7711',EAX                               ; Invalid program entry point "!1S".
    ; Simulate missing or invalid entry as if it were scalar 0.
.N: ; EntryExp EDX is specified as an absolute offset (no segment), e.g. ENTRY=100h.
    ; Assume it is the offset in the first code segment.
    BufferRetrieve [EBX+PGM.SegOrdBuffer]
    JECXZ .F:
.62:LODSD                                        ; Search for a code segment.
    JNSt [EAX+SSS.Status],sssSegment,.64:
    JSt [EAX+SSS.Purpose],sssPurposeCODE,.6B:
.64:LOOP .62:
.F: ; EntryExp EDX was specified as immediate far pointer, e.g. ENTRY=0x0040:1234h.
    Msg '2921',EAX                               ; Nonrelocable entry point "!1S" is not supported.
    MOV ECX,[EDX+EXP.Seg]                        ; Paragraph address of the entry.
    MOV EAX,[EDX+EXP.Low]                        ; Offset of the entry.
    JMP .73:
.00:Msg '7710'                                   ; Missing program entry point.
    JMP .N:
.E6961:Msg '6961',ECX                            ; Unresolved external/imported symbol "!1S".
    JMP .N:

.A: ; Entry expression EDX was evaluated as an address symbol or expression, e.g. ENTRY=Main+4.
    MOV ECX,[EDX+EXP.Sym]
    JECXZ .N:
    JNSt [ECX+SYM.Status],symExtern|symImport,.69:
    JNSt [ECX+SYM.Status],symResolved,.E6961:    ; Unresolved external/imported symbol "!1S".
    MOV ECX,[ECX+SYM.SymbPtr]                    ; ECX=resolved entry symbol.
    JECXZ .E6961:                                ; Unresolved external/imported symbol "!1S".
.69:MOV EAX,[ECX+SYM.Section]
    TEST EAX
    JZ .E6961:                                   ; Unresolved external/imported symbol "!1S".
.6B:MOV ECX,[EAX+SSS.SVA]
    ADD ECX,[EDX+EXP.Low]                        ; ECX is now the linear RVA of the entry.
    MOVZX EAX,CX                                 ; EAX is offset part of the entry point.
    SHR ECX,16
    SHL ECX,12                                   ; ECX is paragraph addres of the entry point.
.73:TEST ECX,0xFFFF_0000
    Msg cc=NZ,'7715'                             ; Entry above 1 MB is not encodable in this program format.
.74:MOV [EDI+PFMZ_DOS_HEADER.e_ip],AX
    MOV [EDI+PFMZ_DOS_HEADER.e_cs],CX

    ; Resolve and convert paragraph relocations (relocPara) to 16+16 FAR pointers in MZRelocBuffer.
    BufferRetrieve [%ParaRelocBuffer]            ; Buffer with pointers to relocPara records.
    SHR ECX,2
    JZ .78:
.76:LODSD
    PUSH ESI
     MOV ESI,EAX
   ;;  JSt [ESI+RELOC.Status],relocResolved,.77:
     SetSt [ESI+RELOC.Status],relocResolved
     MOV EDI,[ESI+RELOC.Section]
     MOV EAX,[EDI+SSS.BottomLow]
     TEST EAX,0xFFF0_0000
     Msg cc=NZ,'7716',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Relocation [!1S]:!2H above 1 MB is not encodable in this program format.
     MOV EDX,0x0000_000F
     AND EDX,EAX
     ADD EDX,[ESI+RELOC.OrgLow]
     SHL EAX,12
     MOV AX,DX
     BufferStoreDword [%MzRelocBuffer],EAX       ; Store MZ relocation far pointer.
.77:POP ESI
    LOOP .76:
.78:Invoke EaBufferAlign::,[%MzRelocBuffer],32   ; Round up to even paragraphs (YWORD).
    Invoke RelocReportUnresolved::,EBX

    ; Calculate file checksum.
    XOR EDX,EDX                                  ; Checksum word accumulator.
    LEA ESI,[%MzDosHeader]
    MOV ECX,SIZE# PFMZ_DOS_HEADER /2
.80:LODSW
    ADD EDX,EAX
    LOOP .80:
    BufferRetrieve [%MzRelocBuffer]
    SHR ECX,1
    JZ .84:
.82:LODSW
    ADD EDX,EAX
    LOOP .82:
.84:MOV EDI,[%OutputStream]
    StreamGetSize EDI                            ; Return number of bytes in EAX.
    StreamStoreByte EDI,0                        ; Temporarily word-align the stream size in case it was odd.
.86:StreamRetrieve EDI                           ; Get one stream block to ESI,ECX.
    SHR ECX,1
    JZ .90:                                      ; No more data in stream. EDX is the word checksum.
.88:LODSW
    ADD EDX,EAX                                  ; Compute checksum.
    LOOP .88:
    JMP .86:                                     ; The next stream block.
.90:NOT EDX
    LEA EBX,[%MzDosHeader]
    MOV [EBX+PFMZ_DOS_HEADER.e_csum],DX
    ; File is completly compiled in buffers.
    StreamClear EDI
    StreamStore EDI,EBX,SIZE# PFMZ_DOS_HEADER
    BufferRetrieve [%MzRelocBuffer]
    StreamStore EDI,ESI,ECX
    Invoke PgmStreamImage::,[%Pgm],EDI
    Invoke EaBufferRelease::,[%MzRelocBuffer]
    Invoke EaBufferRelease::,[%ParaRelocBuffer]
.99:EndProcedure PfmzCompile
↑ PfmzDefaultStack Pgm
PfmzDefaultStack will create missing implicit segment [STACK] with size specified by the option PROGRAM SIZEOFSTACKCOMMIT= (factory-default is 8 KB), when these conditions are met:
Input
Pgm is pointer to PGM representing the completely assembled and combined program.
Output
-
Error
-
Invoked from
PfOutput
Invokes
SssCreateSe SssFindByName
Invoked by
PfmzCompile
PfmzDefaultStack Procedure Pgm
    MOV EBX,[%Pgm]
    MOV EAX,[EBX+PGM.Pgmopt.Status]
    AND EAX,pgmoptFormatMask
    CMP AL,pgmoptMZ
    JNE .90:
    JNSt [Ea.Eaopt.Status::],eaoptAUTOSEGMENT,.90:
    Invoke SssFindByName::,sssSegment,0,=B"STACK",5,EBX
    JNC .60:
    ListGetLast [EBX+PGM.SssList]
    JZ .50:
.10:JNSt [EAX+SSS.Status],sssSegment,.40:
    JSt [EAX+SSS.Purpose],sssPurposeSTACK,.60:
.40:ListGetPrev EAX
    JNZ .10:
.50:Invoke SssCreateSe::,[EBX+PGM.CurrentStm],0, \ No stack segment found. Implicit [STACK] will be created.
           =B"STACK",5,sssWidth16+sssSegment+sssStack+sssImplicit+sssUsed,sssPurposeSTACK, 16
    MOV ECX,[EBX+PGM.Pgmopt.SizeOfStackCommitLow]
    MOV [EAX+SSS.TopLow],ECX
.60:CMPD [EAX+SSS.GroupPtr],0
    JNZ .90:                                     ; Stack segment should be grouped in MZ format.
    MOV EDI,EAX                                  ; Assign stack segment EDI to an existing group.
    ListGetFirst [EBX+PGM.SssList]
.70:JNSt [EAX+SSS.Status],sssGroup,.80:
    JNSt [EAX+SSS.Purpose],sssPurposeSTACK,.80:
    MOV [EDI+SSS.GroupPtr],EAX
.80:ListGetNext EAX
    JNZ .70:
.90:EndProcedure PfmzDefaultStack
↑ PfmzLoadPgm BasePgm, ObjBegin, ObjEnd, FileNamePtr
Executable format MZ is not linkable, it cannot be loaded.
Input
BasePgm is pointer to an existing PGM to which the object file is being linked/imported.
ObjBegin is pointer to the contents of linked/imported object file mapped in memory by the caller.
ObjSize is number of bytes in the object file.
FileNamePtr is pointer to zero-terminated object file name (used in error reports).
Output
-
Error
E8534 Format !1S of file "!2$" is not linkable.
Invoked from
PfLoad
PfmzLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
    Msg '8534',Dict_FormatMZ::,[%FileNamePtr] ; Format !1S of file "!2$" is not linkable.
   EndProcedure PfmzLoadPgm
  ENDPROGRAM pfmz

▲Back to the top▲