| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# pfpe.htm
Structures
PFPE_DATA_DIRECTORY
PFPE_EXPORT_DIRECTORY
PFPE_IDATA_MAP
PFPE_IMPORT_DESCRIPTOR
PFPE_OPTIONAL_HEADER32
PFPE_OPTIONAL_HEADER64
PFPE_BASERELOC
Encodings
PFPE_encodings
Procedures
PfpeBaserelocCreate
PfpeBaserelocFixup
PfpeCompile
PfpeExportCreate
PfpeExportFixup
PfpeImportCreate
PfpeImportFixup
PfpeLoadStubFile
PfpeLoadPgm
PfpeOptionalHeader

This source PFPE generates EuroAssembler output executable file in program format PE. as described in [MS_PECOFF].

         EUROASM NOWARN=2101
    pfpe 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,msg.htm,pf.htm,pfcoff.htm,pfmz.htm,pgm.htm, \
                     pgmopt.htm,reloc.htm,sss.htm,stm.htm,sym.htm

     pfpe HEAD ; Start module interface.

↑ PFPE_DATA_DIRECTORY
  Substructure used in PFPE_OPTIONAL_HEADER32.DataDirectory

    PFPE_DATA_DIRECTORY STRUC
     .VirtualAddress D DWORD ; RVA of the table (relative to ImageBase).
     .Size           D DWORD ; Number of bytes in the directory table.
     ENDSTRUC PFPE_DATA_DIRECTORY

↑ PFPE_OPTIONAL_HEADER32
  32bit COFF optional header used in image files (PE,DLL).

    PFPE_OPTIONAL_HEADER32 STRUC
     .Magic                       D WORD  ; 0x010B=PE executable, 0x0107=ROMimage.
     .MajorLinkerVersion          D BYTE
     .MinorLinkerVersion          D BYTE
     .SizeOfCode                  D DWORD ; Total size of all sections with PURPOSE=CODE.
     .SizeOfInitializedData       D DWORD ; Total size of all sections with PURPOSE=DATA.
     .SizeOfUninitializedData     D DWORD ; Total size of all sections with PURPOSE=BSS.
                                  ; 10h.
     .AddressOfEntryPoint         D DWORD ; Entry offset relative to ImageBase, or 0.
     .BaseOfCode                  D DWORD ; Code section offset relative to ImageBase.
     .BaseOfData                  D DWORD ; Data section offset relative to ImageBase.
     .ImageBase                   D DWORD ; Preferred VA of the image, 64K aligned. NT additional fields.
                                  ; 20h.
     .SectionAlignment            D DWORD ; Power of 2, must be > .FileAlignment, default=4K.
     .FileAlignment               D DWORD ; Power of 2, 512..64K, default=512.
     .MajorOperatingSystemVersion D WORD  ; Required version of required OS.
     .MinorOperatingSystemVersion D WORD
     .MajorImageVersion           D WORD  ; Version of this image.
     .MinorImageVersion           D WORD
                                  ; 30h.
     .MajorSubsystemVersion       D WORD  ; Required version of subsystem.
     .MinorSubsystemVersion       D WORD
     .Win32VersionValue           D DWORD ; Reserved, must be 0.
     .SizeOfImage                 D DWORD ; Size of image loaded in memory, rounded up to .SectionAlignment.
     .SizeOfHeaders               D DWORD ; Size of stub+PE header+section headers, rounded up to .FileAlignment.
                                  ; 40h.
     .CheckSum                    D DWORD
     .Subsystem                   D WORD  ; DictProgramSubsystems.Data value.
     .DllCharacteristics          D WORD  ; See DLL_CHARACTERSTICS below.
     .SizeOfStackReserve          D DWORD
     .SizeOfStackCommit           D DWORD
                                  ; 50h.
     .SizeOfHeapReserve           D DWORD
     .SizeOfHeapCommit            D DWORD
     .LoaderFlags                 D DWORD ; Reserved, must be 0.
     .NumberOfRvaAndSizes         D DWORD ; Number of following .DataDirectory entries.
                                  ; 60h.
     .DataDirectory               DS 16*PFPE_DATA_DIRECTORY ; See indexes 0..15 in PFPE_encodings below.
      ENDSTRUC PFPE_OPTIONAL_HEADER32 ; Size# = 224 = 0E0h.

↑ PFPE_OPTIONAL_HEADER64
  64bit COFF optional header used in image files (PE,DLL).

    PFPE_OPTIONAL_HEADER64 STRUC
     .Magic                         D WORD ;  0x20B=PE32+ (64bit executable).
     .MajorLinkerVersion            D BYTE ; Standard members have identical offsets in 32bit and 64bit versions.
     .MinorLinkerVersion            D BYTE
     .SizeOfCode                    D DWORD
     .SizeOfInitializedData         D DWORD
     .SizeOfUninitializedData       D DWORD
                                    ; 10h.
     .AddressOfEntryPoint           D DWORD
     .BaseOfCode                    D DWORD
     ;  .BaseOfData                   DWORD ; Omitted in 64bit version in favour of qword .ImageBase.
     .ImageBase                     D QWORD
                                    ; 20h.
     .SectionAlignment              D DWORD
     .FileAlignment                 D DWORD
     .MajorOperatingSystemVersion   D WORD
     .MinorOperatingSystemVersion   D WORD
     .MajorImageVersion             D WORD
     .MinorImageVersion             D WORD
                                    ; 30h.
     .MajorSubsystemVersion         D WORD
     .MinorSubsystemVersion         D WORD
     .Win32VersionValue             D DWORD
     .SizeOfImage                   D DWORD
     .SizeOfHeaders                 D DWORD
                                    ; 40h.
     .CheckSum                      D DWORD
     .Subsystem                     D WORD
     .DllCharacteristics            D WORD  ; See DLL_CHARACTERSTICS below.
     .SizeOfStackReserve            D QWORD ; This and following members have different offsets in 32 and 64bit version.
                                    ; 50h.
     .SizeOfStackCommit             D QWORD
     .SizeOfHeapReserve             D QWORD
                                    ; 60h.
     .SizeOfHeapCommit              D QWORD
     .LoaderFlags                   D DWORD
     .NumberOfRvaAndSizes           D DWORD
                                    ; 70h.
     .DataDirectory                 DS 16*PFPE_DATA_DIRECTORY ; See indexes 0..15 in PFPE_encodings below.
     ENDSTRUC PFPE_OPTIONAL_HEADER64 ; Size# = 240 = 0F0h.

↑ PFPE_BASERELOC
  This structure describes one base relocation block. Dword-aligned blocks are emitted by the linker in `[.reloc]` section of PE and DLL executable files.
  Base relocation blocks will be used by loader only when the image could not be loaded at the preferred ImageBase (4 MB for PE, 256 MB for DLL).
  See also PFCOFF_RELOCATION used in COFF object files, and RELOC used internally by €ASM.

    PFPE_BASERELOC STRUC
     .PageRVA    D DWORD ; RVA of raw data which may need base-relocation by this block.
     .BlockSize  D DWORD ; Size of this block of relocations including .PageRVA and .BlockSize.
     .TypeOffset D 0 * WORD ; Variable number of words which combine type and offset in 4+12 bits.
     ENDSTRUC PFPE_BASERELOC

↑ PFPE_IDATA_MAP
  This is an €ASM internal structure which describes contents of PE section `[.idata]` created by PfpeImportCreate.
  Each `.Offset*` member specifies offset of the table within the emitted contents of section `[.idata]`.

    PFPE_IDATA_MAP STRUC
    .IdataPtr  D DWORD ; Pointer to SSS section [.idata].
    .OffsetIAT D DWORD ; Offset of Import Address Table. Always 0.
    .OffsetIDT D DWORD ; Offset of Import Descriptor Table.
    .OffsetILT D DWORD ; Offset of Import Lookup Table.
    .OffsetONT D DWORD ; Offset of Ordinal+Name Table.
    .OffsetDNT D DWORD ; Offset of Dll Names Table.
    .OffsetSPT D DWORD ; Offset of Stub Proxy Table.
    .OffsetEND D DWORD ; Offset of end-of tables, i.e. the size of section [.idata].
     ENDSTRUC PFPE_IDATA_MAP ; Size# = 32 = 020h.

↑ PFPE_EXPORT_DIRECTORY
  COFF export properties, used in PfpeExportCreate.

    PFPE_EXPORT_DIRECTORY STRUC
     .Characteristics    D DWORD ; Reserved, must be 0.
     .TimeDateStamp      D DWORD ; Time when the export data was created.
     .MajorVersion       D WORD  ; User-defined version number of the export.
     .MinorVersion       D WORD  ; Identical with ImageVersion in optional PE header.
     .Name               D DWORD ; RVA of DNT (ASCIIZ DLL name).
     .Base               D DWORD ; Starting ordinal number, always 1.
     .NumberOfFunctions  D DWORD ; Number of DWORD entries in EAT (Export Address Table).
     .NumberOfNames      D DWORD ; Number of DWORD entries in NPT and WORD entries in OPT.
     .AddressOfFunctions D DWORD ; RVA of EAT (Export Address Table).
     .AddressOfNames     D DWORD ; RVA of NPT (Name Pointer Table).
     .AddressOfOrdinals  D DWORD ; RVA of ONT (Ordinal Numbers Table).
     ENDSTRUC PFPE_EXPORT_DIRECTORY ; Size# = 40 = 028h.

↑ PFPE_IMPORT_DESCRIPTOR
  COFF import properties, used in PfpeImportCreate.

    PFPE_IMPORT_DESCRIPTOR STRUC
     .OriginalFirstThunk    D DWORD ; RVA of the table with name/ordinal for each import. 0 to terminate chain.
     .TimeDateStamp         D DWORD ; Time of the DLL, or 0 until the image is bound.
     .ForwarderChain        D DWORD ; Index of 1st forwarder reference or -1 if no forwarders.
     .Name                  D DWORD ; RVA of ASCIIZ DLL name.
     .FirstThunk            D DWORD ; RVA of IAT. If bound, this IAT has actual addresses.
     ENDSTRUC PFPE_IMPORT_DESCRIPTOR

↑ PFPE_encodings
  Following symbolic encodings was adopted from Win32 SDK WINNT.h.
See also
  SssPurposeEnc.

    ; PFPE_OPTIONAL_HEADER32.DataDirectory and PFPE_OPTIONAL_HEADER64.DataDirectory indexes:
    pfpeDIRECTORY_ENTRY_EXPORT         =  0   ; Export Directory.
    pfpeDIRECTORY_ENTRY_IMPORT         =  1   ; Import Directory.
    pfpeDIRECTORY_ENTRY_RESOURCE       =  2   ; Resource Directory.
    pfpeDIRECTORY_ENTRY_EXCEPTION      =  3   ; Exception Directory.
    pfpeDIRECTORY_ENTRY_SECURITY       =  4   ; Security (certificate) Directory.
    pfpeDIRECTORY_ENTRY_BASERELOC      =  5   ; Base Relocation Table.
    pfpeDIRECTORY_ENTRY_DEBUG          =  6   ; Debug Directory.
    pfpeDIRECTORY_ENTRY_COPYRIGHT      =  7   ; (X86 usage)
    pfpeDIRECTORY_ENTRY_ARCHITECTURE   =  7   ; Architecture Specific Data. Must be 0.
    pfpeDIRECTORY_ENTRY_GLOBALPTR      =  8   ; RVA of the value in GPTR register.
    pfpeDIRECTORY_ENTRY_TLS            =  9   ; TLS Directory.
    pfpeDIRECTORY_ENTRY_LOAD_CONFIG    = 10   ; Load Configuration Directory.
    pfpeDIRECTORY_ENTRY_BOUND_IMPORT   = 11   ; Bound Import Directory in headers.
    pfpeDIRECTORY_ENTRY_IAT            = 12   ; Import Address Table.
    pfpeDIRECTORY_ENTRY_DELAY_IMPORT   = 13   ; Delay Load Import Descriptors.
    pfpeDIRECTORY_ENTRY_CLR            = 14   ; CLR Runtime descriptor.

    ; PFPE_OPTIONAL_HEADER32.DllCharacteristic.
    pfpeDLLCHARACTERISTICS_HIGH_ENTROPY_VA       = 0x0020 ; ASLR with 64 bit address space.
    pfpeDLLCHARACTERISTICS_DYNAMIC_BASE          = 0x0040 ; The DLL can be relocated at load time.
    pfpeDLLCHARACTERISTICS_FORCE_INTEGRITY       = 0x0080 ; Code integrity checks are forced.
    pfpeDLLCHARACTERISTICS_NX_COMPAT             = 0x0100 ; The image is compatible with data execution prevention (DEP).
    pfpeDLLCHARACTERISTICS_NO_ISOLATION          = 0x0200 ; The image is isolation aware, but should not be isolated.
    pfpeDLLCHARACTERISTICS_NO_SEH                = 0x0400 ; The image does not use structured exception handling (SEH).
    pfpeDLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000 ; The image is terminal server aware.

    ; PFPE_BASERELOC.TypeOffset base-relocation width specifiers:
    pfpeREL_BASED_ABSOLUTE EQU  0 << 12 ; Empty relocation used to pad a block.                      ;>>
    pfpeREL_BASED_LOW      EQU  2 << 12 ; Relocate the  word at Offset.                              ;>>
    pfpeREL_BASED_HIGHLOW  EQU  3 << 12 ; Relocate the dword at Offset.                              ;>>
    pfpeREL_BASED_DIR64    EQU 10 << 12 ; Relocate the qword at Offset.                              ;>>

     ENDHEAD pfpe  ; End of module interface.

