Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | 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  = 0C0000040H;
  32.     SHC_bss   = 0C00000C0H;
  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; BaseAddress: INTEGER; 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.     Address: VIRTUAL_ADDR;
  386.  
  387.     File: FILE;
  388.  
  389.     import:       BIN.IMPRT;
  390.     ImportTable:  CHL.INTLIST;
  391.  
  392.     ExportDir:  IMAGE_EXPORT_DIRECTORY;
  393.     export:     BIN.EXPRT;
  394.  
  395.  
  396.     PROCEDURE WriteExportDir (file: FILE; e: IMAGE_EXPORT_DIRECTORY);
  397.     BEGIN
  398.         WR.Write32LE(file, e.Characteristics);
  399.         WR.Write32LE(file, e.TimeDateStamp);
  400.  
  401.         WriteWord(file, e.MajorVersion);
  402.         WriteWord(file, e.MinorVersion);
  403.  
  404.         WR.Write32LE(file, e.Name);
  405.         WR.Write32LE(file, e.Base);
  406.         WR.Write32LE(file, e.NumberOfFunctions);
  407.         WR.Write32LE(file, e.NumberOfNames);
  408.         WR.Write32LE(file, e.AddressOfFunctions);
  409.         WR.Write32LE(file, e.AddressOfNames);
  410.         WR.Write32LE(file, e.AddressOfNameOrdinals)
  411.     END WriteExportDir;
  412.  
  413.  
  414.     PROCEDURE WriteOptHeader (file: FILE; h: IMAGE_OPTIONAL_HEADER);
  415.     VAR
  416.         i: INTEGER;
  417.  
  418.     BEGIN
  419.  
  420.         WriteWord(file, h.Magic);
  421.  
  422.         WR.WriteByte(file, h.MajorLinkerVersion);
  423.         WR.WriteByte(file, h.MinorLinkerVersion);
  424.  
  425.         WR.Write32LE(file, h.SizeOfCode);
  426.         WR.Write32LE(file, h.SizeOfInitializedData);
  427.         WR.Write32LE(file, h.SizeOfUninitializedData);
  428.         WR.Write32LE(file, h.AddressOfEntryPoint);
  429.         WR.Write32LE(file, h.BaseOfCode);
  430.  
  431.         IF bit64 THEN
  432.             WR.Write64LE(file, h.ImageBase)
  433.         ELSE
  434.             WR.Write32LE(file, h.BaseOfData);
  435.             WR.Write32LE(file, h.ImageBase)
  436.         END;
  437.  
  438.         WR.Write32LE(file, h.SectionAlignment);
  439.         WR.Write32LE(file, h.FileAlignment);
  440.  
  441.         WriteWord(file, h.MajorOperatingSystemVersion);
  442.         WriteWord(file, h.MinorOperatingSystemVersion);
  443.         WriteWord(file, h.MajorImageVersion);
  444.         WriteWord(file, h.MinorImageVersion);
  445.         WriteWord(file, h.MajorSubsystemVersion);
  446.         WriteWord(file, h.MinorSubsystemVersion);
  447.  
  448.         WR.Write32LE(file, h.Win32VersionValue);
  449.         WR.Write32LE(file, h.SizeOfImage);
  450.         WR.Write32LE(file, h.SizeOfHeaders);
  451.         WR.Write32LE(file, h.CheckSum);
  452.  
  453.         WriteWord(file, h.Subsystem);
  454.         WriteWord(file, h.DllCharacteristics);
  455.  
  456.         IF bit64 THEN
  457.             WR.Write64LE(file, h.SizeOfStackReserve);
  458.             WR.Write64LE(file, h.SizeOfStackCommit);
  459.             WR.Write64LE(file, h.SizeOfHeapReserve);
  460.             WR.Write64LE(file, h.SizeOfHeapCommit)
  461.         ELSE
  462.             WR.Write32LE(file, h.SizeOfStackReserve);
  463.             WR.Write32LE(file, h.SizeOfStackCommit);
  464.             WR.Write32LE(file, h.SizeOfHeapReserve);
  465.             WR.Write32LE(file, h.SizeOfHeapCommit)
  466.         END;
  467.  
  468.         WR.Write32LE(file, h.LoaderFlags);
  469.         WR.Write32LE(file, h.NumberOfRvaAndSizes);
  470.  
  471.         FOR i := 0 TO LEN(h.DataDirectory) - 1 DO
  472.             WR.Write32LE(file, h.DataDirectory[i].VirtualAddress);
  473.             WR.Write32LE(file, h.DataDirectory[i].Size)
  474.         END
  475.  
  476.     END WriteOptHeader;
  477.  
  478.  
  479.     PROCEDURE WritePEHeader (file: FILE; h: IMAGE_NT_HEADERS);
  480.     BEGIN
  481.         WR.Write(file, h.Signature, LEN(h.Signature));
  482.         WriteFileHeader(file, h.FileHeader);
  483.         WriteOptHeader(file, h.OptionalHeader)
  484.     END WritePEHeader;
  485.  
  486.  
  487.     PROCEDURE InitSection (VAR section: IMAGE_SECTION_HEADER; Name: NAME; Characteristics: DWORD);
  488.     BEGIN
  489.         section.Name                  :=  Name;
  490.         section.PointerToRelocations  :=  0;
  491.         section.PointerToLinenumbers  :=  0;
  492.         section.NumberOfRelocations   :=  0X;
  493.         section.NumberOfLinenumbers   :=  0X;
  494.         section.Characteristics       :=  Characteristics
  495.     END InitSection;
  496.  
  497.  
  498. BEGIN
  499.     bit64 := amd64;
  500.     Relocations := LISTS.create(NIL);
  501.  
  502.     Size.Code  := CHL.Length(program.code);
  503.     Size.Data  := CHL.Length(program.data);
  504.     Size.Bss   := program.bss;
  505.     Size.Stack := program.stack;
  506.  
  507.     PEHeader.Signature[0] := 50H;
  508.     PEHeader.Signature[1] := 45H;
  509.     PEHeader.Signature[2] := 0;
  510.     PEHeader.Signature[3] := 0;
  511.  
  512.     IF amd64 THEN
  513.         PEHeader.FileHeader.Machine := 08664X
  514.     ELSE
  515.         PEHeader.FileHeader.Machine := 014CX
  516.     END;
  517.  
  518.     PEHeader.FileHeader.NumberOfSections := WCHR(4 + ORD(dll));
  519.  
  520.     PEHeader.FileHeader.TimeDateStamp         :=  UTILS.UnixTime();
  521.     PEHeader.FileHeader.PointerToSymbolTable  :=  0H;
  522.     PEHeader.FileHeader.NumberOfSymbols       :=  0H;
  523.     PEHeader.FileHeader.SizeOfOptionalHeader  :=  WCHR(0E0H + 10H * ORD(amd64));
  524.     PEHeader.FileHeader.Characteristics       :=  WCHR(010EH + (20H - 100H) * ORD(amd64) + 2000H * ORD(dll));
  525.  
  526.     PEHeader.OptionalHeader.Magic                        :=  WCHR(010BH + 100H * ORD(amd64));
  527.     PEHeader.OptionalHeader.MajorLinkerVersion           :=  mConst.vMajor;
  528.     PEHeader.OptionalHeader.MinorLinkerVersion           :=  mConst.vMinor;
  529.     PEHeader.OptionalHeader.SizeOfCode                   :=  align(Size.Code, FileAlignment);
  530.     PEHeader.OptionalHeader.SizeOfInitializedData        :=  0;
  531.     PEHeader.OptionalHeader.SizeOfUninitializedData      :=  0;
  532.     PEHeader.OptionalHeader.AddressOfEntryPoint          :=  SectionAlignment;
  533.     PEHeader.OptionalHeader.BaseOfCode                   :=  SectionAlignment;
  534.     PEHeader.OptionalHeader.BaseOfData                   :=  PEHeader.OptionalHeader.BaseOfCode + align(Size.Code, SectionAlignment);
  535.     PEHeader.OptionalHeader.ImageBase                    :=  BaseAddress;
  536.     PEHeader.OptionalHeader.SectionAlignment             :=  SectionAlignment;
  537.     PEHeader.OptionalHeader.FileAlignment                :=  FileAlignment;
  538.     PEHeader.OptionalHeader.MajorOperatingSystemVersion  :=  1X;
  539.     PEHeader.OptionalHeader.MinorOperatingSystemVersion  :=  0X;
  540.     PEHeader.OptionalHeader.MajorImageVersion            :=  0X;
  541.     PEHeader.OptionalHeader.MinorImageVersion            :=  0X;
  542.     PEHeader.OptionalHeader.MajorSubsystemVersion        :=  4X;
  543.     PEHeader.OptionalHeader.MinorSubsystemVersion        :=  0X;
  544.     PEHeader.OptionalHeader.Win32VersionValue            :=  0H;
  545.     PEHeader.OptionalHeader.SizeOfImage                  :=  SectionAlignment;
  546.     PEHeader.OptionalHeader.SizeOfHeaders                :=  400H;
  547.     PEHeader.OptionalHeader.CheckSum                     :=  0;
  548.     PEHeader.OptionalHeader.Subsystem                    :=  WCHR((2 + ORD(console)) * ORD(~dll));
  549.     PEHeader.OptionalHeader.DllCharacteristics           :=  0040X;
  550.     PEHeader.OptionalHeader.SizeOfStackReserve           :=  Size.Stack;
  551.     PEHeader.OptionalHeader.SizeOfStackCommit            :=  Size.Stack DIV 16;
  552.     PEHeader.OptionalHeader.SizeOfHeapReserve            :=  100000H;
  553.     PEHeader.OptionalHeader.SizeOfHeapCommit             :=  10000H;
  554.     PEHeader.OptionalHeader.LoaderFlags                  :=  0;
  555.     PEHeader.OptionalHeader.NumberOfRvaAndSizes          :=  IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
  556.  
  557.     InitSection(SectionHeaders[0], ".text", SHC_text);
  558.     SectionHeaders[0].VirtualSize           :=  Size.Code;
  559.     SectionHeaders[0].VirtualAddress        :=  1000H;
  560.     SectionHeaders[0].SizeOfRawData         :=  align(Size.Code, FileAlignment);
  561.     SectionHeaders[0].PointerToRawData      :=  PEHeader.OptionalHeader.SizeOfHeaders;
  562.  
  563.     InitSection(SectionHeaders[1], ".data", SHC_data);
  564.     SectionHeaders[1].VirtualSize           :=  Size.Data;
  565.     SectionHeaders[1].VirtualAddress        :=  align(SectionHeaders[0].VirtualAddress + SectionHeaders[0].VirtualSize, SectionAlignment);
  566.     SectionHeaders[1].SizeOfRawData         :=  align(Size.Data, FileAlignment);
  567.     SectionHeaders[1].PointerToRawData      :=  SectionHeaders[0].PointerToRawData + SectionHeaders[0].SizeOfRawData;
  568.  
  569.     InitSection(SectionHeaders[2], ".bss", SHC_bss);
  570.     SectionHeaders[2].VirtualSize           :=  Size.Bss;
  571.     SectionHeaders[2].VirtualAddress        :=  align(SectionHeaders[1].VirtualAddress + SectionHeaders[1].VirtualSize, SectionAlignment);
  572.     SectionHeaders[2].SizeOfRawData         :=  0;
  573.     SectionHeaders[2].PointerToRawData      :=  SectionHeaders[1].PointerToRawData + SectionHeaders[1].SizeOfRawData;
  574.  
  575.     Size.Import := GetImportSize(program.imp_list);
  576.  
  577.     InitSection(SectionHeaders[3], ".idata", SHC_data);
  578.     SectionHeaders[3].VirtualSize           :=  Size.Import + CHL.Length(program.import);
  579.     SectionHeaders[3].VirtualAddress        :=  align(SectionHeaders[2].VirtualAddress + SectionHeaders[2].VirtualSize, SectionAlignment);
  580.     SectionHeaders[3].SizeOfRawData         :=  align(SectionHeaders[3].VirtualSize, FileAlignment);
  581.     SectionHeaders[3].PointerToRawData      :=  SectionHeaders[2].PointerToRawData + SectionHeaders[2].SizeOfRawData;
  582.  
  583.     Address.Code   := SectionHeaders[0].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  584.     Address.Data   := SectionHeaders[1].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  585.     Address.Bss    := SectionHeaders[2].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  586.     Address.Import := SectionHeaders[3].VirtualAddress + PEHeader.OptionalHeader.ImageBase;
  587.  
  588.     fixup(program, Address);
  589.  
  590.     IF dll THEN
  591.         Size.Export := Export(program, SectionHeaders[1].VirtualAddress, ExportDir);
  592.  
  593.         InitSection(SectionHeaders[4], ".edata", SHC_data);
  594.         SectionHeaders[4].VirtualSize           :=  Size.Export + CHL.Length(program.export);
  595.         SectionHeaders[4].VirtualAddress        :=  align(SectionHeaders[3].VirtualAddress + SectionHeaders[3].VirtualSize, SectionAlignment);
  596.         SectionHeaders[4].SizeOfRawData         :=  align(SectionHeaders[4].VirtualSize, FileAlignment);
  597.         SectionHeaders[4].PointerToRawData      :=  SectionHeaders[3].PointerToRawData + SectionHeaders[3].SizeOfRawData;
  598.     END;
  599.  
  600.     FOR i := 0 TO IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1 DO
  601.         PEHeader.OptionalHeader.DataDirectory[i].VirtualAddress := 0;
  602.         PEHeader.OptionalHeader.DataDirectory[i].Size := 0
  603.     END;
  604.  
  605.     IF dll THEN
  606.         PEHeader.OptionalHeader.DataDirectory[0].VirtualAddress := SectionHeaders[4].VirtualAddress;
  607.         PEHeader.OptionalHeader.DataDirectory[0].Size := SectionHeaders[4].VirtualSize
  608.     END;
  609.  
  610.     PEHeader.OptionalHeader.DataDirectory[1].VirtualAddress := SectionHeaders[3].VirtualAddress;
  611.     PEHeader.OptionalHeader.DataDirectory[1].Size := SectionHeaders[3].VirtualSize;
  612.  
  613.     FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
  614.         INC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[i].SizeOfRawData)
  615.     END;
  616.  
  617.     DEC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[0].SizeOfRawData);
  618.     DEC(PEHeader.OptionalHeader.SizeOfInitializedData, SectionHeaders[2].SizeOfRawData);
  619.  
  620.     PEHeader.OptionalHeader.SizeOfUninitializedData := align(SectionHeaders[2].VirtualSize, FileAlignment);
  621.  
  622.     FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
  623.         INC(PEHeader.OptionalHeader.SizeOfImage, align(SectionHeaders[i].VirtualSize, SectionAlignment))
  624.     END;
  625.  
  626.     n := 0;
  627.     BIN.InitArray(msdos, n, "4D5A80000100000004001000FFFF000040010000000000004000000000000000");
  628.     BIN.InitArray(msdos, n, "0000000000000000000000000000000000000000000000000000000080000000");
  629.     BIN.InitArray(msdos, n, "0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F");
  630.     BIN.InitArray(msdos, n, "742062652072756E20696E20444F53206D6F64652E0D0A240000000000000000");
  631.  
  632.     File := WR.Create(FileName);
  633.  
  634.     WR.Write(File, msdos, LEN(msdos));
  635.  
  636.     WritePEHeader(File, PEHeader);
  637.  
  638.     FOR i := 0 TO ORD(PEHeader.FileHeader.NumberOfSections) - 1 DO
  639.         WriteSectionHeader(File, SectionHeaders[i])
  640.     END;
  641.  
  642.     WR.Padding(File, FileAlignment);
  643.  
  644.     CHL.WriteToFile(File, program.code);
  645.     WR.Padding(File, FileAlignment);
  646.  
  647.     CHL.WriteToFile(File, program.data);
  648.     WR.Padding(File, FileAlignment);
  649.  
  650.     n := (libcnt + 1) * 5;
  651.     ImportTable := CHL.CreateIntList();
  652.  
  653.     FOR i := 0 TO (Size.Import - n * SIZE_OF_DWORD) DIV SIZE() + n - 1 DO
  654.         CHL.PushInt(ImportTable, 0)
  655.     END;
  656.  
  657.     i := 0;
  658.     import := program.imp_list.first(BIN.IMPRT);
  659.     WHILE import # NIL DO
  660.         IF import.label = 0 THEN
  661.             CHL.SetInt(ImportTable, i + 0, import.OriginalFirstThunk * SIZE() + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
  662.             CHL.SetInt(ImportTable, i + 1, 0);
  663.             CHL.SetInt(ImportTable, i + 2, 0);
  664.             CHL.SetInt(ImportTable, i + 3, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress);
  665.             CHL.SetInt(ImportTable, i + 4, import.FirstThunk * SIZE() + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
  666.             i := i + 5
  667.         END;
  668.         import := import.next(BIN.IMPRT)
  669.     END;
  670.  
  671.     CHL.SetInt(ImportTable, i + 0, 0);
  672.     CHL.SetInt(ImportTable, i + 1, 0);
  673.     CHL.SetInt(ImportTable, i + 2, 0);
  674.     CHL.SetInt(ImportTable, i + 3, 0);
  675.     CHL.SetInt(ImportTable, i + 4, 0);
  676.  
  677.     import := program.imp_list.first(BIN.IMPRT);
  678.     WHILE import # NIL DO
  679.         IF import.label # 0 THEN
  680.             CHL.SetInt(ImportTable, import.OriginalFirstThunk + n, import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2);
  681.             CHL.SetInt(ImportTable, import.FirstThunk + n,         import.nameoffs + Size.Import + SectionHeaders[3].VirtualAddress - 2)
  682.         END;
  683.         import := import.next(BIN.IMPRT)
  684.     END;
  685.  
  686.     FOR i := 0 TO n - 1 DO
  687.         WR.Write32LE(File, CHL.GetInt(ImportTable, i))
  688.     END;
  689.  
  690.     FOR i := n TO CHL.Length(ImportTable) - 1 DO
  691.         IF amd64 THEN
  692.             WR.Write64LE(File, CHL.GetInt(ImportTable, i))
  693.         ELSE
  694.             WR.Write32LE(File, CHL.GetInt(ImportTable, i))
  695.         END
  696.     END;
  697.  
  698.     CHL.WriteToFile(File, program.import);
  699.     WR.Padding(File, FileAlignment);
  700.  
  701.     IF dll THEN
  702.  
  703.         INC(ExportDir.AddressOfFunctions,    SectionHeaders[4].VirtualAddress);
  704.         INC(ExportDir.AddressOfNames,        SectionHeaders[4].VirtualAddress);
  705.         INC(ExportDir.AddressOfNameOrdinals, SectionHeaders[4].VirtualAddress);
  706.  
  707.         WriteExportDir(File, ExportDir);
  708.  
  709.         export := program.exp_list.first(BIN.EXPRT);
  710.         WHILE export # NIL DO
  711.             WR.Write32LE(File, export.label + SectionHeaders[0].VirtualAddress);
  712.             export := export.next(BIN.EXPRT)
  713.         END;
  714.  
  715.         export := program.exp_list.first(BIN.EXPRT);
  716.         WHILE export # NIL DO
  717.             WR.Write32LE(File, export.nameoffs + Size.Export + SectionHeaders[4].VirtualAddress);
  718.             export := export.next(BIN.EXPRT)
  719.         END;
  720.  
  721.         FOR i := 0 TO ExportDir.NumberOfFunctions - 1 DO
  722.             WriteWord(File, WCHR(i))
  723.         END;
  724.  
  725.         CHL.WriteToFile(File, program.export);
  726.         WR.Padding(File, FileAlignment)
  727.     END;
  728.  
  729.     WR.Close(File)
  730. END write;
  731.  
  732.  
  733. END PE32.