Subversion Repositories Kolibri OS

Rev

Rev 7597 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018-2019, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE PE32;
  9.  
  10. IMPORT BIN, LISTS, UTILS, WR := WRITER, mConst := CONSTANTS, CHL := CHUNKLISTS;
  11.  
  12.  
  13. CONST
  14.  
  15.     SIZE_OF_DWORD = 4;
  16.     SIZE_OF_WORD  = 2;
  17.  
  18.     SIZE_OF_IMAGE_EXPORT_DIRECTORY = 40;
  19.  
  20.     IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16;
  21.  
  22.     IMAGE_SIZEOF_SHORT_NAME = 8;
  23.  
  24.     SIZE_OF_IMAGE_FILE_HEADER* = 20;
  25.  
  26.     SIZE_OF_IMAGE_SECTION_HEADER* = 40;
  27.  
  28.     (* SectionHeader.Characteristics *)
  29.  
  30.     SHC_text  = 060000020H;
  31.     SHC_data  = 040000040H;
  32.     SHC_bss   = 0C0000080H;
  33.  
  34.     SectionAlignment = 1000H;
  35.     FileAlignment    =  200H;
  36.  
  37.  
  38. TYPE
  39.  
  40.     WORD  = WCHAR;
  41.     DWORD = INTEGER;
  42.  
  43.     NAME* = ARRAY IMAGE_SIZEOF_SHORT_NAME OF CHAR;
  44.  
  45.  
  46.     IMAGE_DATA_DIRECTORY = RECORD
  47.  
  48.         VirtualAddress:  DWORD;
  49.         Size:            DWORD
  50.  
  51.     END;
  52.  
  53.  
  54.     IMAGE_OPTIONAL_HEADER = RECORD
  55.  
  56.         Magic:                        WORD;
  57.         MajorLinkerVersion:           BYTE;
  58.         MinorLinkerVersion:           BYTE;
  59.         SizeOfCode:                   DWORD;
  60.         SizeOfInitializedData:        DWORD;
  61.         SizeOfUninitializedData:      DWORD;
  62.         AddressOfEntryPoint:          DWORD;
  63.         BaseOfCode:                   DWORD;
  64.         BaseOfData:                   DWORD;
  65.         ImageBase:                    DWORD;
  66.         SectionAlignment:             DWORD;
  67.         FileAlignment:                DWORD;
  68.         MajorOperatingSystemVersion:  WORD;
  69.         MinorOperatingSystemVersion:  WORD;
  70.         MajorImageVersion:            WORD;
  71.         MinorImageVersion:            WORD;
  72.         MajorSubsystemVersion:        WORD;
  73.         MinorSubsystemVersion:        WORD;
  74.         Win32VersionValue:            DWORD;
  75.         SizeOfImage:                  DWORD;
  76.         SizeOfHeaders:                DWORD;
  77.         CheckSum:                     DWORD;
  78.         Subsystem:                    WORD;
  79.         DllCharacteristics:           WORD;
  80.         SizeOfStackReserve:           DWORD;
  81.         SizeOfStackCommit:            DWORD;
  82.         SizeOfHeapReserve:            DWORD;
  83.         SizeOfHeapCommit:             DWORD;
  84.         LoaderFlags:                  DWORD;
  85.         NumberOfRvaAndSizes:          DWORD;
  86.  
  87.         DataDirectory: ARRAY IMAGE_NUMBEROF_DIRECTORY_ENTRIES OF IMAGE_DATA_DIRECTORY
  88.  
  89.     END;
  90.  
  91.  
  92.     IMAGE_FILE_HEADER* = RECORD
  93.  
  94.         Machine*:               WORD;
  95.         NumberOfSections*:      WORD;
  96.         TimeDateStamp*:         DWORD;
  97.         PointerToSymbolTable*:  DWORD;
  98.         NumberOfSymbols*:       DWORD;
  99.         SizeOfOptionalHeader*:  WORD;
  100.         Characteristics*:       WORD
  101.  
  102.     END;
  103.  
  104.  
  105.     IMAGE_NT_HEADERS = RECORD
  106.  
  107.         Signature:       ARRAY 4 OF BYTE;
  108.         FileHeader:      IMAGE_FILE_HEADER;
  109.         OptionalHeader:  IMAGE_OPTIONAL_HEADER
  110.  
  111.     END;
  112.  
  113.  
  114.     IMAGE_SECTION_HEADER* = RECORD
  115.  
  116.         Name*: NAME;
  117.  
  118.         VirtualSize*,
  119.         VirtualAddress*,
  120.         SizeOfRawData*,
  121.         PointerToRawData*,
  122.         PointerToRelocations*,
  123.         PointerToLinenumbers*:   DWORD;
  124.  
  125.         NumberOfRelocations*,
  126.         NumberOfLinenumbers*:    WORD;
  127.  
  128.         Characteristics*:        DWORD
  129.  
  130.     END;
  131.  
  132.  
  133.     IMAGE_EXPORT_DIRECTORY = RECORD
  134.  
  135.         Characteristics:       DWORD;
  136.         TimeDateStamp:         DWORD;
  137.         MajorVersion:          WORD;
  138.         MinorVersion:          WORD;
  139.         Name,
  140.         Base,
  141.         NumberOfFunctions,
  142.         NumberOfNames,
  143.         AddressOfFunctions,
  144.         AddressOfNames,
  145.         AddressOfNameOrdinals: DWORD
  146.  
  147.     END;
  148.  
  149.  
  150.     VIRTUAL_ADDR = RECORD
  151.  
  152.         Code, Data, Bss, Import: INTEGER
  153.  
  154.     END;
  155.  
  156.  
  157.     FILE = WR.FILE;
  158.  
  159.  
  160. VAR
  161.  
  162.     msdos:           ARRAY 128 OF BYTE;
  163.     PEHeader:        IMAGE_NT_HEADERS;
  164.     SectionHeaders:  ARRAY 16 OF IMAGE_SECTION_HEADER;
  165.     Relocations:     LISTS.LIST;
  166.     bit64:           BOOLEAN;
  167.     libcnt:          INTEGER;
  168.  
  169.  
  170. PROCEDURE SIZE (): INTEGER;
  171.     RETURN SIZE_OF_DWORD * (ORD(bit64) + 1)
  172. END SIZE;
  173.  
  174.  
  175. PROCEDURE Export (program: BIN.PROGRAM; DataRVA: INTEGER; VAR ExportDir: IMAGE_EXPORT_DIRECTORY): INTEGER;
  176. BEGIN
  177.  
  178.     ExportDir.Characteristics        :=  0;
  179.     ExportDir.TimeDateStamp          :=  PEHeader.FileHeader.TimeDateStamp;
  180.     ExportDir.MajorVersion           :=  0X;
  181.     ExportDir.MinorVersion           :=  0X;
  182.     ExportDir.Name                   :=  program.modname + DataRVA;
  183.     ExportDir.Base                   :=  0;
  184.     ExportDir.NumberOfFunctions      :=  LISTS.count(program.exp_list);
  185.     ExportDir.NumberOfNames          :=  ExportDir.NumberOfFunctions;
  186.     ExportDir.AddressOfFunctions     :=  SIZE_OF_IMAGE_EXPORT_DIRECTORY;
  187.     ExportDir.AddressOfNames         :=  ExportDir.AddressOfFunctions + ExportDir.NumberOfFunctions * SIZE_OF_DWORD;
  188.     ExportDir.AddressOfNameOrdinals  :=  ExportDir.AddressOfNames     + ExportDir.NumberOfFunctions * SIZE_OF_DWORD
  189.  
  190.     RETURN SIZE_OF_IMAGE_EXPORT_DIRECTORY + ExportDir.NumberOfFunctions * (2 * SIZE_OF_DWORD + SIZE_OF_WORD)
  191. END Export;
  192.  
  193.  
  194. PROCEDURE align (n, _align: INTEGER): INTEGER;
  195. BEGIN
  196.     IF n MOD _align # 0 THEN
  197.         n := n + _align - (n MOD _align)
  198.     END
  199.  
  200.     RETURN n
  201. END align;
  202.  
  203.  
  204. PROCEDURE GetProcCount (lib: BIN.IMPRT): INTEGER;
  205. VAR
  206.     import: BIN.IMPRT;
  207.     res:    INTEGER;
  208.  
  209. BEGIN
  210.     res := 0;
  211.     import := lib.next(BIN.IMPRT);
  212.     WHILE (import # NIL) & (import.label # 0) DO
  213.         INC(res);
  214.         import := import.next(BIN.IMPRT)
  215.     END
  216.  
  217.     RETURN res
  218. END GetProcCount;
  219.  
  220.  
  221. PROCEDURE GetImportSize (imp_list: LISTS.LIST): INTEGER;
  222. VAR
  223.     import: BIN.IMPRT;
  224.     proccnt: INTEGER;
  225.     procoffs: INTEGER;
  226.     OriginalCurrentThunk,
  227.     CurrentThunk: INTEGER;
  228.  
  229. BEGIN
  230.     libcnt  := 0;
  231.     proccnt := 0;
  232.     import  := imp_list.first(BIN.IMPRT);
  233.     WHILE import # NIL DO
  234.         IF import.label = 0 THEN
  235.             INC(libcnt)
  236.         ELSE
  237.             INC(proccnt)
  238.         END;
  239.         import := import.next(BIN.IMPRT)
  240.     END;
  241.  
  242.     procoffs := 0;
  243.  
  244.     import  := imp_list.first(BIN.IMPRT);
  245.     WHILE import # NIL DO
  246.         IF import.label = 0 THEN
  247.             import.OriginalFirstThunk := procoffs;
  248.             import.FirstThunk := procoffs + (GetProcCount(import) + 1);
  249.             OriginalCurrentThunk := import.OriginalFirstThunk;
  250.             CurrentThunk := import.FirstThunk;
  251.             procoffs := procoffs + (GetProcCount(import) + 1) * 2
  252.         ELSE
  253.             import.OriginalFirstThunk := OriginalCurrentThunk;
  254.             import.FirstThunk := CurrentThunk;
  255.             INC(OriginalCurrentThunk);
  256.             INC(CurrentThunk)
  257.         END;
  258.         import := import.next(BIN.IMPRT)
  259.     END
  260.  
  261.     RETURN (libcnt + 1) * 5 * SIZE_OF_DWORD + (proccnt + libcnt) * 2 * SIZE()
  262. END GetImportSize;
  263.  
  264.  
  265. PROCEDURE fixup (program: BIN.PROGRAM; Address: VIRTUAL_ADDR);
  266. VAR
  267.     reloc:   BIN.RELOC;
  268.     iproc:   BIN.IMPRT;
  269.     L:       INTEGER;
  270.     delta:   INTEGER;
  271.     AdrImp:  INTEGER;
  272.  
  273. BEGIN
  274.     AdrImp := Address.Import + (libcnt + 1) * 5 * SIZE_OF_DWORD;
  275.  
  276.     reloc := program.rel_list.first(BIN.RELOC);
  277.     WHILE reloc # NIL DO
  278.  
  279.         L := BIN.get32le(program.code, reloc.offset);
  280.         delta := 3 - reloc.offset - Address.Code - 7 * ORD(bit64);
  281.  
  282.         CASE reloc.opcode OF
  283.  
  284.         |BIN.PICDATA:
  285.               BIN.put32le(program.code, reloc.offset, L + Address.Data + delta)
  286.  
  287.         |BIN.PICCODE:
  288.               BIN.put32le(program.code, reloc.offset, BIN.GetLabel(program, L) + Address.Code + delta)
  289.  
  290.         |BIN.PICBSS:
  291.               BIN.put32le(program.code, reloc.offset, L + Address.Bss + delta)
  292.  
  293.         |BIN.PICIMP:
  294.               iproc := BIN.GetIProc(program, L);
  295.               BIN.put32le(program.code, reloc.offset, iproc.FirstThunk * SIZE() + AdrImp + delta)
  296.  
  297.         END;
  298.  
  299.         reloc := reloc.next(BIN.RELOC)
  300.     END
  301. END fixup;
  302.  
  303.  
  304. PROCEDURE WriteWord (file: FILE; w: WORD);
  305. BEGIN
  306.     WR.Write16LE(file, ORD(w))
  307. END WriteWord;
  308.  
  309.  
  310. PROCEDURE WriteName* (File: FILE; name: NAME);
  311. VAR
  312.     i, nameLen: INTEGER;
  313.  
  314. BEGIN
  315.     nameLen := LENGTH(name);
  316.  
  317.     FOR i := 0 TO nameLen - 1 DO
  318.         WR.WriteByte(File, ORD(name[i]))
  319.     END;
  320.  
  321.     i := LEN(name) - nameLen;
  322.     WHILE i > 0 DO
  323.         WR.WriteByte(File, 0);
  324.         DEC(i)
  325.     END
  326.  
  327. END WriteName;
  328.  
  329.  
  330. PROCEDURE WriteSectionHeader* (file: FILE; h: IMAGE_SECTION_HEADER);
  331. VAR
  332.     i, nameLen: INTEGER;
  333.  
  334. BEGIN
  335.     nameLen := LENGTH(h.Name);
  336.  
  337.     FOR i := 0 TO nameLen - 1 DO
  338.         WR.WriteByte(file, ORD(h.Name[i]))
  339.     END;
  340.  
  341.     i := LEN(h.Name) - nameLen;
  342.     WHILE i > 0 DO
  343.         WR.WriteByte(file, 0);
  344.         DEC(i)
  345.     END;
  346.  
  347.     WR.Write32LE(file, h.VirtualSize);
  348.     WR.Write32LE(file, h.VirtualAddress);
  349.     WR.Write32LE(file, h.SizeOfRawData);
  350.     WR.Write32LE(file, h.PointerToRawData);
  351.     WR.Write32LE(file, h.PointerToRelocations);
  352.     WR.Write32LE(file, h.PointerToLinenumbers);
  353.  
  354.     WriteWord(file, h.NumberOfRelocations);
  355.     WriteWord(file, h.NumberOfLinenumbers);
  356.  
  357.     WR.Write32LE(file, h.Characteristics)
  358. END WriteSectionHeader;
  359.  
  360.  
  361. PROCEDURE WriteFileHeader* (file: FILE; h: IMAGE_FILE_HEADER);
  362. BEGIN
  363.     WriteWord(file, h.Machine);
  364.     WriteWord(file, h.NumberOfSections);
  365.  
  366.     WR.Write32LE(file, h.TimeDateStamp);
  367.     WR.Write32LE(file, h.PointerToSymbolTable);
  368.     WR.Write32LE(file, h.NumberOfSymbols);
  369.  
  370.     WriteWord(file, h.SizeOfOptionalHeader);
  371.     WriteWord(file, h.Characteristics)
  372. END WriteFileHeader;
  373.  
  374.  
  375. PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; console, dll, amd64: BOOLEAN);
  376. VAR
  377.     i, n: INTEGER;
  378.  
  379.     Size: RECORD
  380.  
  381.         Code, Data, Bss, Stack, Import, Reloc, Export: INTEGER
  382.  
  383.     END;
  384.  
  385.     BaseAddress: INTEGER;
  386.  
  387.     Address: VIRTUAL_ADDR;
  388.  
  389.     File: FILE;
  390.  
  391.     import:       BIN.IMPRT;
  392.     ImportTable:  CHL.INTLIST;
  393.  
  394.     ExportDir:  IMAGE_EXPORT_DIRECTORY;
  395.     export:     BIN.EXPRT;
  396.  
  397.  
  398.     PROCEDURE WriteExportDir (file: FILE; e: IMAGE_EXPORT_DIRECTORY);
  399.     BEGIN
  400.         WR.Write32LE(file, e.Characteristics);
  401.         WR.Write32LE(file, e.TimeDateStamp);
  402.  
  403.         WriteWord(file, e.MajorVersion);
  404.         WriteWord(file, e.MinorVersion);
  405.  
  406.         WR.Write32LE(file, e.Name);
  407.         WR.Write32LE(file, e.Base);
  408.         WR.Write32LE(file, e.NumberOfFunctions);
  409.         WR.Write32LE(file, e.NumberOfNames);
  410.         WR.Write32LE(file, e.AddressOfFunctions);
  411.         WR.Write32LE(file, e.AddressOfNames);
  412.         WR.Write32LE(file, e.AddressOfNameOrdinals)
  413.     END WriteExportDir;
  414.  
  415.  
  416.     PROCEDURE WriteOptHeader (file: FILE; h: IMAGE_OPTIONAL_HEADER);
  417.     VAR
  418.         i: INTEGER;
  419.  
  420.     BEGIN
  421.  
  422.         WriteWord(file, h.Magic);
  423.  
  424.         WR.WriteByte(file, h.MajorLinkerVersion);
  425.         WR.WriteByte(file, h.MinorLinkerVersion);
  426.  
  427.         WR.Write32LE(file, h.SizeOfCode);
  428.         WR.Write32LE(file, h.SizeOfInitializedData);
  429.         WR.Write32LE(file, h.SizeOfUninitializedData);
  430.         WR.Write32LE(file, h.AddressOfEntryPoint);
  431.         WR.Write32LE(file, h.BaseOfCode);
  432.  
  433.         IF bit64 THEN
  434.             WR.Write64LE(file, h.ImageBase)
  435.         ELSE
  436.             WR.Write32LE(file, h.BaseOfData);
  437.             WR.Write32LE(file, h.ImageBase)
  438.         END;
  439.  
  440.         WR.Write32LE(file, h.SectionAlignment);
  441.         WR.Write32LE(file, h.FileAlignment);
  442.  
  443.         WriteWord(file, h.MajorOperatingSystemVersion);
  444.         WriteWord(file, h.MinorOperatingSystemVersion);
  445.         WriteWord(file, h.MajorImageVersion);
  446.         WriteWord(file, h.MinorImageVersion);
  447.         WriteWord(file, h.MajorSubsystemVersion);
  448.         WriteWord(file, h.MinorSubsystemVersion);
  449.  
  450.         WR.Write32LE(file, h.Win32VersionValue);
  451.         WR.Write32LE(file, h.SizeOfImage);
  452.         WR.Write32LE(file, h.SizeOfHeaders);
  453.         WR.Write32LE(file, h.CheckSum);
  454.  
  455.         WriteWord(file, h.Subsystem);
  456.         WriteWord(file, h.DllCharacteristics);
  457.  
  458.         IF bit64 THEN
  459.             WR.Write64LE(file, h.SizeOfStackReserve);
  460.             WR.Write64LE(file, h.SizeOfStackCommit);
  461.             WR.Write64LE(file, h.SizeOfHeapReserve);
  462.             WR.Write64LE(file, h.SizeOfHeapCommit)
  463.         ELSE
  464.             WR.Write32LE(file, h.SizeOfStackReserve);
  465.             WR.Write32LE(file, h.SizeOfStackCommit);
  466.             WR.Write32LE(file, h.SizeOfHeapReserve);
  467.             WR.Write32LE(file, h.SizeOfHeapCommit)
  468.         END;
  469.  
  470.         WR.Write32LE(file, h.LoaderFlags);
  471.         WR.Write32LE(file, h.NumberOfRvaAndSizes);
  472.  
  473.         FOR i := 0 TO LEN(h.DataDirectory) - 1 DO
  474.             WR.Write32LE(file, h.DataDirectory[i].VirtualAddress);
  475.             WR.Write32LE(file, h.DataDirectory[i].Size)
  476.         END
  477.  
  478.     END WriteOptHeader;
  479.  
  480.  
  481.     PROCEDURE WritePEHeader (file: FILE; h: IMAGE_NT_HEADERS);
  482.     BEGIN
  483.         WR.Write(file, h.Signature, LEN(h.Signature));
  484.         WriteFileHeader(file, h.FileHeader);
  485.         WriteOptHeader(file, h.OptionalHeader)
  486.     END WritePEHeader;
  487.  
  488.  
  489.     PROCEDURE InitSection (VAR section: IMAGE_SECTION_HEADER; Name: NAME; Characteristics: DWORD);
  490.     BEGIN
  491.         section.Name                  :=  Name;
  492.         section.PointerToRelocations  :=  0;
  493.         section.PointerToLinenumbers  :=  0;
  494.         section.NumberOfRelocations   :=  0X;
  495.         section.NumberOfLinenumbers   :=  0X;
  496.         section.Characteristics       :=  Characteristics
  497.     END InitSection;
  498.  
  499.  
  500. BEGIN
  501.     bit64 := amd64;
  502.     Relocations := LISTS.create(NIL);
  503.  
  504.     Size.Code  := CHL.Length(program.code);
  505.     Size.Data  := CHL.Length(program.data);
  506.     Size.Bss   := program.bss;
  507.     Size.Stack := program.stack;
  508.  
  509.     IF dll THEN
  510.         BaseAddress := 10000000H
  511.     ELSE
  512.         BaseAddress := 400000H
  513.     END;
  514.  
  515.     PEHeader.Signature[0] := 50H;
  516.     PEHeader.Signature[1] := 45H;
  517.     PEHeader.Signature[2] := 0;
  518.     PEHeader.Signature[3] := 0;
  519.  
  520.     IF amd64 THEN
  521.         PEHeader.FileHeader.Machine := 08664X
  522.     ELSE
  523.         PEHeader.FileHeader.Machine := 014CX
  524.     END;
  525.  
  526.     PEHeader.FileHeader.NumberOfSections := WCHR(4 + ORD(dll));
  527.  
  528.     PEHeader.FileHeader.TimeDateStamp         :=  UTILS.UnixTime();
  529.     PEHeader.FileHeader.PointerToSymbolTable  :=  0H;
  530.     PEHeader.FileHeader.NumberOfSymbols       :=  0H;
  531.     PEHeader.FileHeader.SizeOfOptionalHeader  :=  WCHR(0E0H + 10H * ORD(amd64));
  532.     PEHeader.FileHeader.Characteristics       :=  WCHR(010EH + (20H - 100H) * ORD(amd64) + 2000H * ORD(dll));
  533.  
  534.     PEHeader.OptionalHeader.Magic                        :=  WCHR(010BH + 100H * ORD(amd64));
  535.     PEHeader.OptionalHeader.MajorLinkerVersion           :=  mConst.vMajor;
  536.     PEHeader.OptionalHeader.MinorLinkerVersion           :=  mConst.vMinor;
  537.     PEHeader.OptionalHeader.SizeOfCode                   :=  align(Size.Code, FileAlignment);
  538.     PEHeader.OptionalHeader.SizeOfInitializedData        :=  0;
  539.     PEHeader.OptionalHeader.SizeOfUninitializedData      :=  0;
  540.     PEHeader.OptionalHeader.AddressOfEntryPoint          :=  SectionAlignment;
  541.     PEHeader.OptionalHeader.BaseOfCode                   :=  SectionAlignment;
  542.     PEHeader.OptionalHeader.BaseOfData                   :=  PEHeader.OptionalHeader.BaseOfCode + align(Size.Code, SectionAlignment);
  543.     PEHeader.OptionalHeader.ImageBase                    :=  BaseAddress;
  544.     PEHeader.OptionalHeader.SectionAlignment             :=  SectionAlignment;
  545.     PEHeader.OptionalHeader.FileAlignment                :=  FileAlignment;
  546.     PEHeader.OptionalHeader.MajorOperatingSystemVersion  :=  1X;
  547.     PEHeader.OptionalHeader.MinorOperatingSystemVersion  :=  0X;
  548.     PEHeader.OptionalHeader.MajorImageVersion            :=  0X;
  549.     PEHeader.OptionalHeader.MinorImageVersion            :=  0X;
  550.     PEHeader.OptionalHeader.MajorSubsystemVersion        :=  4X;
  551.     PEHeader.OptionalHeader.MinorSubsystemVersion        :=  0X;
  552.     PEHeader.OptionalHeader.Win32VersionValue            :=  0H;
  553.     PEHeader.OptionalHeader.SizeOfImage                  :=  SectionAlignment;
  554.     PEHeader.OptionalHeader.SizeOfHeaders                :=  400H;
  555.     PEHeader.OptionalHeader.CheckSum                     :=  0;
  556.     PEHeader.OptionalHeader.Subsystem                    :=  WCHR((2 + ORD(console)) * ORD(~dll));
  557.     PEHeader.OptionalHeader.DllCharacteristics           :=  0040X;
  558.     PEHeader.OptionalHeader.SizeOfStackReserve           :=  Size.Stack;
  559.     PEHeader.OptionalHeader.SizeOfStackCommit            :=  Size.Stack DIV 16;
  560.     PEHeader.OptionalHeader.SizeOfHeapReserve            :=  100000H;
  561.     PEHeader.OptionalHeader.SizeOfHeapCommit             :=  10000H;
  562.     PEHeader.OptionalHeader.LoaderFlags                  :=  0;
  563.     PEHeader.OptionalHeader.NumberOfRvaAndSizes          :=  IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
  564.  
  565.     InitSection(SectionHeaders[0], ".text", SHC_text);
  566.     SectionHeaders[0].VirtualSize           :=  Size.Code;
  567.     SectionHeaders[0].VirtualAddress        :=  SectionAlignment;
  568.     SectionHeaders[0].SizeOfRawData         :=  align(Size.Code, FileAlignment);
  569.     SectionHeaders[0].PointerToRawData      :=  PEHeader.OptionalHeader.SizeOfHeaders;
  570.  
  571.     InitSection(SectionHeaders[1], ".data", SHC_data);
  572.     SectionHeaders[1].VirtualSize           :=  Size.Data;
  573.     SectionHeaders[1].VirtualAddress        :=  align(SectionHeaders[0].VirtualAddress + SectionHeaders[0].VirtualSize, SectionAlignment);
  574.     SectionHeaders[1].SizeOfRawData         :=  align(Size.Data, FileAlignment);
  575.     SectionHeaders[1].PointerToRawData      :=  SectionHeaders[0].PointerToRawData + SectionHeaders[0].SizeOfRawData;
  576.  
  577.     InitSection(SectionHeaders[2], ".bss", SHC_bss);
  578.     SectionHeaders[2].VirtualSize           :=  Size.Bss;
  579.     SectionHeaders[2].VirtualAddress        :=  align(SectionHeaders[1].VirtualAddress + SectionHeaders[1].VirtualSize, SectionAlignment);
  580.     SectionHeaders[2].SizeOfRawData         :=  0;
  581.     SectionHeaders[2].PointerToRawData      :=  SectionHeaders[1].PointerToRawData + SectionHeaders[1].SizeOfRawData;
  582.  
  583.     Size.Import := GetImportSize(program.imp_list);
  584.  
  585.     InitSection(SectionHeaders[3], ".idata", SHC_data);
  586.     SectionHeaders[3].VirtualSize           :=  Size.Import + CHL.Length(program.import);
  587.     SectionHeaders[3].VirtualAddress        :=  align(SectionHeaders[2].VirtualAddress + SectionHeaders[2].VirtualSize, SectionAlignment);
  588.     SectionHeaders[3].SizeOfRawData         :=  align(SectionHeaders[3].VirtualSize, FileAlignment);
  589.     SectionHeaders[3].PointerToRawData      :=  SectionHeaders[2].PointerToRawData + SectionHeaders[2].SizeOfRawData;
  590.  
  591.     Address.Code   := SectionHeaders[0].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  592.     Address.Data   := SectionHeaders[1].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  593.     Address.Bss    := SectionHeaders[2].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  594.     Address.Import := SectionHeaders[3].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  595.  
  596.     fixup(program, Address);
  597.  
  598.     IF dll THEN
  599.         Size.Export := Export(program, SectionHeaders[1].VirtualAddress, ExportDir);
  600.  
  601.         InitSection(SectionHeaders[4], ".edata", SHC_data);
  602.         SectionHeaders[4].VirtualSize           :=  Size.Export + CHL.Length(program.export);
  603.         SectionHeaders[4].VirtualAddress        :=  align(SectionHeaders[3].VirtualAddress + SectionHeaders[3].VirtualSize, SectionAlignment);
  604.         SectionHeaders[4].SizeOfRawData         :=  align(SectionHeaders[4].VirtualSize, FileAlignment);
  605.         SectionHeaders[4].PointerToRawData      :=  SectionHeaders[3].PointerToRawData + SectionHeaders[3].SizeOfRawData;
  606.     END;
  607.  
  608.     FOR i := 0 TO IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 DO
  609.         PEHeader.OptionalHeader.DataDirectory[i].VirtualAddress := 0;
  610.         PEHeader.OptionalHeader.DataDirectory[i].Size := 0
  611.     END;
  612.  
  613.     IF dll THEN
  614.         PEHeader.OptionalHeader.DataDirectory[0].VirtualAddress := SectionHeaders[4].VirtualAddress;
  615.         PEHeader.OptionalHeader.DataDirectory[0].Size := SectionHeaders[4].VirtualSize
  616.     END;
  617.  
  618.     PEHeader.OptionalHeader.DataDirectory[1].VirtualAddress := SectionHeaders[3].VirtualAddress;
  619.     PEHeader.OptionalHeader.DataDirectory[1].Size := SectionHeaders[3].VirtualSize;
  620.  
  621.     FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
  622.         INC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[i].SizeOfRawData)
  623.     END;
  624.  
  625.     DEC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[0].SizeOfRawData);
  626.     DEC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[2].SizeOfRawData);
  627.  
  628.     PEHeader.OptionalHeader.SizeOfUninitializedData := align(SectionHeaders[2].VirtualSize, FileAlignment);
  629.  
  630.     FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
  631.         INC(PEHeader.OptionalHeader.SizeOfImage, align(SectionHeaders[i].VirtualSize, SectionAlignment))
  632.     END;
  633.  
  634.     n := 0;
  635.     BIN.InitArray(msdos, n, "4D5A80000100000004001000FFFF000040010000000000004000000000000000");
  636.     BIN.InitArray(msdos, n, "0000000000000000000000000000000000000000000000000000000080000000");
  637.     BIN.InitArray(msdos, n, "0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F");
  638.     BIN.InitArray(msdos, n, "742062652072756E20696E20444F53206D6F64652E0D0A240000000000000000");
  639.  
  640.     File := WR.Create(FileName);
  641.  
  642.     WR.Write(File, msdos, LEN(msdos));
  643.  
  644.     WritePEHeader(File, PEHeader);
  645.  
  646.     FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
  647.         WriteSectionHeader(File, SectionHeaders[i])
  648.     END;
  649.  
  650.     WR.Padding(File, FileAlignment);
  651.  
  652.     CHL.WriteToFile(File, program.code);
  653.     WR.Padding(File, FileAlignment);
  654.  
  655.     CHL.WriteToFile(File, program.data);
  656.     WR.Padding(File, FileAlignment);
  657.  
  658.     n := (libcnt + 1) * 5;
  659.     ImportTable := CHL.CreateIntList();
  660.  
  661.     FOR i := 0 TO (Size.Import - n * SIZE_OF_DWORD) DIV SIZE() + n - 1 DO
  662.         CHL.PushInt(ImportTable, 0)
  663.     END;
  664.  
  665.     i := 0;
  666.     import := program.imp_list.first(BIN.IMPRT);
  667.     WHILE import # NIL DO
  668.         IF import.label = 0 THEN
  669.             CHL.SetInt(ImportTable, i + 0, import.OriginalFirstThunk * SIZE() + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
  670.             CHL.SetInt(ImportTable, i + 1, 0);
  671.             CHL.SetInt(ImportTable, i + 2, 0);
  672.             CHL.SetInt(ImportTable, i + 3, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress);
  673.             CHL.SetInt(ImportTable, i + 4, import.FirstThunk * SIZE() + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
  674.             i := i + 5
  675.         END;
  676.         import := import.next(BIN.IMPRT)
  677.     END;
  678.  
  679.     CHL.SetInt(ImportTable, i + 0, 0);
  680.     CHL.SetInt(ImportTable, i + 1, 0);
  681.     CHL.SetInt(ImportTable, i + 2, 0);
  682.     CHL.SetInt(ImportTable, i + 3, 0);
  683.     CHL.SetInt(ImportTable, i + 4, 0);
  684.  
  685.     import := program.imp_list.first(BIN.IMPRT);
  686.     WHILE import # NIL DO
  687.         IF import.label # 0 THEN
  688.             CHL.SetInt(ImportTable, import.OriginalFirstThunk + n, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2);
  689.             CHL.SetInt(ImportTable, import.FirstThunk + n,         import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2)
  690.         END;
  691.         import := import.next(BIN.IMPRT)
  692.     END;
  693.  
  694.     FOR i := 0 TO n - 1 DO
  695.         WR.Write32LE(File, CHL.GetInt(ImportTable, i))
  696.     END;
  697.  
  698.     FOR i := n TO CHL.Length(ImportTable) - 1 DO
  699.         IF amd64 THEN
  700.             WR.Write64LE(File, CHL.GetInt(ImportTable, i))
  701.         ELSE
  702.             WR.Write32LE(File, CHL.GetInt(ImportTable, i))
  703.         END
  704.     END;
  705.  
  706.     CHL.WriteToFile(File, program.import);
  707.     WR.Padding(File, FileAlignment);
  708.  
  709.     IF dll THEN
  710.  
  711.         INC(ExportDir.AddressOfFunctions,    SectionHeaders[4].VirtualAddress);
  712.         INC(ExportDir.AddressOfNames,        SectionHeaders[4].VirtualAddress);
  713.         INC(ExportDir.AddressOfNameOrdinals, SectionHeaders[4].VirtualAddress);
  714.  
  715.         WriteExportDir(File, ExportDir);
  716.  
  717.         export := program.exp_list.first(BIN.EXPRT);
  718.         WHILE export # NIL DO
  719.             WR.Write32LE(File, export.label + SectionHeaders[0].VirtualAddress);
  720.             export := export.next(BIN.EXPRT)
  721.         END;
  722.  
  723.         export := program.exp_list.first(BIN.EXPRT);
  724.         WHILE export # NIL DO
  725.             WR.Write32LE(File, export.nameoffs + Size.Export + SectionHeaders[4].VirtualAddress);
  726.             export := export.next(BIN.EXPRT)
  727.         END;
  728.  
  729.         FOR i := 0 TO ExportDir.NumberOfFunctions - 1 DO
  730.             WriteWord(File, WCHR(i))
  731.         END;
  732.  
  733.         CHL.WriteToFile(File, program.export);
  734.         WR.Padding(File, FileAlignment)
  735.     END;
  736.  
  737.     WR.Close(File)
  738. END write;
  739.  
  740.  
  741. END PE32.
  742.