Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
7597 akron1 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.