↑ PfpeOptionalHeader OptionalHeader, PgmPtr
  PfpeOptionalHeader will initizalize PE optional header structure of PE or DLL format and set those members which can be derived from program specified with PgmPtr at the moment of executable file construction.
Input
  OptionalHeader is pointer to PFPE_OPTIONAL_HEADER32 or PFPE_OPTIONAL_HEADER64 object, allocated by the caller.
  Which of the both classes will be actually used depends on program width.
  PgmPtr Pointer to the compiled PGM.
Output
  Following members of OptionalHeader are filled: `.Magic`, `.AddressOfEntryPoint`, `ImageBase`, `SectionAlignment`, `FileAlignment`, `Subsystem`, `*Version, SizeOfStack*`, `SizeOfHeap*, NumberOfRvaAndSizes`.
  Other members are zeroed.
Error
  CF=1 Errors are reported with macro Msg.
Invoked by
  PfpeCompile
Invokes
  EaBufferRelease EaBufferReserve SssFindByPurpose SymFindByName

    PfpeOptionalHeader Procedure OptionalHeader, PgmPtr
        MOV EDI,[%OptionalHeader]
        MOV EBX,[%PgmPtr]
        Clear EDI,Size=SIZE#PFPE_OPTIONAL_HEADER64 ; Clear the longer variant.
        ; PFPE_OPTIONAL_HEADER32.Magic.
        MOV CX,0x020B                              ; 64bit execu`table.
        JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.10:
        MOV CX,0x010B                              ; 32bit executable.
    .10:MOV [EDI+PFPE_OPTIONAL_HEADER32.Magic],CX
        ; PFPE_OPTIONAL_HEADER32.AddressOfEntryPoint.
        MOV ECX,[EBX+PGM.Pgmopt.EntrySize]
        MOV ESI,[EBX+PGM.Pgmopt.EntryPtr]
        TEST ECX
        JNZ .12:
        JSt [EBX+PGM.Pgmopt.Status],pgmoptExportable,.19: ; PROGRAM ENTRY is optional in DLL format.
        Msg '7710'                                 ; "PROGRAM ENTRY=" is mandatory in this program format.
    .11:; Find the surrogate ENTRY as the bottom of the first CODE section. This will make PE valid in spite of E7710.
        Invoke EaBufferReserve::,%^PROC
        Invoke SssFindByPurpose::,sssSegment,sssPurposeCODE,sssNotBSS,0,EBX,EAX
        BufferRetrieve EAX
        Invoke EaBufferRelease::,EAX
        TEST ECX
        JZ .19:
        MOV ECX,[ESI]                              ; ECX is the first CODE section.
        XOR EAX,EAX
        XOR EDX,EDX
        JMP .17:
    .12:StripColons ESI,ECX                        ; ESI,ECX is the raw ENTRY= value.
        Invoke SymFindByName::, symPublic,ESI,ECX,EBX
        JNC .15:
        Invoke SymFindByName::, symWeak,ESI,ECX,EBX
        JNC .15:
        LEA EAX,[EBX+PGM.Pgmopt.EntryPtr]
        Msg '7711',EAX                             ; "PROGRAM ENTRY=!1S" symbol was not found.
        JMP .11:                                   ; Use the bottom of CODE section instead.
    .15:MOV ECX,[EAX+SYM.Section]                  ; Entry symbol EAX was found.
        MOV EDX,[EAX+SYM.OffsetHigh]
        MOV EAX,[EAX+SYM.OffsetLow]
    .17:JECXZ .18:
        ADD EAX,[ECX+SSS.BottomLow]
        ADC EDX,[ECX+SSS.BottomHigh]               ; EDX:EAX is now VA or entry point.
        SUB EAX,[EBX+PGM.Pgmopt.ImageBaseLow]      ; Convert to RVA.                                 ;
        SBB EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]                                                       ;
        JZ .18:
        LEA EAX,[EBX+PGM.Pgmopt.EntryPtr]
        Msg '7712',EAX                             ; "PROGRAM ENTRY=!1S" is above 4 GB. Ignored.
        SUB EAX,EAX
    .18:MOV [EDI+PFPE_OPTIONAL_HEADER32.AddressOfEntryPoint],EAX
    .19:; PFPE_OPTIONAL_HEADER32 | PFPE_OPTIONAL_HEADER64 standard members.
        MOV EAX,[EBX+PGM.Pgmopt.SectionAlign]
        MOV EDX,[EBX+PGM.Pgmopt.FileAlign]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SectionAlignment],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.FileAlignment],EDX
        MOV EAX,[EBX+PGM.Pgmopt.MinorOsVersion]
        MOV EDX,[EBX+PGM.Pgmopt.MajorOsVersion]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MinorOperatingSystemVersion],AX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MajorOperatingSystemVersion],DX
        MOV EAX,[EBX+PGM.Pgmopt.MinorImageVersion]
        MOV EDX,[EBX+PGM.Pgmopt.MajorImageVersion]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MinorImageVersion],AX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MajorImageVersion],DX
        MOV EAX,[EBX+PGM.Pgmopt.MinorSubsystemVersion]
        MOV EDX,[EBX+PGM.Pgmopt.MajorSubsystemVersion]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MinorSubsystemVersion],AX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MajorSubsystemVersion],DX
        MOV EAX,[EBX+PGM.Pgmopt.MinorLinkerVersion]
        MOV EDX,[EBX+PGM.Pgmopt.MajorLinkerVersion]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MinorLinkerVersion],AL
        MOV [EDI+PFPE_OPTIONAL_HEADER32.MajorLinkerVersion],DL
        MOV ECX,[EBX+PGM.Pgmopt.Win32VersionValue]
        MOV EAX,[EBX+PGM.Pgmopt.Subsystem]
        MOV EDX,[EBX+PGM.Pgmopt.DllCharacteristics]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.Win32VersionValue],ECX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.Subsystem],AX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.DllCharacteristics],DX
        ; PFPE_OPTIONAL_HEADER32 | PFPE_OPTIONAL_HEADER64 version-specific members.
        MOV EAX,[EBX+PGM.Pgmopt.ImageBaseLow]
        MOV EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
        MOV ECX,16                                 ; Number of data directory records in optional header.
        JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.60:
        MOV [EDI+PFPE_OPTIONAL_HEADER32.ImageBase],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.NumberOfRvaAndSizes],ECX
        JMP .65:
    .60:MOV [EDI+PFPE_OPTIONAL_HEADER64.ImageBase+0],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.ImageBase+4],EDX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.NumberOfRvaAndSizes],ECX
    .65:MOV EAX,[EBX+PGM.Pgmopt.SizeOfHeapCommitLow]
        MOV EDX,[EBX+PGM.Pgmopt.SizeOfHeapCommitHigh]
        MOV ECX,[EBX+PGM.Pgmopt.SizeOfHeapReserveLow]
        MOV ESI,[EBX+PGM.Pgmopt.SizeOfHeapReserveHigh]
        JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.70:
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SizeOfHeapCommit],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SizeOfHeapReserve],ECX
        JMP .75:
    .70:MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfHeapCommit+0],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfHeapCommit+4],EDX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfHeapReserve+0],ECX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfHeapReserve+4],ESI
    .75:MOV EAX,[EBX+PGM.Pgmopt.SizeOfStackCommitLow]
        MOV EDX,[EBX+PGM.Pgmopt.SizeOfStackCommitHigh]
        MOV ECX,[EBX+PGM.Pgmopt.SizeOfStackReserveLow]
        MOV ESI,[EBX+PGM.Pgmopt.SizeOfStackReserveHigh]
        JSt [EBX+PGM.Pgmopt+PGMOPT.Status],pgmoptWidth64,.80:
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SizeOfStackCommit],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SizeOfStackReserve],ECX
        JMP .90:
    .80:MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfStackCommit+0],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfStackCommit+4],EDX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfStackReserve+0],ECX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.SizeOfStackReserve+4],ESI
    .90:EndProcedure PfpeOptionalHeader

↑ PfpeLoadPgm BasePgm, ObjBegin, ObjEnd, FileNamePtr
  Executable format PE 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

    PfpeLoadPgm Procedure BasePgm, ObjBegin, ObjSize, FileNamePtr
        Msg '8534',Dict_FormatPE::,[%FileNamePtr]    ; Format !1S of file "!2$" is not linkable.
       EndProcedure PfpeLoadPgm

↑ PfpeImportCreate Program, IdataMapPtr
  PfpeImportCreate creates a new auxilliary section with name `[.idata]` and `PURPOSE=IMPORT+IAT` in the main Program.
  Division of the section are:
  1. IAT (Import Address Table) is a copy of ILT as compiled at link-time. It will be fixed up by the loader at bind time and the offsets of ONT records will be replaced with absolute DWORD|QWORD pointer to the imported function loaded in memory.
  2. IDT (Import Descriptor Table) of PFPE_IMPORT_DESCRIPTOR records, one per each imported DLL. The table is terminated with an empty record.
  3. ILT (Import Lookup Table) of DWORD|QWORD offsets into ONT, one offset per each imported symbol. Offsets are grouped by DLL, after the last import offset of each DLL there is a NULL offset which terminates the group.
     Offsets are RVA (related to the ImageBase).
  4. ONT (Ordinal+Name Table) is concatenation of 16bit ordinal number and ASCIIZ string with symbol name. There is one word-aligned Ordinal-Name concatination per each imported symbol.
  5. DNT (Dll Names Table) with ASCIIZ names of each used DLL.
  6. SPT (Stub Proxy Table) with indirect (dword or qword) absolute near jump instruction per import. Each such proxy jump is 7 bytes long and it uses DWORD|QWORD pointer in IAT as its indirect DWORD target. DWORD target in the body of proxy jump needs relocation if the PE|DLL could not be loaded at its preferred ImageBase virtual address at run-time.
     Every reference made to an imported symbol in assembler source is in fact referring to this proxy jump inside `[.idata]` section.

  Type of pointers in ILT and IAT (DWORD|QWORD) is determined by the program width (32|64).

  When the section is created, its RVA is not known ( PgmLink wasn't invoked yet) and pointers in ILT, IAT, IDT are related to RVA=0. Hence PfpeImportFixup must be invoked later to fixup the RVAs.

  Each import creates a new public symbol with offset pointing to proxy jumps in SPT.

  Offsets returned in IdataMapPtr can be used to calculate IMPORT and IAT data directory entries in PE optional header.

  Section `[.idata]` will not be created when no symbol with `symImport && symReferenced` is found in program.

Input
  Program points to PE|DLL PGM which is being linked.
  IdataMapPtr is pointer to an empty PFPE_IDATA_MAP allocated by the caller, and it will be filled with offsets of section tables.
Output
  New segment `[.idata]` is created and appended on Program.SssList.
  Output structure at IdataMapPtr is filled with pointers to tables.
  The structure is zeroed and no section is created when the program does not use imported symbols.
Error
  Errors are reported with macro Msg.
See also
  PfpeImportFixup
Invoked by
  PfpeCompile
Invokes
  EaBufferAlign EaBufferRelease EaBufferReserve SssCreateSe SymLowcaseDll

    PfpeImportCreate Procedure Program, IdataMapPtr
    SssPtr    LocalVar ; Pointer to SSS [.idata].
    SymImpBuf LocalVar ; BUFFER for pointers to imported symbols.
    SymPubBuf LocalVar ; Buffer for pointers to new created public symbols.
    DllPtrBuf LocalVar ; Buffer with Ptr+Size of DLL names used in imports.
    ILTbuffer LocalVar ; Buffer with thunks (dword or qword RVA pointers into ONT).
    IDTbuffer LocalVar ; Buffer with PFPE_IMPORT_DESCRIPTOR records.
    ONTbuffer LocalVar ; Buffer with 16bit ordinal + ASCIIZ symbol name strings.
    DNTbuffer LocalVar ; Buffer with ASCCIZ DLL name strings.
    SPTbuffer LocalVar ; Buffer with JMPN instructions to offsets from IAT.
    IDTmember LocalVar Size=SIZE# PFPE_IMPORT_DESCRIPTOR ; Temporary record of IDT.
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%SymImpBuf],EAX
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%SymPubBuf],EAX
        Clear [%IdataMapPtr],Size=SIZE#PFPE_IDATA_MAP
        MOV EBX,[%Program]
        ; Collect import symbols actually used in this program into %SymImpBuf.
        SUB ECX,ECX
        ListGetFirst [EBX+PGM.SymList]
        JZ .25:                                      ; Loop .10: .. .20: collects referenced import symbols.
    .10:JNSt [EAX+SYM.Status],symImport,.20:
        BufferStoreDword [%SymImpBuf],EAX
        CMP [EAX+SYM.DllNameSize],ECX
        JNE .20:                                     ; Skip default if the DLL is already specified.
        MOVD [EAX+SYM.DllNamePtr],=B"%EuroasmDefaultDllName"
        MOVD [EAX+SYM.DllNameSize],%EuroasmDefaultDllNameSize
    .20:ListGetNext EAX                              ; The next symbol.
        JNZ .10:
    .25:BufferRetrieve [%SymImpBuf]
        SHR ECX,2                                    ; ECX=Number of imports.
        JZ .90:                                      ; If no import is used in this program, do not create section [.idata].
        ; Prepare to construct import data.
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%DllPtrBuf],EAX
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%ILTbuffer],EAX
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%IDTbuffer],EAX
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%ONTbuffer],EAX
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%DNTbuffer],EAX
        Invoke EaBufferReserve::,PfpeImportCreate
        MOV [%SPTbuffer],EAX
        ; Collect used dynamic libraries names into DllPtrBuf in a loop .31: .. .39:.
        ; ESI points to an array of ECX pointers to import symbol.
    .31:LODSD                                        ; EAX is now pointer to a referenced import symbol.
        Invoke SymLowcaseDll::,EAX
        MOV EDI,[EAX+SYM.DllNamePtr]
        MOV EDX,[EAX+SYM.DllNameSize]
        PUSH ECX,ESI                                 ; Check if DLL name EDI,EDX already is on DllPtrBuf.
          BufferRetrieve [%DllPtrBuf]
          JECXZ .35:                                 ; If empty, go and store EDI,EDX.
    .32:  Compare EDI,EDX,[ESI+0],[ESI+4]
          JE .39:                                    ; Skip when DLL EDI,EDX was already stored.
          ADD ESI,8
          SUB ECX,8
          JNZ .32:                                   ; The next DLL.
    .35:  BufferStoreDword [%DllPtrBuf],EDI
          BufferStoreDword [%DllPtrBuf],EDX
    .39:POP ESI,ECX
        DEC ECX
        JNZ .31:                                     ; The next import.
        ; Create a new section [idata].
        MOV ECX,pgmoptWidthMask
        AND ECX,[EBX+PGM.Pgmopt.Status]
        OR ECX,sssSegment+sssNotBSS+sssPrivate+sssUsed
        Invoke SssCreateSe::,[EBX+PGM.CurrentStm],0,=B".idata",6, \
                             ECX,sssPurposeIMPORT+sssPurposeIAT,8
        MsgUnexpected cc=C
        MOV [%SssPtr],EAX                            ; EAX=^SSS - the new [.idata] segment.
        ; Initialize static fields in %IDTmember, based on DLL names collected in %DllPtrBuf.
        LEA EDI,[%IDTmember]                         ; One temporary record of IDT.
        XOR EAX,EAX
        MOV [EDI+PFPE_IMPORT_DESCRIPTOR.TimeDateStamp],EAX ; Always 0.
        DEC EAX
        MOV [EDI+PFPE_IMPORT_DESCRIPTOR.ForwarderChain],EAX ; Always -1.
        ; Create tables for each DLL which is now in %DllPtrBuf.
        BufferRetrieve [%DllPtrBuf]
        TEST ECX
        JZ .80:                                      ; Outer loop .41: .. .59: through all dynamic libraries.
    .41:PUSH ECX,ESI                                 ; ESI points to QWORD (Ptr,Size) of DLL name.
          LEA EDI,[%IDTmember]
          PUSH ESI
            BufferRetrieve [%DNTbuffer]
            MOV [EDI+PFPE_IMPORT_DESCRIPTOR.Name],ECX; Future offset of DllName in DNT.
            BufferRetrieve [%ILTbuffer]
            MOV [EDI+PFPE_IMPORT_DESCRIPTOR.OriginalFirstThunk],ECX
            MOV [EDI+PFPE_IMPORT_DESCRIPTOR.FirstThunk],ECX
            BufferStore [%IDTbuffer],EDI,SIZE# PFPE_IMPORT_DESCRIPTOR
          POP ESI
          MOV EDI,[ESI+0]
          MOV EDX,[ESI+4]
          BufferStore [%DNTbuffer],EDI,EDX           ; DLL name.
          BufferStoreByte [%DNTbuffer],0             ; ASCIIZ string terminator.
          ; Handle each symbol imported from current DLL named EDI,EDX.
          BufferRetrieve [%SymImpBuf]
          SHR ECX,2
    .42:  LODSD                                      ; Inner loop .42: .. .58: through all symbols from one DLL (EDI,EDX).
          PUSH ECX,EDX,ESI,EDI
            Compare [EAX+SYM.DllNamePtr],[EAX+SYM.DllNameSize],EDI,EDX
            JNE .58:                                 ; Skip symbol EAX when it is not from the current DLL named EDI,EDX.
            ; Create record in ONT (hint-name table).
            BufferRetrieve [%ONTbuffer]              ; ECX is now offset of record within ONT.
            TEST CL,1
            JZ .43:
            BufferStoreByte [%ONTbuffer],0           ; Word alignment of %ONTbuffer.
            INC ECX
    .43:    MOV EDX,[EAX+SYM.OrdinalNr]
            BufferStoreWord [%ONTbuffer],EDX         ; 16bit hint.
            BufferStore [%ONTbuffer],[EAX+SYM.NamePtr],[EAX+SYM.NameSize]
            BufferStoreByte [%ONTbuffer],0           ; ASCIIZ string terminator.
            ; Store dword or qword thunk to ILT (Import Lookup Table).
            JSt [EAX+SYM.Status],symImportedByOrd,.45:
            ; Import by name pointed to by ECX.
            PUSH ECX
              BufferRetrieve [%ILTbuffer]
              MOV EDI,ECX                            ; Store offset of thunk to EDI (0,4,8,,, in PE32 or 0,8,16,24,, in PE64).
            POP ECX
            BufferStoreDword [%ILTbuffer],ECX        ; Relative offset in ONT.
            JNSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.50:
            BufferStoreDword [%ILTbuffer],0          ; PE64 uses qword thunks.
            JMP .50:
    .45:    ; Import by ordinal EDX. MSbit must be set in thunk.
            JNSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.46:
            BufferStoreDword [%ONTbuffer],EDX        ; 64bit mode.
            BufferStoreDword [%ONTbuffer],0x8000_0000; Signalize import by ordinal with MSbit.
            JMP .50:
    .46:    OR EDX,0x8000_0000
            BufferStoreDword [%ONTbuffer],EDX        ; 32bit mode.
    .50:    ; Create public symbol as a copy of the imported symbol EAX. It represents the proxy jump.
            MOV EDX,EAX                              ; Imported symbol.
            ListStore [EBX+PGM.SymList],EAX          ; Save copy of the imported SYM EAX. The new copy is returned in EAX.
            MOV [EDX+SYM.SymbPtr],EAX                ; Let the imported symbol refer to the new public symbol EAX
            SetSt [EDX+SYM.Status],symResolved       ;  and mark it as resolved.
            SetSt [EAX+SYM.Status],symPublic+symImport+symReferenced
            MOV EDX,[%SssPtr]                        ; ^SSS [.idata].
            MOV [EAX+SYM.Section],EDX
            BufferStoreDword [%SymPubBuf],EAX        ; Collect the just created public symbols in SymPubBuf.
            BufferRetrieve [%SPTbuffer]              ; ECX is now offset of proxy jump, relative to SPT.
            MOV [EAX+SYM.OffsetLow],ECX              ; After relocation this will be the pointer to proxy JMPN.
            ; Store proxy jump instruction to SPT. Target of JMPN is specified by EDI (not relocated yet).
            BufferStore [%SPTbuffer],=I"JMPN [0],ADDR=ABS,SCALE=VERBATIM",7
            ; Assembled as FF2425[00000000] in both 32bit and 64bit mode.
            BufferRetrieve [%SPTbuffer]
            LEA ECX,[ESI+ECX-4]                      ; ECX is now pointer to the relocable DWORD [00000000] in SPT.
            ; EDI is stored offset of DWORD|QWORD thunk in ILT (0,4,8,,, or 0,8,16,,, in 64bit mode).
            MOV [ECX],EDI                            ; Rewrite the jump target in the last 4 bytes of JMPN encoding with ILT index.
            ; Create relocation of target IAT in the body of proxy jump instruction.
            MOV EDI,EAX                              ; ^SYM - public symbol in [.idata] segment (proxy jump).
            BufferNew [EDX+SSS.RelocBuffer],SIZE# RELOC ; New absolute relocation record for JMPN's target.
            Clear EAX,Size=SIZE# RELOC
            SetSt [EAX+RELOC.Status],relocAbsVA+relocWidth32
            ; ECX points to disp32 in the encoding of JMPN proxy jump. ESI is bottom of SPT.
            SUB ECX,ESI                              ; Make the pointer to relocated DWORD relative to the start of SPT (which is in ESI).
            MOV [EAX+RELOC.OrgLow],ECX               ; ECX is now 3,10,17,24,,,
            MOV EDX,[%SssPtr]                        ; ^SSS [.idata].
            MOV [EAX+RELOC.Section],EDX
            MOV EDX,[EDX+SSS.SymPtr]                 ; symSe .idata.
            MOV [EAX+RELOC.Symbol],EDX
    .58:  POP EDI,ESI,EDX,ECX
          DEC ECX
          JNZ .42:                                   ; The next symbol.
          ; Terminate ILT of this DLL with NULL thunk.
          BufferStoreDword [%ILTbuffer],0
          JNSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.59:
          BufferStoreDword [%ILTbuffer],0
    .59:POP ESI,ECX
        ADD ESI,8
        SUB ECX,8
        JNZ .41:                                     ; The next DLL.
        LEA EDI,[%IDTmember]
        MOV ECX,SIZE# PFPE_IMPORT_DESCRIPTOR
        Clear EDI,Size=ECX
        BufferStore [%IDTbuffer],EDI,ECX             ; Use NULL directory entry to terminate IDT.
        Invoke EaBufferAlign::,[%IDTbuffer],8        ; The following ILT should be qword aligned.
        MOV EAX,[%SssPtr]
        ; Populate [.idata] section EAX.EmitBuffer with its tables.
        MOV EDI,[%IdataMapPtr]
        MOV [EDI+PFPE_IDATA_MAP.IdataPtr],EAX        ; Return pointer to just created section [.idata].
        SUB EDX,EDX                                  ; EDX keeps offsets of the tables relative to the bottom of section [.idata].
        MOV [EDI+PFPE_IDATA_MAP.OffsetIAT],EDX       ; Section starts with IAT at offset 0.
        BufferRetrieve [%ILTbuffer]                  ; IAT is identical with ILT at link time.
        ADD EDX,ECX
        BufferStore [EAX+SSS.EmitBuffer],ESI,ECX     ; Store IAT.
        MOV [EDI+PFPE_IDATA_MAP.OffsetIDT],EDX
        BufferRetrieve [%IDTbuffer]
        ADD EDX,ECX
        BufferStore [EAX+SSS.EmitBuffer],ESI,ECX     ; Store IDT.
        MOV [EDI+PFPE_IDATA_MAP.OffsetILT],EDX
        BufferRetrieve [%ILTbuffer]
        ADD EDX,ECX
        BufferStore [EAX+SSS.EmitBuffer],ESI,ECX     ; Store ILT.
        MOV [EDI+PFPE_IDATA_MAP.OffsetONT],EDX
        BufferRetrieve [%ONTbuffer]
        ADD EDX,ECX
        BufferStore [EAX+SSS.EmitBuffer],ESI,ECX     ; Store ONT.
        MOV [EDI+PFPE_IDATA_MAP.OffsetDNT],EDX
        BufferRetrieve [%DNTbuffer]
        ADD EDX,ECX
        BufferStore [EAX+SSS.EmitBuffer],ESI,ECX     ; Store DNT.
        MOV [EDI+PFPE_IDATA_MAP.OffsetSPT],EDX
        BufferRetrieve [%SPTbuffer]
        ADD EDX,ECX
        BufferStore [EAX+SSS.EmitBuffer],ESI,ECX     ; Store SPT.
        MOV [EDI+PFPE_IDATA_MAP.OffsetEND],EDX       ; EDX is now the raw size of [.idata] contents.
        MOV [EAX+SSS.TopLow],EDX
        ; Fixup relocations of dwords in the body of proxy jumps.
        MOV EDX,[EDI+PFPE_IDATA_MAP.IdataPtr]        ; ^SSS [.idata].
        BufferRetrieve [EDX+SSS.RelocBuffer]
        JECXZ .70:
        MOV EAX,[EDI+PFPE_IDATA_MAP.OffsetSPT]
        SUB EDX,EDX                                  ; EDX:EAX is now the fixup delta.
    .62:ADD [ESI+RELOC.OrgLow],EAX
        ADC [ESI+RELOC.OrgHigh],EDX
        ADD ESI,SIZE# RELOC
        SUB ECX,SIZE# RELOC
        JNZ .62:                                     ; The next relocation.
    .70:; Fixup offset of created public symbols by SPT offset.
        MOV EDX,[EDI+PFPE_IDATA_MAP.OffsetSPT]
        SUB EDI,EDI                                  ; Fixup delta is EDI:EDX.
        BufferRetrieve [%SymPubBuf]
        SHR ECX,2
        JZ .80:
    .71:LODSD
        ADD [EAX+SYM.OffsetLow],EDX
        ADC [EAX+SYM.OffsetHigh],EDI
    .79:LOOP .71:
    .80:Invoke EaBufferRelease::,[%SPTbuffer]
        Invoke EaBufferRelease::,[%DNTbuffer]
        Invoke EaBufferRelease::,[%ONTbuffer]
        Invoke EaBufferRelease::,[%IDTbuffer]
        Invoke EaBufferRelease::,[%ILTbuffer]
        Invoke EaBufferRelease::,[%DllPtrBuf]
    .90:Invoke EaBufferRelease::,[%SymPubBuf]
        Invoke EaBufferRelease::,[%SymImpBuf]
       EndProcedure PfpeImportCreate

↑ PfpeImportFixup Program, OptionalHeaderPtr, IdataMapPtr
  PfpeImportFixup will update temporary offsets in import section `[.idata]` . It is invoked when PE image was linked by PgmLink and section bottoms fixed.
  PfpeImportFixup also specifies RVA and sizes in Optional Header Data Directory IMPORT and IAT.
Input
  PgmPtr is pointer to the compiled and partially linked PGM.
  OptionalHeaderPtr is pointer to PFPE_OPTIONAL_HEADER32 whose data directories IMPORT and IAT will be updated. When program width is 64, this is the pointer to PFPE_OPTIONAL_HEADER64 instead.
  IdataMapPtr is pointer to PFPE_IDATA_MAP which have been filled with offsets of section tables by PfpeImportCreate.
Output
  Import data section is updated.
Error
  CF=1 Errors are reported with macro Msg.
See also
  PfpeImportCreate.
Invoked by
  PfpeCompile

    PfpeImportFixup Procedure Program, OptionalHeaderPtr, IdataMapPtr
    IdataRVA LocalVar                                ; RVA of [.idata] section.
    IdataPtr LocalVar                                ; Pointer to the emitted contents of [.idata] section.
        MOV EBX,[%Program]
        MOV EDX,[%IdataMapPtr]
        MOV ESI,[EDX+PFPE_IDATA_MAP.IdataPtr]
        TEST ESI
        JZ .90:                                      ; Skil when section [.idata] wasn't created (no imports in image).
        MOV EAX,[ESI+SSS.BottomLow]                  ; VA of [.idata] in memory at run time.
        SUB EAX,[EBX+PGM.Pgmopt.ImageBaseLow]        ; Convert VA to RVA of IAT.
        MOV [%IdataRVA],EAX
        ; Update data directory entries IAT and IMPORT in optional header.
        MOV EDI,[%OptionalHeaderPtr]
        MOV ECX,[EDX+PFPE_IDATA_MAP.OffsetIDT]       ; ECX is now the size of IAT.
        JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.10:
        ; 32bit program.
        MOV [EDI+PFPE_OPTIONAL_HEADER32.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IAT+PFPE_DATA_DIRECTORY.VirtualAddress],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IAT+PFPE_DATA_DIRECTORY.Size],ECX
        ADD EAX,ECX ; EAX is now RVA of IDT.
        MOV ECX,[EDX+PFPE_IDATA_MAP.OffsetEND]
        SUB ECX,[EDX+PFPE_IDATA_MAP.OffsetIDT] ; ECX is now size of IDT+ILT+ONT+DNT+SPT.
        MOV [EDI+PFPE_OPTIONAL_HEADER32.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IMPORT+PFPE_DATA_DIRECTORY.VirtualAddress],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IMPORT+PFPE_DATA_DIRECTORY.Size],ECX
        JMP .20:
    .10:; 64bit program.
        MOV [EDI+PFPE_OPTIONAL_HEADER64.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IAT+PFPE_DATA_DIRECTORY.VirtualAddress],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IAT+PFPE_DATA_DIRECTORY.Size],ECX
        ADD EAX,ECX ; EAX is now RVA of IDT.
        MOV ECX,[EDX+PFPE_IDATA_MAP.OffsetEND]
        SUB ECX,[EDX+PFPE_IDATA_MAP.OffsetIDT]       ; ECX is now the size of IDT+ILT+ONT+DNT+SPT.
        MOV [EDI+PFPE_OPTIONAL_HEADER64.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IMPORT+PFPE_DATA_DIRECTORY.VirtualAddress],EAX
        MOV [EDI+PFPE_OPTIONAL_HEADER64.DataDirectory+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_IMPORT+PFPE_DATA_DIRECTORY.Size],ECX
    .20:BufferRetrieve [ESI+SSS.EmitBuffer]          ; ESI,ECX is now the contents of IAT+IDT+ILT+ONT+DNT+SPT.
        MOV [%IdataPtr],ESI
       ; Fixup Import Address Table.
        MOV ECX,[EDX+PFPE_IDATA_MAP.OffsetIDT]
        ADD ECX,ESI ; ESI..ECX is now contents of IAT.
        MOV EDI,[EDX+PFPE_IDATA_MAP.OffsetONT]
        ADD EDI,[%IdataRVA]                          ; EDI is now delta fixup of dwords/qwords in IAT.
        JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.40:
        ; 32bit program.
        MOV EAX,[ESI+0]
        TEST EAX
        JS .28:                                      ; Do not fixup when imported by ordinal (MSbit is set).
        ADD [ESI],EDI                                ; Do not check thunk at the 1st position in IAT on NULL as it legally refers to 0-offset in ONT.
    .28:LODSD                                        ; Skip the first thunk.
    .30:CMP ESI,ECX
        JNB .60:
        LODSD
        TEST EAX
        JNG .30:                                     ; Skip fixup when EAX=0 or when imported by ordinal (MSbit is set).
        ADD [ESI-4],EDI                              ; Perform the fixup.
        JMP .30:
    .40:; 64bit program.
        MOV EAX,[ESI+0]
        MOV EDX,[ESI+4]
        TEST EDX
        JS .48:                                      ; Do not fixup when imported by ordinal (MSbit is set).
        ADD [ESI+0],EDI                              ; Do not check thunk at the 1st position in IAT on NULL
        ADCD [ESI+4],0                               ;   as it legally refers to 0-offset in ONT.
    .48:ADD ESI,8
    .50:CMP ESI,ECX
        JNB .60:
        LODSD
        XCHG EAX,EDX
        LODSD
        TEST EAX
        JS .50:                                      ; Skip fixup when imported by ordinal (MSbit is set).
        OR EAX,EDX
        JZ .50:                                      ; Skip fixup when NULL.
        ADD  [ESI-8],EDI
        ADCD [ESI-4],0
        JMP .50:
    .60: ; Copy fixed IAT to ILT.
        MOV EDX,[%IdataMapPtr]
        MOV ESI,[EDX+PFPE_IDATA_MAP.OffsetIAT]
        MOV ECX,[EDX+PFPE_IDATA_MAP.OffsetIDT]
        MOV EDI,[EDX+PFPE_IDATA_MAP.OffsetILT]
        SUB ECX,ESI
        SHR ECX,2
        ADD ESI,[%IdataPtr]
        ADD EDI,[%IdataPtr]
        REP MOVSD
        ; Fixup Import Descriptor Table.
        MOV ESI,[%IdataPtr]
        MOV EDI,[%IdataRVA]                          ; Fixup delta to IAT.
        MOV ECX,[EDX+PFPE_IDATA_MAP.OffsetILT]
        MOV EAX,[EDX+PFPE_IDATA_MAP.OffsetDNT]
        ADD ECX,EDI                                  ; Fixup delta to ILT.
        ADD EAX,EDI                                  ; Fixup delta to DNT.
        ADD ESI,[EDX+PFPE_IDATA_MAP.OffsetIDT]
    .70:CMPD [ESI+PFPE_IMPORT_DESCRIPTOR.ForwarderChain],-1
        JNE .90:                                     ; Empty record signalizes end of IDT.
        ADD [ESI+PFPE_IMPORT_DESCRIPTOR.OriginalFirstThunk],ECX
        ADD [ESI+PFPE_IMPORT_DESCRIPTOR.Name],EAX
        ADD [ESI+PFPE_IMPORT_DESCRIPTOR.FirstThunk],EDI
        ADD ESI,SIZE# PFPE_IMPORT_DESCRIPTOR
        JMP .70:                                     ; The next import descriptor (one for each imported DLL).
    .90:EndProcedure PfpeImportFixup

↑ PfpeExportCreate Program
  PfpeExportCreate creates a new auxilliary PE/DLL section with name `[.edata]` and `PURPOSE=EXPORT` in the main Program.
  Division of the section are:
  1. EDT (Export Directory Table) with one PFPE_EXPORT_DIRECTORY structured object. Its members specify other export tables.
  2. EAT (Export Address Table) contains DWORD RVA of exported functions (their entry point).
  3. NPT (Name Pointers Table) contains DWORD RVA of ASCIIZ function names.
  4. ONT (Ordinal Numbers Table) contains WORD ordinal number of function in EAT.
  5. DNT (Dll Name Table) contains ASCIIZ strings with DLL name.
  6. ENT (Export Names Table) contains a series of ASCIIZ strings with function names.
  7. FWD (Forwarded Names Table) contains a series of ASCIIZ strings with forwarded DLL name (without extension "dll") concatenated with function name, e.g. `NTDLL.RtlAllocateHeap`.
  Number of objects in NPT and ONT (dwords and words) is the same, they are synchronized. Function names in ENT are alphabetically sorted.
Input
  Program is pointer to PGM.
Output
  EAX= pointer to SSS segment `[.edata]` created and appended on Program.SssList.
  ECX= offset of ENT related to the start of export section contents.
  EDX= offset of FWD related to the start of export section contents.
Error
  EAX=ECX=EDX=0 when no program symbol is marked as exportable.
See also
  PfpeExportFixup
Invoked by
  PfpeCompile
Invokes
  EaBufferRelease EaBufferReserve EaBufferSort SssCreateSe SymStoreForwarderName

    PfpeExportCreate Procedure Program
    SymExpBuf LocalVar ; BUFFER for pointers to exported symbols.
    Ordinal   LocalVar ; Ordinal number of the current exported symbol.
    EATbuffer LocalVar ; Buffer with RVA of exported symbols.
    NPTbuffer LocalVar ; Buffer with RVA of symbol names.
    ONTbuffer LocalVar ; Buffer with word ordinal numbers.
    DNTbuffer LocalVar ; Buffer with RVA of DLL ASCIIZ names.
    ENTbuffer LocalVar ; Buffer with RVA of exported symbol ASCIIZ names.
    FWDbuffer LocalVar ; Buffer with RVA of forward-exported Dll.symbol ASCIIZ names.
    EDT       LocalVar Size=SIZE#PFPE_EXPORT_DIRECTORY
        XOR EAX,EAX
        MOV [%Ordinal],EAX
        MOV [%ReturnEAX],EAX
        MOV [%ReturnECX],EAX
        MOV [%ReturnEDX],EAX
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%SymExpBuf],EAX
        MOV EDI,EAX
        ; Collect exported public symbols actually used in this program into buffer EDI.
        MOV EBX,[%Program]
        ListGetFirst [EBX+PGM.SymList]
        JZ .25:                                      ; Loop .10: .. .20: collecting exports.
    .10:JSt [EAX+SYM.Status],symResolved,.20:
        JNSt [EAX+SYM.Status],symExport,.20:
        MOV ECX,[EAX+SYM.SymbPtr]
        TEST ECX
        JNZ .11:
        MOV ECX,EAX
        JMP .14:
    .11:MOV EDX,[EAX+SYM.Status]
        SetSt EDX,symResolved
        MOV [EAX+SYM.Status],EDX
        CMPB [ECX+SYM.Status],0
        JNZ .12:
        MOV [ECX+SYM.Status],DL                      ; Inherit symbol type from the resolved one.
    .12:SetSt [EAX+SYM.Status],symExport
    .14:BufferStoreDword EDI,ECX
    .20:ListGetNext EAX
        JNZ .10:
    .25:Invoke EaBufferSort::,EDI                    ; Alphabetically by symbol names.
        BufferRetrieve EDI
        SHR ECX,2                                    ; Number of exports.
        JZ .90:                                      ; If no export is used in this program, do not create section.
        ; Prepare to construct export data.
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%EATbuffer],EAX
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%NPTbuffer],EAX
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%ONTbuffer],EAX
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%DNTbuffer],EAX
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%ENTbuffer],EAX
        Invoke EaBufferReserve::,PfpeExportCreate
        MOV [%FWDbuffer],EAX
        LEA EDI,[%EDT]
        Clear EDI,Size=SIZE#PFPE_EXPORT_DIRECTORY
        MOV EAX,[Ea.Eaopt.TimeStamp::]
        MOV [EDI+PFPE_EXPORT_DIRECTORY.TimeDateStamp],EAX
        MOV EDX,[EBX+PGM.Pgmopt.MajorImageVersion]
        MOV EAX,[EBX+PGM.Pgmopt.MinorImageVersion]
        MOV [EDI+PFPE_EXPORT_DIRECTORY.MajorVersion],DX
        MOV [EDI+PFPE_EXPORT_DIRECTORY.MinorVersion],AX
        INCD [EDI+PFPE_EXPORT_DIRECTORY.Base]        ; Always start with ordinal 1.
        BufferStore [%DNTbuffer],[EBX+PGM.Pgmopt.OutFilePtr],[EBX+PGM.Pgmopt.OutFileSize] ; Compiled DLL name.
        BufferStoreByte [%DNTbuffer],0               ; Zero-terminate the DLL name.
        ; ESI points to ECX DWORD pointers to alphabetically sorted SYM objects.
    .30:LODSD
        PUSH ECX,ESI
         MOV ESI,EAX                                 ; ESI is now pointer to the exported symbol.
         MOV EAX,[%Ordinal]
         BufferStoreWord  [%ONTbuffer],EAX
         INC EAX
         MOV [%Ordinal],EAX
         MOV [EDI+PFPE_EXPORT_DIRECTORY.NumberOfFunctions],EAX
         MOV [EDI+PFPE_EXPORT_DIRECTORY.NumberOfNames],EAX
         MOV [ESI+SYM.OrdinalNr],EAX
         BufferStoreDword [%EATbuffer],ESI           ; Temporarily store pointer to exported SYM
          ; instead of pointer to the function or instead of pointer to forwarded "DllName.SymbolName".
          ; This will be fixed later in PfpeExportFixup after PgmLinkSegments.
         JNSt [ESI+SYM.Status],symForwarded,.36:
         PUSH ESI                                    ; Forwarded DLL.SymbolName will be stored in FWD.
           BufferRetrieve [%FWDbuffer]
         POP ESI
         MOV [ESI+SYM.NameIndex],ECX                 ; Temporary store forwarder name offset relative to the bottom of FWD
         ; instead of RVA.  This will be fixed later in PfpeExportFixup after PgmLinkSegments.
         Invoke SymStoreForwarderName::,ESI,[%FWDbuffer]
    .36: PUSH ESI                                    ; Symbol name will be stored in ENT.
           BufferRetrieve [%ENTbuffer]
         POP ESI
         BufferStoreDword [%NPTbuffer],ECX           ; Temporarily store name offset relative to the bottom of ENT
         ; instead of RVA.  This will be fixed later in PfpeExportFixup after PgmLinkSegments.
         BufferStore [%ENTbuffer],[ESI+SYM.NamePtr],[ESI+SYM.NameSize]
         BufferStoreByte [%ENTbuffer],0              ; Zero-terminate the name string.
    .40:POP ESI,ECX
        DEC ECX
        JNZ .30:
        ; Create export section [.edata].
        Invoke SssCreateSe::,[EBX+PGM.CurrentStm],0,=B'.edata',6, \
              sssSegment+sssNotBSS+sssImplicit+sssPrivate,sssPurposeEXPORT,8
        JC .80:
        MOV [%ReturnEAX],EAX
        ; Populate [.edata] section EAX.EmitBuffer with its divisions.
        MOV EDX,SIZE#PFPE_EXPORT_DIRECTORY
        BufferStore [EAX+SSS.EmitBuffer],EDI,EDX
        MOV EDI,EAX                                  ; EDI is now the section [.edata].
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [ESI+PFPE_EXPORT_DIRECTORY.AddressOfFunctions],EDX ; Temporary offset of EAT in section.
        BufferRetrieve [%EATbuffer]
        BufferStore [EDI+SSS.EmitBuffer],ESI,ECX
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [ESI+PFPE_EXPORT_DIRECTORY.AddressOfNames],ECX     ; Temporary offset of NPT in section.
        BufferRetrieve [%NPTbuffer]
        BufferStore [EDI+SSS.EmitBuffer],ESI,ECX
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [ESI+PFPE_EXPORT_DIRECTORY.AddressOfOrdinals],ECX  ; Temporary offset of ONT in section.
        BufferRetrieve [%ONTbuffer]
        BufferStore [EDI+SSS.EmitBuffer],ESI,ECX
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [ESI+PFPE_EXPORT_DIRECTORY.Name],ECX
        BufferRetrieve [%DNTbuffer]
        BufferStore [EDI+SSS.EmitBuffer],ESI,ECX
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [%ReturnECX],ECX
        BufferRetrieve [%ENTbuffer]
        BufferStore [EDI+SSS.EmitBuffer],ESI,ECX
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [%ReturnEDX],ECX
        BufferRetrieve [%FWDbuffer]
        BufferStore [EDI+SSS.EmitBuffer],ESI,ECX
        BufferRetrieve [EDI+SSS.EmitBuffer]
        MOV [EDI+SSS.TopLow],ECX
    .80:Invoke EaBufferRelease::,[%FWDbuffer]
        Invoke EaBufferRelease::,[%ENTbuffer]
        Invoke EaBufferRelease::,[%DNTbuffer]
        Invoke EaBufferRelease::,[%ONTbuffer]
        Invoke EaBufferRelease::,[%NPTbuffer]
        Invoke EaBufferRelease::,[%EATbuffer]
    .90:Invoke EaBufferRelease::,[%SymExpBuf]
      EndProcedure PfpeExportCreate

↑ PfpeExportFixup Program, edataPtr, ENToffset, FWDoffset
  PfpeExportFixup will update temporary offsets in export section `[.edata]` . It is invoked when PE image was linked by PgmLink and section bottoms fixed.
Input
  PgmPtr is pointer to the compiled and partially linked PGM.
  edataPtr is pointer to SSS object `[.edata]`.
  ENToffset is offset of ENT related to the start of `[.edata]` emit contents.
  FWDoffset is offset of FWD related to the start of `[.edata]` emit contents.
Output
  Export data section is updated.
Error
  CF=1 Errors are reported with macro Msg.
See also
  PfpeExportCreate.
Invoked by
  PfpeCompile

    PfpeExportFixup Procedure Program, edataPtr, ENToffset, FWDoffset
    edataRVA LocalVar ; RVA of section [.edata] (low dword).
        MOV EDI,[%edataPtr]
        MOV EBX,[%Program]
        TEST EDI
        JZ .90:                                      ; Do nothing when [.edata] was not created.
        MOV EAX,[EDI+SSS.BottomLow]                  ; VA of [.edata].
        MOV EDX,[EDI+SSS.BottomHigh]
        SUB EAX,[EBX+PGM.Pgmopt.ImageBaseLow]        ; Convert VA to RVA.
        SBB EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
        Msg cc=NZ,'8525',EDI                         ; Size of segment [!1S] exceeded 4 GB.
        MOV [%edataRVA],EAX                          ; EAX is now fixup delta which will update pointers in export dictionary ESI.
        ; Fixup RVAs in export directory.
        BufferRetrieve [EDI+SSS.EmitBuffer]                    ; Get contents of [.edata] to ESI,ECX.
        MOV EDX,[ESI+PFPE_EXPORT_DIRECTORY.AddressOfNames]     ; Offset of NPT within EmitBuffer.
        MOV EBX,[ESI+PFPE_EXPORT_DIRECTORY.AddressOfFunctions] ; Offset of EAT within EmitBuffer.
        ADD EDX,ESI                                            ; EDX now points to NPT with temporary offsets to ENT.
        ADD [ESI+PFPE_EXPORT_DIRECTORY.Name],EAX
        ADD [ESI+PFPE_EXPORT_DIRECTORY.AddressOfFunctions],EAX
        ADD [ESI+PFPE_EXPORT_DIRECTORY.AddressOfNames],EAX
        ADD [ESI+PFPE_EXPORT_DIRECTORY.AddressOfOrdinals],EAX
        ; Fixup RVAs of function names stored in NPT.
        ; Each pointer in NPT temporarily contains an offset of ASCIIZ string
        ;  related to the start of NPT. So the 1st dword contains 0. Required delta is RVA of ENT.
        MOV EAX,[ESI+PFPE_EXPORT_DIRECTORY.AddressOfFunctions]
        SUB EAX,SIZE#PFPE_EXPORT_DIRECTORY
        ADD EAX,[%ENToffset]                         ; Compute fixup delta value.
        MOV ECX,[ESI+PFPE_EXPORT_DIRECTORY.NumberOfNames]
        JECXZ .30:
    .20:ADD [EDX],EAX
        ADD EDX,4                                    ; The next name pointer.
        LOOP .20:

    .30:; Fixup function addresses in EAT.
        ; EAT was temporarily populated in PfpeExportCreate with pointers to symbols.
        ; Now they will be replaced with RVA of the symbol (exported function entry).
        MOV EDI,[%Program]
        MOV ECX,[ESI+PFPE_EXPORT_DIRECTORY.NumberOfFunctions]
        JECXZ .90:
        ; EBX is temporary offset of EAT within [.edata]. ESI is pointer to [.edata] contents.
        ADD EBX,ESI                                  ; Pointer to EAT in memory, i.e. table of pointers to exported symbols.
    .40:PUSH ECX
         MOV ESI,[EBX]                               ; ESI now points to the exported symbol.
         MOV ECX,[ESI+SYM.Section]
         JSt [ESI+SYM.Status],symForwarded,.50:
         MOV EAX,[ESI+SYM.OffsetLow]
         MOV EDX,[ESI+SYM.OffsetHigh]
         JECXZ .70:                                  ; If a scalar was exported.
         ADD EAX,[ECX+SSS.BottomLow]
         ADC EDX,[ECX+SSS.BottomHigh]                ; EDX:EAX is now VA of the symbol.
         SUB EAX,[EDI+PGM.Pgmopt.ImageBaseLow]
         SBB EDX,[EDI+PGM.Pgmopt.ImageBaseHigh]      ; VA is converted to RVA.
         Msg cc=NZ,'8525',ECX                        ; Size of segment [!1S] exceeded 4 GB.
         JMP .70:
    .50: MOV EAX,[ESI+SYM.NameIndex]                 ; Temporary offset within FWD table.
         ADD EAX,[%FWDoffset]                        ; EAX is now the offset of "DLL.FwdSymbol" in [.edata].
         ADD EAX,[%edataRVA]
    .70: MOV [EBX],EAX                               ; Update one pointer in EAT.
    .80: ADD EBX,4                                   ; Point to the next symbol in EAT.
        POP ECX
        LOOP .40:
    .90:EndProcedure PfpeExportFixup

↑ PfpeBaserelocCreate Program
  PfpeBaserelocCreate creates auxilliary PE/DLL segment `[.reloc]` with base relocations in the main Program. Size of its emitted contents is only estimated here into SSS.Top. The actual base relocation blocks will be written to section `[.reloc]` later by PfpeBaserelocFixup , after bottoms of all sections will have been fixed by PgmLink.
Input
  New segment is created and appended on Program.SssList.
Error
  CF=1 Errors are reported with macro Msg.
See also
  PfpeBaserelocFixup.
Invoked by
  PfpeCompile
Invokes
  SssCreateSe

    PfpeBaserelocCreate Procedure Program
    RelocCnt   LocalVar ; Total number of BASERELOC records in Program.
    SegmentCnt LocalVar ; Total number of relocable sections in Program.
    EmitSize   LocalVar ; Total emitted size of segments with relocations.
        ClearLocalVar
        XOR EAX,EAX
        MOV EBX,[%Program]
        ListGetFirst [EBX+PGM.SssList]
        JZ .90:
    .10:JNSt [EAX+SSS.Status],sssSegment,.50:
        BufferRetrieve [EAX+SSS.RelocBuffer]
        JECXZ .50:                                   ; Skip if this segment does not contribute to BASERELOC.
        INCD [%SegmentCnt]
        LEA EDX,[ESI+ECX]                            ; End of RELOC array.
        PUSH ESI
          BufferRetrieve [EAX+SSS.EmitBuffer]
        POP ESI
        ADD [%EmitSize],ECX
    .20:CMP ESI,EDX
        JNB .50:
        JNSt [ESI+RELOC.Status],relocAbsVA,.30:
        INCD [%RelocCnt]                             ; Absolute relocation will have a BASERELOC record.
    .30:ADD ESI,SIZE#RELOC
        JMP .20:
    .50:ListGetNext EAX                              ; The next segment.
        JNZ .10:
        MOV ECX,[%RelocCnt]
        SAL ECX,1                                    ; Each relocation takes 2 bytes.
        JZ .90:
        ; [.reloc] section will be created. Estimate its raw size.
        ; Each PFPE_BASERELOC header takes 8 bytes and it manages 4KB of emitted data.
        MOV EDI,4K
        MOV EAX,[%EmitSize]
        SUB EDX,EDX
        DIV EDI                                      ; EAX is now the maximal possible number of base relocation blocks.
        INC EAX                                      ; Round up.
        ADD EAX,[%SegmentCnt]                        ; Add one more block per each section change.
        LEA EDI,[8*EAX]                              ; Each block takes 8-byte header (SIZE#PFPE_BASERELOC).
        LEA EDI,[EDI+2*EAX]                          ; Add word alignment for each header.
        LEA EDI,[EDI+ECX+32]                         ; Add a small reserve to be safe.
        ; EDI is now estimated [.reloc] section size.
        Invoke SssCreateSe::,[EBX+PGM.CurrentStm],0,=B".reloc",6, \
                             sssSegment+sssWidth32+sssNotBSS+sssImplicit+sssPublic,sssPurposeBASERELOC,4
        MOV [EAX+SSS.TopLow],EDI
    .90:EndProcedure PfpeBaserelocCreate

↑ PfpeBaserelocFixup Program, SectionHeaderBuffer
  PfpeBaserelocFixup fills the emitted contents of auxilliary PE/DLL segment `[reloc]` with base relocations in the main Program.
  It is invoked when all relocation have been fixed and resolved in PgmLink , and all segments ordered in `Program.SegOrdBuffer`.
Input
  Program Pointer to the compiled and partially linked PGM.
  SectionHeaderBuffer is pointer to BUFFER with array of PFCOFF_SECTION_HEADER records.
Output
  EmitBuffer of segment with `PURPOSE=BASERELOC` (if found) is filled with PFPE_BASERELOC records.
Error
  CF=1 Errors are reported with macro Msg.
Invoked by
  PfpeCompile
Invokes
  EaBufferAlign EaBufferRelease EaBufferReserve

    PfpeBaserelocFixup Procedure Program, SectionHeaderBuffer
    SssReloc      LocalVar ; Pointer to SSS [.reloc].
    TypeOffsetBuf LocalVar ; Pointer to BUFFER with WORDs of one PFPE_BASERELOC block.
    SectionRVA    LocalVar ; RVA of the section bottom.
    PageOffset    LocalVar ; Offset of currently processed block relative to section bottom.
        Invoke EaBufferReserve::,PfpeBaserelocFixup
        MOV [%TypeOffsetBuf],EAX
        MOV EBX,[%Program]
        CALL .FlushBlock:                            ; Initialize TypeOffsetBuf and BlockRVA.

        ; First segment pass .10: .. .20: searches for [.reloc] section created by PfpeBaserelocCreate.
        BufferRetrieve [EBX+PGM.SegOrdBuffer]
        SAR ECX,2
        JZ .90:                                      ; If no segments are linked.
    .10:LODSD
        JSt [EAX+SSS.Purpose],sssPurposeBASERELOC,.20:
        LOOP .10:
        JMP .90:                                    ; No BASERELOC section exists in PE program (e.g. pure resource DLL).

    .20:MOV [%SssReloc],EAX                         ; [.reloc] section was found.
        ; Second segment pass .30: .. .80: handles base relocation from all segments.
        BufferRetrieve [EBX+PGM.SegOrdBuffer]
        SAR ECX,2
    .30:LODSD                                       ; Get the next segment.
        JNSt [EAX+SSS.Status],sssSegment,.80:
        PUSHAD
          MOV ECX,[EAX+SSS.BottomLow]               ; Linked VA of the segment (section).
          MOV EDX,[EAX+SSS.BottomHigh]
          SUB ECX,[EBX+PGM.Pgmopt.ImageBaseLow]
          SBB EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
          Msg cc=NZ,'7922',EAX,ECX                  ; Fixup increment out of 4GB range at [!1S]:!2Hh.
          MOV [%SectionRVA],ECX
          BufferRetrieve [EAX+SSS.RelocBuffer]
          LEA EDX,[ESI+ECX]                         ; End of RELOC array.
    .40:  CMP ESI,EDX
          JNB .70:
          JNSt [ESI+RELOC.Status],relocAbsVA,.60:
          ; ESI is (resolved) absolute relocation.
          MOV ECX,~(4K-1)                           ; Mask of PFPE_BASERELOC.PageOffset (0xFFFF_F000).
          AND ECX,[ESI+RELOC.OrgLow]
          CMP ECX,[%PageOffset]                     ; Check if the RELOC ESI is in the same block.
          JE .50:
          CALL .FlushBlock:                         ; Flush the previous block and start a new one.
          MOV [%PageOffset],ECX
    .50:  MOV ECX,4K-1                              ; Mask of PFPE_BASERELOC.TypeOffset (0x0000_0FFF).
          AND ECX,[ESI+RELOC.OrgLow]
          MOV EAX,pfpeREL_BASED_HIGHLOW
          JSt [ESI+RELOC.Status],relocWidth32,.55:
          MOV EAX,pfpeREL_BASED_DIR64
          JSt [ESI+RELOC.Status],relocWidth64,.55:
          MOV EAX,pfpeREL_BASED_LOW
          JSt [ESI+RELOC.Status],relocWidth16,.55:
          Msg '7737',[ESI+RELOC.Section],[ESI+RELOC.OrgLow] ; Invalid base relocation at [!1S]:!2H.
          JMP .60:
    .55:  OR ECX,EAX                                ; Merge PFPE_BASERELOC.TypeOffset.
          BufferStoreWord [%TypeOffsetBuf],ECX
    .60:  ADD ESI,SIZE# RELOC
          JMP .40:                                  ; The next RELOC record.

    PfpeBaserelocFixup.FlushBlock: PROC                               ; Write one PFPE_BASERELOC block to section [.reloc].
        PUSHAD
         Invoke EaBufferAlign::,[%TypeOffsetBuf],4   ; Pad the block with an empty word if they weren't even.
         BufferRetrieve [%TypeOffsetBuf]
         JECXZ .F9:                                  ; If no base relocation appeared in this segment.
         MOV EDI,[%SssReloc]
         MOV EAX,[%PageOffset]
         ADD EAX,[%SectionRVA]
         BufferStoreDword [EDI+SSS.EmitBuffer],EAX
         LEA EAX,[ECX+SIZE# PFPE_BASERELOC]
         BufferStoreDword [EDI+SSS.EmitBuffer],EAX   ; BlockSize.
         BufferStore [EDI+SSS.EmitBuffer],ESI,ECX    ; The block is complete now.
         BufferClear [%TypeOffsetBuf]
    .F9: XOR ECX,ECX
         DEC ECX
         MOV [%PageOffset],ECX                       ; Initialize PageOffset with nonexisting address.
        POPAD
        RET
        ENDP PfpeBaserelocFixup.FlushBlock:

    .70:  CALL .FlushBlock:
        POPAD
    .80:DEC ECX
        JNZ .30:                                   ; The next segment.
        MOV EDI,[%SssReloc]                         ; ^SSS [.reloc].
        ; Base relocation blocks are now stored in [EDI+SSS.RelocBuffer].
        MOV EAX,[EDI+SSS.SegmIndex]
        MOV ESI,SIZE# PFCOFF_SECTION_HEADER
        DEC EAX                                     ; Segment index is 1-based.
        MsgUnexpected cc=S
        MUL ESI
        BufferRetrieve [%SectionHeaderBuffer]
        ADD ESI,EAX                                 ; ESI is now pointer to section header [.reloc].
        PUSH ESI
          BufferRetrieve [EDI+SSS.EmitBuffer]       ; The final [.reloc] contents.
        POP ESI                                     ; Update section header with the final size ECX.
        MOV [ESI+PFCOFF_SECTION_HEADER.SizeOfRawData],ECX
        ADD ECX,[EDI+SSS.BottomLow]                 ; Update SSS virtual size.
        MOV [EDI+SSS.TopLow],ECX
    .90:Invoke EaBufferRelease::,[%TypeOffsetBuf]
        EndProcedure PfpeBaserelocFixup

↑ PfpeLoadStubFile StubBuffer, Pgm
  PfpeLoadStubFile is invoked when a PE or DLL executable program is linked. When program option STUBFILE= defines a file without path, it will search for that file in LINKPATH= directories, check MZ format, copy the file contents to StubBuffer and close it.
  If the file is not found, or if STUBFILE= is empty, PfpeLoadStubFile will use built-in default instead.
Input
  StubBuffer is pointer to the output empty BUFFER, reserved by the caller.
  Pgmis pointer to the linked PGM.
Output
  StubBuffer if filled with DOS stub.
Error
  Errors E6953, E7741, E7742, E7763 are reported with macro Msg , default stub is used in this case.
Depends on
  PfQueryChar
Invokes
  EaoptGetOnePath
Invoked by
  PfpeCompile

    PfpeLoadStubFile Procedure StubBuffer, Pgm
    PathNr    LocalVar                               ; Ordinal number of LINKPATH.
    StubFile  LocalVar Size=SIZE# FILE               ; FILE object of the external stub file.
        ClearLocalVar
        MOV ESI,PfcoffStub::                         ; First assume that the default stub built inside euroasm.exe will be used.
        MOV EAX,PfcoffStubEnd::
        SUB EAX,ESI
        BufferStore [%StubBuffer],ESI,EAX
        MOV EBX,[%Pgm]                               ; Check if stub file is explicitly specified.
        MOV EDX,[EBX+PGM.Pgmopt.StubFileSize]
        MOV ESI,[EBX+PGM.Pgmopt.StubFilePtr]
        TEST EDX
        JZ .90:                                      ; If not, we're done.
        PfQueryChar '\'                              ; Query if Filemask ESI,EDX was specified with path (it contains slash or colon).
        JE .50:
        PfQueryChar '/'
        JE .50:
        PfQueryChar ':'
        JE .50:
        SUB EAX,EAX                                  ; When there is no path in STUBFILE=, try all pathes from LINKPATH=.
        MOV [%PathNr],EAX
    .20:Invoke EaoptGetOnePath::,[Ea.Eaopt.LinkPathPtr::],[Ea.Eaopt.LinkPathSize::],[%PathNr]
        JC .E7742:                                   ; StubFile=!1$ was not found in LinkPath="!2S".
        INCD [%PathNr]                               ; Prepare for the next path.
        MOV EDX,[EBX+PGM.Pgmopt.StubFileSize]        ; One path is in ESI,ECX.
        LEA EAX,[EDX+ECX+1]
        CMP EAX,260                                  ; MAX_PATH_SIZE
        JA .E6953:                                   ; Size of LinkPath "!1_" + size of filename exceeded 260 characters.
        LEA EDI,[%StubFile+FILE.Name]                ; Assign path+stubfile name to %StubFile.
        REP MOVSB
        MOV AX,'\/'
        CMPB [Ea.EuroasmOS::],'W'                    ; Choose slash or backslash.
        JE .30:
        XCHG AL,AH
    .30:CMP AL,[EDI-1]
        JE .40:
        CMP AH,[EDI-1]
        JE .40:
        STOSB                                        ; If the path was not terminated with (back)slash, append it.
    .40:MOV ESI,[EBX+PGM.Pgmopt.StubFilePtr]
        MOV ECX,EDX
        REP MOVSB
        SUB EAX,EAX
        STOSB  ; Zero terminate the filename.
        LEA EDI,[%StubFile]                          ; %StubFile is now assigned with path and filemask.
        LEA EDX,[EDI+FILE.Name]
        SysOpenFileMap EDI,EDX
        JC .20:                                      ; If not found, try the next IncludePath.
        JMP .60:
    .50:LEA EDI,[%StubFile]
        SysOpenFileMap EDI,ESI,FileNameSize=EDX      ; Path was present in filename ESI, use as is.
        JC .E7741:                                   ; StubFile=!1$ was no found.
    .60:MOV ECX,EAX                                  ; Contents of the file is now mapped at ESI,EAX.
        CMP ECX,SIZE#PFMZ_DOS_HEADER
        JNA .E7743:                                  ; Invalid format (file is too short).
        CMPW [ESI],'MZ'
        JNE .E7743:                                  ; Invalid format.
        BufferClear [%StubBuffer]
        BufferStore [%StubBuffer],ESI,ECX
        SysCloseFile EDI
        JMP .90:
    .E6953:Msg '6953',ESI                            ; Size of LinkPath "!1_" + size of filename exceeded 256 characters.
           JMP .Error:
    .E7741:MOV ESI,[EBX+PGM.Pgmopt.StubFilePtr]
           Msg '7741',ESI                            ; StubFile=!1$ was no found.
           JMP .Error:
    .E7742:MOV ESI,[EBX+PGM.Pgmopt.StubFilePtr]
           LEA EAX,[Ea::+EA.Eaopt.LinkPathPtr]
           Msg '7742',ESI,EAX                        ; StubFile=!1$ was no found in LinkPath="!2S".
           JMP .Error:
    .E7743:MOV ESI,[EBX+PGM.Pgmopt.StubFilePtr]
           Msg '7743',ESI                            ; Invalid format of StubFile="!1$".
           SysCloseFile EDI
    .Error:STC
    .90:EndProcedure PfpeLoadStubFile

↑ PfpeCompile OutputStream, Pgm
  PfpeCompile is constructor of output PE and DLL 32bit or 64bit executable file in Microsoft Portable Executable Common Object File Format as specified in [MS_PECOFF].
Input
  OutputStream is pointer to a STREAM for the output file contents.
  Pgm is pointer to PGM representing 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 ExpAlign PfcoffFileHeader PfcoffSegmCreate PfcoffSegmRawData PfcoffSymFile PfcoffSymSegment PfcoffSymSymbol PfpeBaserelocCreate PfpeBaserelocFixup PfpeExportCreate PfpeExportFixup PfpeImportCreate PfpeImportFixup PfpeLoadStubFile PfpeOptionalHeader PfrsrcLoadIconFile PgmGroupByModel PgmLink PgmOrderSegments PgmRelocResolve PgmSymResolve SymReportUnresolved
Invoked by
  PfdllCompile
Tested by
  t9385 t9436

    PfpeCompile Procedure OutputStream, Pgm
    StubFileBuf        LocalVar ; Pointer to BUFFER which keeps DOS stub file contents.
    SectionHeaderBuf   LocalVar ; Pointer to BUFFER which keeps PFCOFF_SECTION_HEADER objects, one for each segment.
    RawBuf             LocalVar ; Pointer to BUFFER for emitted contents and relocations of all segments.
    SymbolTableBuf     LocalVar ; Pointer to BUFFER for PFCOFF_SYMBOL records.
    StringTableBuf     LocalVar ; Pointer to BUFFER for longname strings.
    SectionHeaderPtr   LocalVar ; Pointer to the current PFCOFF_SECTION_HEADER object on SectionHeaderBuf.
    FileAddr           LocalVar ; File offset in PE file, updated on-the-fly.
    ExportSection      LocalVar ; Pointer to SSS with [.edata] section.
    ENToffset          LocalVar ; Offset of ENT within export section contents.
    FWDoffset          LocalVar ; Offset of FWD within export section contents.
    MaxTopHigh         LocalVar ; Maximal SSS.Top of all sections.
    MaxTopLow          LocalVar
    InputFile          LocalVar Size=SIZE# FILE ; File object for reading stub and icon file.
    CoffFileHeader     LocalVar Size=SIZE#PFCOFF_FILE_HEADER ; Room for PFCOFF_FILE_HEADER object.
    PeOptionalHeader   LocalVar Size=SIZE#PFPE_OPTIONAL_HEADER64 ; Room for PFPE_OPTIONAL_HEADER32 or PFPE_OPTIONAL_HEADER64.
    IdataMap           LocalVar Size=SIZE# PFPE_IDATA_MAP ; Room for PFPE_IDATA_MAP.
        MOV EBX,[%Pgm]
        SUB EAX,EAX
        MOV [%MaxTopLow],EAX
        MOV [%MaxTopHigh],EAX
        Invoke EaBufferReserve::,%^PROC              ; Reserve temporary buffers.
        MOV [%SectionHeaderBuf],EAX
        Invoke EaBufferReserve::,%^PROC
        MOV [%RawBuf],EAX
        Invoke EaBufferReserve::,%^PROC
        MOV [%SymbolTableBuf],EAX
        Invoke EaBufferReserve::,%^PROC
        MOV [%StringTableBuf],EAX
        BufferStoreDword EAX,4                       ; Initialize DD StringTableSize in the buffer.
        Invoke EaBufferReserve::,%^PROC
        MOV [%StubFileBuf],EAX
        ; Load DOS MZ stub into its buffer.
        Invoke PfpeLoadStubFile, EAX, EBX
        Invoke EaBufferAlign::,[%StubFileBuf],8      ; The following PE signature should be QWORD aligned.
        MOV EBX,[%Pgm]                               ; Preformat special PECOFF sections.
        LEA EDX,[%IdataMap]
        Invoke PfpeImportCreate,EBX,EDX
        Invoke PfpeExportCreate,EBX
        MOV [%ExportSection],EAX
        MOV [%ENToffset],ECX
        MOV [%FWDoffset],EDX
        Invoke PfpeBaserelocCreate,EBX
        Invoke PfrsrcLoadIconFile::,EBX
        Invoke PgmGroupByModel::,EBX
    Invoke PgmOrderSegments::,EBX
        Invoke PgmSymResolve::,EBX
        Invoke SymReportUnresolved::,EBX
    .09:BufferRetrieve [%StubFileBuf]                ; Calculate the size of stub+headers into EDX.
        MOV EDX,ECX                                  ; MZ DOS header + stub program size.
        Invoke ExpAlign::,EDX,8,0                    ; The following PE signature should be QWORD aligned.
        ADD EDX,ECX
        ADD EDX,4+SIZE# PFCOFF_FILE_HEADER+SIZE# PFPE_OPTIONAL_HEADER32 ; PE signature + file header + optional header.
        JNSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.11:
        ADD EDX,SIZE# PFPE_OPTIONAL_HEADER64 - SIZE# PFPE_OPTIONAL_HEADER32
    .11:BufferRetrieve [EBX+PGM.SegOrdBuffer]
        SHR ECX,2
        JZ .19:
    .12:LODSD
        JNSt [EAX+SSS.Status],sssSegment,.13:
        ADD EDX,SIZE# PFCOFF_SECTION_HEADER
    .13:LOOP .12:
    .19:Invoke PgmLink::,EBX,EDX,EDX
        BufferRetrieve [%StubFileBuf]                ; Construction of output file of program EBX.
        MOV [ESI+PFMZ_DOS_HEADER.e_lfanew],ECX       ; ECX is now aligned DOS stub size. Update the pointer to PE signature.
        MOV [%FileAddr],ECX                          ; Dword PE signature may be temporarily ignored.
        LEA EDI,[%CoffFileHeader]                    ; Initialize COFF file header.
        Invoke PfcoffFileHeader::,EDI,EBX
        MOVZXW ECX,[EDI+PFCOFF_FILE_HEADER.SizeOfOptionalHeader]
        LEA EDI,[%PeOptionalHeader]                  ; Initialize PE optional header.
        Invoke PfpeOptionalHeader,EDI,EBX
        ADD ECX,4+SIZE# PFCOFF_FILE_HEADER           ; Skip PE signature and file header.
        ADDD [%FileAddr],ECX                         ; Now it is FA of the 1st section header.
        LEA EAX,[%IdataMap]
        Invoke PfpeImportFixup,EBX,EDI,EAX
        Invoke PfpeExportFixup,EBX,[%ExportSection],[%ENToffset],[%FWDoffset]
        Invoke PgmRelocResolve::,EBX
        ; Create symbol record ".file".
        LEA EAX,[Ea.SrcFile::]
        Invoke PfcoffSymFile::,EAX,[%SymbolTableBuf]
        ; First segments pass .30: .. .33: updates PFCOFF_FILE_HEADER.NrOfSections,
        ;   stores empty IMAGE_SECTION_HEADER object to [%SectionHeaderBuf] and
        ;   creates segment's symbol record + one auxilliary record to [%SymbolTableBuf]
        BufferRetrieve [EBX+PGM.SegOrdBuffer]        ; Array of pointers to segments, sorted order.
        SHR ECX,2 ; Number of pointers.
        JZ .37:
        LEA EDX,[%CoffFileHeader]
    .30:LODSD
        JNSt [EAX+SSS.Status],sssSegment,.33:        ; Skip if EAX is not a segment ("section" in MS terminology}.
        Invoke PfcoffSegmCreate::, EAX, [%Pgm],[%SectionHeaderBuf],EDX    ; Create one section header.
        MOV EAX,[EAX+SSS.SymPtr]
        Invoke PfcoffSymSegment::,EAX,[%SymbolTableBuf],[%StringTableBuf] ; Create symbol assigned to the section EAX.
    .33:LOOP .30:
    .37:BufferRetrieve [%SectionHeaderBuf]
        MOV [%SectionHeaderPtr],ESI
        ADD [%FileAddr],ECX                          ; Now it is FA of raw data, i.e. .SizeOfHeaders in optional header.
        MOV EAX,[%FileAddr]
        LEA EDI,[%PeOptionalHeader]
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SizeOfHeaders],EAX
        Invoke PfpeBaserelocFixup,EBX,[%SectionHeaderBuf]
        ListGetFirst [EBX+PGM.SymList]               ; Symbol list pass at .40: creates PFCOFF_SYMBOL_TABLE records.
        JZ .43:
    .40:Invoke PfcoffSymSymbol::,EAX,[%SymbolTableBuf],[%StringTableBuf] ; Create symbol EAX.
        ListGetNext EAX
        JNZ .40:
    .43:BufferRetrieve [EBX+PGM.SegOrdBuffer]        ; Second segments pass .43: .. .50: copies data from segments to COFF buffers.
        SHR ECX,2
        JZ .55:
    .47:LODSD
        MOV EDX,EAX ; ^SSS.
        JNSt [EDX+SSS.Status],sssSegment,.50:        ; Skip when EDX is not a segment.
        Invoke PfcoffSegmRawData::,EDX,EBX,[%FileAddr],[%SectionHeaderPtr],[%RawBuf],[%StringTableBuf]
        MOV [%FileAddr],EAX
        ADDD [%SectionHeaderPtr],SIZE#PFCOFF_SECTION_HEADER
    .50:LOOP .47:                                    ; The next segment.
    .55:; Update file header.
        JNSt [Ea.Eaopt.Status::],eaoptDEBUG,.60:     ; Skip symbol table if not debug version.
        MOV EAX,[%FileAddr]                          ; Raw emitted data and relocations has been just buffered.
        LEA EDI,[%CoffFileHeader]
        MOV [EDI+PFCOFF_FILE_HEADER.PointerToSymbolTable],EAX
        BufferRetrieve [%SymbolTableBuf]             ; Count the number of symbols.
        MOV EAX,ECX
        SUB EDX,EDX
        MOV ECX,SIZE#PFCOFF_SYMBOL
        DIV ECX
        MOV [EDI+PFCOFF_FILE_HEADER.NumberOfSymbols],EAX
    .60:LEA EDI,[%PeOptionalHeader]                  ; Third segment pass .65: .. .77: to update optional header.
        BufferRetrieve [EBX+PGM.SegOrdBuffer]
        SHR ECX,2
        JZ .80:
    .65:LODSD
        PUSH ECX,ESI,EDI
         MOV ESI,EAX ; ^SSS.
         JNSt [ESI+SSS.Status],sssSegment,.77:       ; Skip when ESI is not a segment.
         MOV EAX,[ESI+SSS.TopLow]
         MOV EDX,[ESI+SSS.TopHigh]
         CMP EDX,[%MaxTopHigh]
         JB .73:
         JA .70:
         CMP EAX,[%MaxTopLow]
         JBE .73:
    .70: MOV [%MaxTopLow],EAX
         MOV [%MaxTopHigh],EDX
    .73: SUB EAX,[ESI+SSS.BottomLow]
         SBB EDX,[ESI+SSS.BottomHigh]                ; EDX:EAX is now unaligned section size.
         Invoke ExpAlign::,EAX,[EBX+PGM.Pgmopt.SectionAlign],0
         ADD ECX,EAX
         ADC EDX,0
         TEST EDX                                    ; EDX:ECX is now aligned section size.
         Msg cc=NZ,'8525',ESI                        ; Size of segment [!1S] exceeded 4 GB.
         MOV EDX,[ESI+SSS.BottomLow]                 ; EDX is now the section VA.
         SUB EDX,[EBX+PGM.Pgmopt.ImageBaseLow]       ; Convert VA to RVA (Borland linkers don't do this).
         MOV EAX,[ESI+SSS.Purpose]
         RstSt EAX,sssPurposeLITERAL+sssPurposeDRECTVE ; Get rid of pseudopurposes.
         Dispatch EAX,sssPurposeCODE,sssPurposeDATA,sssPurposeBSS
         TEST EAX,sssPurposeOptionalMask
         JZ .77:                                     ; Ignore other purposes.
         JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.74:
         LEA EDI,[EDI+PFPE_OPTIONAL_HEADER32.DataDirectory] ; RvaAndSizes of DataDirectories in optional header will be specified here.
         JMP .75:
    .74: LEA EDI,[EDI+PFPE_OPTIONAL_HEADER64.DataDirectory]
    .75: MOV ECX,[ESI+SSS.TopLow]
         SUB ECX,[ESI+SSS.BottomLow]
         ; EDI is now pointer to 0-th member of PFPE_DATA_DIRECTORY in optional header (32 or 64bit).
         ; EAX is special PE purpose. EDX is RVA of the segment ESI.  ECX is unaligned section data size.
         JNSt EAX,sssPurposeEXPORT,.NotEXPORT:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_EXPORT+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_EXPORT+PFPE_DATA_DIRECTORY.Size],ECX
    .NotEXPORT: ; Skip directory entry IMPORT and IAT, which were set in PfpeImportFixup.
         JNSt EAX,sssPurposeRESOURCE,.NotRESOURCE:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_RESOURCE+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_RESOURCE+PFPE_DATA_DIRECTORY.Size],ECX
    .NotRESOURCE:
         JNSt EAX,sssPurposeEXCEPTION,.NotEXCEPTION:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_EXCEPTION+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_EXCEPTION+PFPE_DATA_DIRECTORY.Size],ECX
    .NotEXCEPTION:
         JNSt EAX,sssPurposeSECURITY,.NotSECURITY:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_SECURITY+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_SECURITY+PFPE_DATA_DIRECTORY.Size],ECX
    .NotSECURITY:
         JNSt EAX,sssPurposeBASERELOC,.NotBASERELOC:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_BASERELOC+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_BASERELOC+PFPE_DATA_DIRECTORY.Size],ECX
    .NotBASERELOC:
         JNSt EAX,sssPurposeDEBUG,.NotDEBUG:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_DEBUG+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_DEBUG+PFPE_DATA_DIRECTORY.Size],ECX
    .NotDEBUG:
         JNSt EAX,sssPurposeCOPYRIGHT,.NotCOPYRIGHT:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_COPYRIGHT+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_COPYRIGHT+PFPE_DATA_DIRECTORY.Size],ECX
    .NotCOPYRIGHT:
         JNSt EAX,sssPurposeGLOBALPTR,.NotGLOBALPTR:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_GLOBALPTR+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_GLOBALPTR+PFPE_DATA_DIRECTORY.Size],ECX
    .NotGLOBALPTR:
         JNSt EAX,sssPurposeTLS,.NotTLS:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_TLS+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_TLS+PFPE_DATA_DIRECTORY.Size],ECX
    .NotTLS:
         JNSt EAX,sssPurposeLOAD_CONFIG,.NotLOAD_CONFIG:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_LOAD_CONFIG+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_LOAD_CONFIG+PFPE_DATA_DIRECTORY.Size],ECX
    .NotLOAD_CONFIG:
         JNSt EAX,sssPurposeBOUND_IMPORT,.NotBOUND_IMPORT:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_BOUND_IMPORT+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_BOUND_IMPORT+PFPE_DATA_DIRECTORY.Size],ECX
    .NotBOUND_IMPORT:
         JNSt EAX,sssPurposeDELAY_IMPORT,.NotDELAY_IMPORT:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_DELAY_IMPORT+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_DELAY_IMPORT+PFPE_DATA_DIRECTORY.Size],ECX
    .NotDELAY_IMPORT:
         JNSt EAX,sssPurposeCLR,.NotCLR:
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_CLR+PFPE_DATA_DIRECTORY.VirtualAddress],EDX
         MOV [EDI+SIZE#PFPE_DATA_DIRECTORY*pfpeDIRECTORY_ENTRY_CLR+PFPE_DATA_DIRECTORY.Size],ECX
    .NotCLR:
         JMP .77:
         ; EDI is pointer to PFPE_OPTIONAL_HEADER32 when updating ordinary CODE,DATA or BSS section.
         ; EAX is ordinary PE purpose (CODE,DATA or BSS). EDX is RVA of the segment ESI. ECX is section-aligned section size.
    .sssPurposeCODE:
         ADD [EDI+PFPE_OPTIONAL_HEADER32.SizeOfCode],ECX
         CMPD [EDI+PFPE_OPTIONAL_HEADER32.BaseOfCode],0
         JNZ .77:                                    ; If the BaseOfCode was already specified by another section.
         MOV [EDI+PFPE_OPTIONAL_HEADER32.BaseOfCode],EDX
         JMP .77:
    .sssPurposeDATA:
         ADD [EDI+PFPE_OPTIONAL_HEADER32.SizeOfInitializedData],ECX
         JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.77: ; 64bit version doesn't have BaseOfData.
         CMPD [EDI+PFPE_OPTIONAL_HEADER32.BaseOfData],0
         JNZ .77:                                    ; If the BaseOfData was already specified by another section.
         MOV [EDI+PFPE_OPTIONAL_HEADER32.BaseOfData],EDX
         JMP .77:
    .sssPurposeBSS:
         ADD [EDI+PFPE_OPTIONAL_HEADER32.SizeOfUninitializedData],ECX
    .77:POP EDI,ESI,ECX
        DEC ECX
        JNZ .65:                                     ; The next segment.
    .80:; Update image size.
        MOV EAX,[%MaxTopLow]
        MOV EDX,[%MaxTopHigh]
        SUB EAX,[EBX+PGM.Pgmopt.ImageBaseLow]
        SBB EDX,[EBX+PGM.Pgmopt.ImageBaseHigh]
        JNZ .85:
        Invoke ExpAlign::,EAX,[EBX+PGM.Pgmopt.SectionAlign],0
        ADD EAX,ECX
        MOV [EDI+PFPE_OPTIONAL_HEADER32.SizeOfImage],EAX
    .85:BufferRetrieve [%StubFileBuf]                ; Flush all COFF components to the output stream.
        StreamStore [%OutputStream],ESI,ECX          ; DOS stub, size QWORD aligned.
        StreamStoreDword [%OutputStream],'PE'        ; Signature.
        LEA EDI,[%CoffFileHeader]
        StreamStore [%OutputStream],EDI,SIZE#PFCOFF_FILE_HEADER ; COFF file header.
        LEA EDX,[%PeOptionalHeader]
        MOV ECX,SIZE#PFPE_OPTIONAL_HEADER64
        JSt [EBX+PGM.Pgmopt.Status],pgmoptWidth64,.87:
        MOV ECX,SIZE#PFPE_OPTIONAL_HEADER32
    .87:StreamStore [%OutputStream],EDX,ECX          ; PE Optional header.
        BufferRetrieve [%SectionHeaderBuf]
        StreamStore [%OutputStream],ESI,ECX          ; Section headers.
        BufferRetrieve [%RawBuf]
        StreamStore [%OutputStream],ESI,ECX          ; Section data + relocations of all segments.
        JNSt [Ea.Eaopt.Status::],eaoptDEBUG,.90:     ; Skip symbol table if not debug version.
        BufferRetrieve [%SymbolTableBuf]
        StreamStore [%OutputStream],ESI,ECX          ; Symbol table.
        BufferRetrieve [%StringTableBuf]
        MOV [ESI],ECX                                ; Update StringTable size.
        StreamStore [%OutputStream],ESI,ECX          ; String table.
    .90:Invoke EaBufferRelease::,[%RawBuf]
        Invoke EaBufferRelease::,[%SymbolTableBuf]
        Invoke EaBufferRelease::,[%StringTableBuf]
        Invoke EaBufferRelease::,[%SectionHeaderBuf]
        Invoke EaBufferRelease::,[%StubFileBuf]
      EndProcedure PfpeCompile

      ENDPROGRAM pfpe

▲Back to the top▲