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).


pfmz PROGRAM FORMAT=COFF,MODEL=FLAT,WIDTH=32
 INCLUDEHEAD "euroasm.htm" ; Interface (structures, symbols and macros) of other modules.
 pfmz HEAD ; Start module interface.
↑ PFMZ_DOS_HEADER
Header of DOS executable format MZ.
PFMZ_DOS_HEADER STRUC ; DOS .EXE header
 .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 16B 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.
 .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 4*WORD  ; Reserved.
 .e_oemid    D WORD    ; OEM identifier (for e_oeminfo).
 .e_oeminfo  D WORD    ; OEM information (e_oemid specific).
 .e_res2     D 10*WORD ; Reserved.
 .e_lfanew   D DWORD   ; File offset of PE, LE or NE header.
 ENDSTRUC PFMZ_DOS_HEADER ; SIZE# PFMZ_DOS_HEADER = 64.
 ENDHEAD pfmz  ; End of module interface.
↑ PfmzCompile OutputStream, Pgm
PfmzCompile is constructor of output file image in format MZ.
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 PgmConcatenateImage PgmCreateImplicitGroups PgmEvalEntry PgmLinkImage PgmOrderSegments RelocSort
Tested by
t7472 t7475 t7478 t7481 t7484 t7911 t7940 t7946
PfmzCompile Procedure OutputStream, Pgm
MzDosHeader   LocalVar Size=SIZE# PFMZ_DOS_HEADER
MzRelocBuffer LocalVar ; Buffer with 16+16bit far pointers to image base relocations.
MzImageBuffer LocalVar ; Buffer with raw segments contents.
TopInitRVA    LocalVar ; Highest RVA of   initialized segments. ImageSize=TopInitRVA-0.
TopUninitRVA  LocalVar ; Highest RVA of uninitialized segments. BssSize=TopUninitRVA-TopInitRVA.
    MOV EBX,[%Pgm]
    Invoke EaBufferReserve::,PfmzCompile
    MOV [%MzRelocBuffer],EAX
    Invoke PgmCreateImplicitGroups::,EBX
    Invoke PfmzDefaultStack::,EBX
    Invoke RelocSort::,EBX
    Invoke PgmOrderSegments::,EBX
    Invoke PgmLinkImage::,EBX,0
    ; Store unresolved relocations to %MzRelocBuffer.
    BufferRetrieve [EBX+PGM.SssPtrBuf] ; Pointers to segments.
    SHR ECX,2
    JZ .25: ; If no segments.
.10:LODSD
    JNSt [EAX+SSS.Status],sssSegment,.22:
    MOV EBX,EAX ; Segment whose word is relocated.
    PUSH ECX,ESI
      BufferRetrieve [EBX+SSS.RelocBuffer]
      JECXZ .19: ; If no relocations in segment EBX.
.13:  PUSH ESI
        JSt [ESI+RELOC.Status],relocResolved|relocDisp8,.16:
        JNSt [ESI+RELOC.Status],relocPara,.16: ; Only paragraph relocations are left to resolve at load time.
        MOV EAX,[EBX+SSS.BottomLow]
        MOV EDX,0x0000_000F
        AND EDX,EAX ;
        SHL EAX,12 ; Convert RVA to paragraph address and move it to the upper half of EAX.
        ADD EDX,[ESI+RELOC.OrgLow]
        MOV AX,DX
        BufferStoreDword [%MzRelocBuffer],EAX ; Store MZ relocation far pointer.
.16:  POP ESI
      ADD ESI,SIZE#RELOC
      SUB ECX,SIZE#RELOC
      JA .13:
.19:POP ESI,ECX
.22:LOOP .10: ; Next segment.
.25:;Create raw image.
    MOV EBX,[%Pgm]
    Invoke PgmConcatenateImage::,EBX
    MOV [%MzImageBuffer],EAX
    ;Find image RVA.
    BufferRetrieve [EBX+PGM.SssPtrBuf]
    LEA EDI,[ESI+ECX-4] ; EDI points to the pointer to the last linked segment (usually uninitialized).
    MOV EDX,[EDI]
    MOV EAX,[EDX+SSS.TopLow]
    MOV [%TopUninitRVA],EAX ; RVA of image top, including BSS+STACK segments.
    MOV ECX,[EBX+PGM.NrOfInitSegments]
    LEA EDI,[ESI+4*ECX-4] ; EDI points to the pointer to the last initialized segment in image.
    SUB EAX,EAX
    CMP EDI,ESI
    JB .28: ; If no initialized data in image.
    MOV EDX,[EDI] ; EDX points to the last initialized segment.
    MOV EAX,[EDX+SSS.TopLow]
