Subversion Repositories Kolibri OS

Rev

Rev 7696 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7983 leency 1
(*
7597 akron1 2
    BSD 2-Clause License
3
 
7696 akron1 4
    Copyright (c) 2018-2019, Anton Krotov
7597 akron1 5
    All rights reserved.
6
*)
7
 
8
MODULE PE32;
9
 
7983 leency 10
IMPORT BIN, LISTS, UTILS, WR := WRITER, CHL := CHUNKLISTS;
7597 akron1 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;
7696 akron1 31
    SHC_data  = 040000040H;
32
    SHC_bss   = 0C0000080H;
7597 akron1 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;
7983 leency 168
    SizeOfWord:      INTEGER;
7597 akron1 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
 
7983 leency 257
    RETURN (libcnt + 1) * 5 * SIZE_OF_DWORD + (proccnt + libcnt) * 2 * SizeOfWord
7597 akron1 258
END GetImportSize;
259
 
260
 
261
PROCEDURE fixup (program: BIN.PROGRAM; Address: VIRTUAL_ADDR);
262
VAR
7983 leency 263
    reloc: BIN.RELOC;
264
    iproc: BIN.IMPRT;
265
    code:  CHL.BYTELIST;
266
    L, delta, delta0, AdrImp: INTEGER;
7597 akron1 267
 
268
BEGIN
269
    AdrImp := Address.Import + (libcnt + 1) * 5 * SIZE_OF_DWORD;
7983 leency 270
    code := program.code;
271
    reloc := program.rel_list.first(BIN.RELOC);
272
    delta0 := 3 - 7 * ORD(bit64);
7597 akron1 273
 
274
    WHILE reloc # NIL DO
275
 
7983 leency 276
        L := BIN.get32le(code, reloc.offset);
277
        delta := delta0 - reloc.offset - Address.Code;
7597 akron1 278
 
279
        CASE reloc.opcode OF
280
 
281
        |BIN.PICDATA:
7983 leency 282
              BIN.put32le(code, reloc.offset, L + Address.Data + delta)
7597 akron1 283
 
284
        |BIN.PICCODE:
7983 leency 285
              BIN.put32le(code, reloc.offset, BIN.GetLabel(program, L) + Address.Code + delta)
7597 akron1 286
 
287
        |BIN.PICBSS:
7983 leency 288
              BIN.put32le(code, reloc.offset, L + Address.Bss + delta)
7597 akron1 289
 
290
        |BIN.PICIMP:
291
              iproc := BIN.GetIProc(program, L);
7983 leency 292
              BIN.put32le(code, reloc.offset, iproc.FirstThunk * SizeOfWord + AdrImp + delta)
7597 akron1 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
 
7696 akron1 372
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; console, dll, amd64: BOOLEAN);
7597 akron1 373
VAR
374
    i, n: INTEGER;
375
 
376
    Size: RECORD
377
 
378
        Code, Data, Bss, Stack, Import, Reloc, Export: INTEGER
379
 
380
    END;
381
 
7696 akron1 382
    BaseAddress: INTEGER;
383
 
7597 akron1 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;
7983 leency 498
    SizeOfWord := SIZE_OF_DWORD * (ORD(bit64) + 1);
7597 akron1 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
 
7696 akron1 506
    IF dll THEN
507
        BaseAddress := 10000000H
508
    ELSE
509
        BaseAddress := 400000H
510
    END;
511
 
7597 akron1 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));
7983 leency 532
    PEHeader.OptionalHeader.MajorLinkerVersion           :=  UTILS.vMajor;
533
    PEHeader.OptionalHeader.MinorLinkerVersion           :=  UTILS.vMinor;
7597 akron1 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);
7983 leency 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;
7597 akron1 567
 
568
    InitSection(SectionHeaders[1], ".data", SHC_data);
7983 leency 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;
7597 akron1 573
 
574
    InitSection(SectionHeaders[2], ".bss", SHC_bss);
7983 leency 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;
7597 akron1 579
 
580
    Size.Import := GetImportSize(program.imp_list);
581
 
582
    InitSection(SectionHeaders[3], ".idata", SHC_data);
7983 leency 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;
7597 akron1 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);
7983 leency 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;
7597 akron1 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
 
7983 leency 658
    FOR i := 0 TO (Size.Import - n * SIZE_OF_DWORD) DIV SizeOfWord + n - 1 DO
7597 akron1 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
7983 leency 666
            CHL.SetInt(ImportTable, i + 0, import.OriginalFirstThunk * SizeOfWord + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
7597 akron1 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);
7983 leency 670
            CHL.SetInt(ImportTable, i + 4, import.FirstThunk * SizeOfWord + SectionHeaders[3].VirtualAddress + n * SIZE_OF_DWORD);
7597 akron1 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
 
7983 leency 738
END PE32.