Subversion Repositories Kolibri OS

Rev

Rev 8097 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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