.28:MOV [%TopInitRVA],EAX
    ; Construct MzDosHeader.
    LEA EDI,[%MzDosHeader]
    MOV ECX,SIZE# PFMZ_DOS_HEADER
    Clear EDI,Size=ECX
    MOVW [EDI+PFMZ_DOS_HEADER.e_magic],"MZ"
    MOV [EDI+PFMZ_DOS_HEADER.e_lfarlc],CX ; Fileoffset of relocation table.
    BufferRetrieve [%MzRelocBuffer] ; Its size is not YWORD aligned yet.
    MOV EAX,ECX
    SHR ECX,2
    MOV [EDI+PFMZ_DOS_HEADER.e_crlc],CX ; Number of load-time relocations.
    SHR ECX,16
    Msg cc=NZ,'7923',EAX ; Number of relocations (!1D) exceeded 64K.
    Invoke EaBufferAlign::,[%MzRelocBuffer],32 ; Round up the header size to even paragraphs (YWORD).
    BufferRetrieve [%MzRelocBuffer]
    ADD ECX,SIZE# PFMZ_DOS_HEADER
    MOV EDX,ECX
    SHR ECX,4 ; Convert header size to 16B paragraphs.
    MOV [EDI+PFMZ_DOS_HEADER.e_cparhdr],CX ; Size of header (including the relocation table).
    BufferRetrieve [%MzImageBuffer]
    ADD ECX,EDX ; ECX is now the total file size.
    MOV EAX,ECX
    AND AX,0x01FF
    MOV [EDI+PFMZ_DOS_HEADER.e_cblp],AX ; 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,[%TopUninitRVA]
    SUB EAX,[%TopInitRVA]
    ADD EAX,15
    SAR EAX,4 ; Convert reserved size to paragraphs.
    MOV [EDI+PFMZ_DOS_HEADER.e_minalloc],AX     ; Minimal BSS allocation required to execute.
    MOV EAX,[EBX+PGM.Pgmopt.SizeOfHeapCommitLow]
    SAR EAX,4
    CMP EAX,0xFFFF
    JBE .31:
    MOV EAX,0xFFFF
.31:MOV [EDI+PFMZ_DOS_HEADER.e_maxalloc],AX ; Suggested maximal memory allocation for the image.
    ; Find the last STACK segment to EDX.
    XOR EDX,EDX
    BufferRetrieve [EBX+PGM.SssPtrBuf]
    SHR ECX,2
    JZ .40:
.34:LODSD
    JNSt [EAX+SSS.Status],sssSegment,.37:
    JNSt [EAX+SSS.Purpose],sssPurposeSTACK,.37:
    MOV EDX,EAX
.37:LOOP .34:
.40:TEST EDX
    Msg cc=Z,'3922' ; Missing segment with PURPOSE=STACK.
    JZ .43:
    MOV EAX,[EDX+SSS.BottomLow]
    MOV ECX,EAX
    SHR EAX,4
    MOV [EDI+PFMZ_DOS_HEADER.e_ss],AX
    MOV EAX,[EDX+SSS.TopLow]
    SUB EAX,ECX
    MOV [EDI+PFMZ_DOS_HEADER.e_sp],AX
.43: ; Reevaluate entry point which may refer to unresolved external symbol.
    Invoke PgmEvalEntry::,EBX
    LEA EDX,[EBX+PGM.EntryExp]
.46:MOV ECX,[EDX+EXP.Status]
    LEA EAX,[EBX+PGM.Pgmopt.EntryPtr]
    Dispatch CL,'A','N','F',0
    Msg '7711',EAX ; Invalid program entry point "!1S".
    JMP .N:
.0: Msg '7710' ; Missing program entry point.
    JMP .N:
.F: ; Entry EDX is specified as immediate far pointer, e.g. ENTRY=0x0040:1234h.
    Msg '2921',EAX ; Nonrelocable entry point "!1S" is not supported by linker.
    MOV ECX,[EDX+EXP.Seg]
    MOV EAX,[EDX+EXP.Low]
    JMP .64:
.N: ; Entry EDX is specified as absolute offset (no segment), e.g. ENTRY=100h.
    ; Assume it is the offset in the first code segment.
    BufferRetrieve [EBX+PGM.SssPtrBuf]
    JECXZ .58:
.49:LODSD
    JNSt [EAX+SSS.Status],sssSegment,.52:
    JSt [EAX+SSS.Purpose],sssPurposeCODE,.55:
.52:LOOP .49:
    JMP .58:
.55:MOV ECX,[EAX+SSS.BottomLow]
.58:MOV EAX,[EDX+EXP.Low]
    JMP .64:
