Subversion Repositories Kolibri OS

Rev

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