.A: ; Entry EDX is specified as an address symbol, e.g. ENTRY=Main.
    ; It was already relocated withing image or it may be external.
    MOV ESI,[EDX+EXP.Seg]
    JNSt [ESI+SSS.Status],sssExtern,.60:
    ; ESI is extern pseudosegment of entry in linked module.
    MOV EAX,[EDX+EXP.Low]
    MOV ECX,[ESI+SSS.SymPtr]
    JECXZ .60:
    ADD EAX,[ECX+SYM.OffsetLow] ; ECX is matched public symbol.
    MOV ECX,[ECX+SYM.Section]
    JECXZ .60:
    MOV ECX,[ECX+SSS.SegmPtr] ; Segment in base program.
    JECXZ .60:
    ADD EAX,[ECX+SSS.BottomLow]
    MOV ECX,[ECX+SSS.GroupPtr] ; Group in linked program.
    JECXZ .60:
    MOV EDX,[ECX+SSS.GroupPtr] ; Group in base program.
    MOV ECX,[EDX+SSS.BottomLow]
    SUB EAX,ECX ; EAX is now entry offset relative to base group.
    JMP .64:
.60:PUSH EDX ; Temporary save pointer to entry expression.
      MOV EBX,ESI
      MOV ECX,[ESI+SSS.GroupPtr]
      JECXZ .61:
      MOV ESI,ECX
.61: ; ESI is now frame (code group or ungrouped segment). EBX is segment.
      MOV EAX,[EBX+SSS.BottomLow]
      MOV EDX,[EBX+SSS.BottomHigh]
      SUB EAX,[ESI+SSS.BottomLow]
      SBB EDX,[ESI+SSS.BottomHigh]
    POP EDX
    ADD EAX,[EDX+EXP.Low]
    ADC EDX,[EDX+EXP.High]
    MOV ECX,[ESI+SSS.BottomLow]
.64: ; ECX is RVA of entry group, EAX is entry offset.
    MOV EDX,0x0000_000F
    AND EDX,ECX ; Nonzero when the group is not paragraph aligned.
    ADD EAX,EDX
    SHR ECX,4
    MOV [EDI+PFMZ_DOS_HEADER.e_ip],AX
    MOV [EDI+PFMZ_DOS_HEADER.e_cs],CX
    ; Calculate file checksum.
    XOR EDX,EDX ; Checksum word accumulator.
    LEA ESI,[%MzDosHeader]
    MOV ECX,SIZE# PFMZ_DOS_HEADER /2
.67:LODSW
    ADD EDX,EAX
    LOOP .67:
    BufferRetrieve [%MzRelocBuffer]
    SHR ECX,1
    JZ .73:
.70:LODSW
    ADD EDX,EAX
    LOOP .70:
.73:BufferRetrieve [%MzImageBuffer]
    SUB EBX,EBX
    JECXZ .82:
    SHR ECX,1
    JNC .76:
    INC EBX ; Round up file size to even.
    BufferStoreByte [%MzImageBuffer],0 ; Stuff the file before calculating checksum.
.76:BufferRetrieve [%MzImageBuffer]
    SHR ECX,1
.79:LODSW
    ADD EDX,EAX
    LOOP .79:
    BufferDecrement [%MzImageBuffer],Size=EBX ; Remove temporary stuff NULL byte if EBX=1.
.82:NOT EDX
    MOV [EDI+PFMZ_DOS_HEADER.e_csum],DX
    ; File is completly compiled in buffers.
    MOV EBX,[%OutputStream]
    LEA ESI,[%MzDosHeader]
    StreamStore EBX,ESI,SIZE#PFMZ_DOS_HEADER
    BufferRetrieve [%MzRelocBuffer]
    StreamStore EBX,ESI,ECX
    BufferRetrieve [%MzImageBuffer]
    StreamStore EBX,ESI,ECX
    Invoke EaBufferRelease::,[%MzRelocBuffer]
.90:EndProcedure PfmzCompile
↑ PfmzDefaultStack Pgm
PfmzDefaultStack will create implicit segment [STACK] with size specified by the option PROGRAM SIZEOFSTACKCOMMIT= (factory-default is 4KB), when all of theese conditions are met:
Input
Pgm is pointer to PGM representing the completely assembled and combined program.
Output
-
Error
-
Invoked from
PfOutput
Invokes
SssCreate SssFind
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::+EA.Eaopt+EAOPT.Status],eaoptAUTOSEGMENT,.90:
    Invoke SssFind::,sssSegment,0,=B"STACK",5,EBX
    JNC .90:
    MOV EDX,[EBX+PGM.SssList]
    ListGetLast EDX
    JZ .50:
.10:JNSt [EAX+SSS.Status],sssSegment,.40:
    JSt [EAX+SSS.Purpose],sssPurposeSTACK,.90:
.40:ListGetPrev EAX
    JNZ .10:
.50: ; No stack segment found. Implicit [STACK] will be created.
    Invoke SssCreate::,[EBX+PGM.CurrentStm],0,=B"STACK",5, \
       sssSegment+sssStack+sssImplicit+sssUsed,sssPurposeSTACK, 16
    JSt [EAX+SSS.Status],sssWidth32 | sssWidth64, .60:
    SetSt [EAX+SSS.Status],sssWidth16 ; If the width wasn't specified.
.60:MOV ECX,[EBX+PGM.Pgmopt.SizeOfStackCommitLow]
    MOV [EAX+SSS.TopLow],ECX
.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.
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▲