Subversion Repositories Kolibri OS

Rev

Rev 8097 | 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
6613 leency 3
 
8859 leency 4
    Copyright (c) 2019-2021, Anton Krotov
7597 akron1 5
    All rights reserved.
6
*)
6613 leency 7
 
7597 akron1 8
MODULE ELF;
6613 leency 9
 
8859 leency 10
IMPORT BIN, WR := WRITER, CHL := CHUNKLISTS, LISTS, PE32, UTILS, STRINGS;
6613 leency 11
 
12
 
7597 akron1 13
CONST
6613 leency 14
 
7597 akron1 15
    EI_NIDENT = 16;
16
    ET_EXEC = 2;
17
    ET_DYN = 3;
6613 leency 18
 
7597 akron1 19
    EM_386 = 3;
20
    EM_8664 = 3EH;
6613 leency 21
 
7597 akron1 22
    ELFCLASS32 = 1;
23
    ELFCLASS64 = 2;
24
 
25
    ELFDATA2LSB = 1;
26
    ELFDATA2MSB = 2;
27
 
28
    PF_X = 1;
29
    PF_W = 2;
30
    PF_R = 4;
31
 
32
 
33
TYPE
34
 
35
    Elf32_Ehdr = RECORD
36
 
37
        e_ident: ARRAY EI_NIDENT OF BYTE;
38
 
39
        e_type,
40
        e_machine: WCHAR;
41
 
42
        e_version,
43
        e_entry,
44
        e_phoff,
45
        e_shoff,
46
        e_flags: INTEGER;
47
 
48
        e_ehsize,
49
        e_phentsize,
50
        e_phnum,
51
        e_shentsize,
52
        e_shnum,
53
        e_shstrndx: WCHAR
54
 
55
    END;
56
 
57
 
58
    Elf32_Phdr = RECORD
59
 
60
        p_type,
61
        p_offset,
62
        p_vaddr,
63
        p_paddr,
64
        p_filesz,
65
        p_memsz,
66
        p_flags,
67
        p_align: INTEGER
68
 
69
    END;
70
 
7693 akron1 71
 
72
    Elf32_Dyn = POINTER TO RECORD (LISTS.ITEM)
73
 
74
        d_tag, d_val: INTEGER
75
 
76
    END;
77
 
78
 
79
    Elf32_Sym = POINTER TO RECORD (LISTS.ITEM)
80
 
81
        name, value, size: INTEGER;
82
        info, other: CHAR;
83
        shndx: WCHAR
84
 
85
    END;
86
 
87
 
88
VAR
89
 
90
    dynamic: LISTS.LIST;
91
    strtab:  CHL.BYTELIST;
92
    symtab:  LISTS.LIST;
93
 
94
    hashtab, bucket, chain: CHL.INTLIST;
95
 
96
 
8097 maxcodehac 97
PROCEDURE Write16 (w: WCHAR);
6613 leency 98
BEGIN
8097 maxcodehac 99
    WR.Write16LE(ORD(w))
7597 akron1 100
END Write16;
101
 
102
 
8097 maxcodehac 103
PROCEDURE WritePH (ph: Elf32_Phdr);
7597 akron1 104
BEGIN
8097 maxcodehac 105
    WR.Write32LE(ph.p_type);
106
    WR.Write32LE(ph.p_offset);
107
    WR.Write32LE(ph.p_vaddr);
108
    WR.Write32LE(ph.p_paddr);
109
    WR.Write32LE(ph.p_filesz);
110
    WR.Write32LE(ph.p_memsz);
111
    WR.Write32LE(ph.p_flags);
112
    WR.Write32LE(ph.p_align)
7597 akron1 113
END WritePH;
114
 
115
 
8097 maxcodehac 116
PROCEDURE WritePH64 (ph: Elf32_Phdr);
7597 akron1 117
BEGIN
8097 maxcodehac 118
    WR.Write32LE(ph.p_type);
119
    WR.Write32LE(ph.p_flags);
120
    WR.Write64LE(ph.p_offset);
121
    WR.Write64LE(ph.p_vaddr);
122
    WR.Write64LE(ph.p_paddr);
123
    WR.Write64LE(ph.p_filesz);
124
    WR.Write64LE(ph.p_memsz);
125
    WR.Write64LE(ph.p_align)
7597 akron1 126
END WritePH64;
127
 
128
 
7693 akron1 129
PROCEDURE NewDyn (tag, val: INTEGER);
130
VAR
131
    dyn: Elf32_Dyn;
132
 
133
BEGIN
134
    NEW(dyn);
135
    dyn.d_tag := tag;
136
    dyn.d_val := val;
137
    LISTS.push(dynamic, dyn)
138
END NewDyn;
139
 
140
 
141
PROCEDURE NewSym (name, value, size: INTEGER; info, other: CHAR; shndx: WCHAR);
142
VAR
143
    sym: Elf32_Sym;
144
 
145
BEGIN
146
    NEW(sym);
147
    sym.name := name;
148
    sym.value := value;
149
    sym.size := size;
150
    sym.info := info;
151
    sym.other := other;
152
    sym.shndx := shndx;
153
 
154
    LISTS.push(symtab, sym)
155
END NewSym;
156
 
157
 
158
PROCEDURE MakeHash (bucket, chain: CHL.INTLIST; symCount: INTEGER);
159
VAR
160
    symi, hi, k: INTEGER;
161
 
162
BEGIN
163
    FOR symi := 0 TO symCount - 1 DO
164
        CHL.SetInt(chain, symi, 0);
165
        hi := CHL.GetInt(hashtab, symi) MOD symCount;
166
        IF CHL.GetInt(bucket, hi) # 0 THEN
167
            k := symi;
168
            WHILE CHL.GetInt(chain, k) # 0 DO
169
                k := CHL.GetInt(chain, k)
170
            END;
171
            CHL.SetInt(chain, k, CHL.GetInt(bucket, hi))
172
        END;
173
        CHL.SetInt(bucket, hi, symi)
174
    END
175
END MakeHash;
176
 
177
 
178
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; fini: INTEGER; so, amd64: BOOLEAN);
7597 akron1 179
CONST
180
    interp  =  0;
181
    dyn     =  1;
182
    header  =  2;
183
    text    =  3;
184
    data    =  4;
185
    bss     =  5;
186
 
7693 akron1 187
    linuxInterpreter64 = "/lib64/ld-linux-x86-64.so.2";
188
    linuxInterpreter32 = "/lib/ld-linux.so.2";
189
 
190
    exeBaseAddress32 = 8048000H;
191
    exeBaseAddress64 = 400000H;
192
    dllBaseAddress = 0;
193
 
194
    DT_NULL = 0;
195
    DT_NEEDED = 1;
196
    DT_HASH = 4;
197
    DT_STRTAB = 5;
198
    DT_SYMTAB = 6;
199
    DT_RELA = 7;
200
    DT_RELASZ = 8;
201
    DT_RELAENT = 9;
202
    DT_STRSZ = 10;
203
    DT_SYMENT = 11;
204
    DT_INIT = 12;
205
    DT_FINI = 13;
206
    DT_SONAME = 14;
207
    DT_REL = 17;
208
    DT_RELSZ = 18;
209
    DT_RELENT = 19;
210
 
7597 akron1 211
VAR
212
    ehdr: Elf32_Ehdr;
213
    phdr: ARRAY 16 OF Elf32_Phdr;
214
 
8097 maxcodehac 215
    i, BaseAdr, DynAdr, offset, pad, VA, symCount: INTEGER;
7597 akron1 216
 
217
    SizeOf: RECORD header, code, data, bss: INTEGER END;
218
 
8097 maxcodehac 219
    Offset: RECORD symtab, reltab, hash, strtab: INTEGER END;
7693 akron1 220
 
221
    Interpreter: ARRAY 40 OF CHAR; lenInterpreter: INTEGER;
7597 akron1 222
 
7693 akron1 223
    item: LISTS.ITEM;
224
 
225
    Name: ARRAY 2048 OF CHAR;
226
 
8097 maxcodehac 227
    Address: PE32.VIRTUAL_ADDR;
228
 
7597 akron1 229
BEGIN
7693 akron1 230
    dynamic := LISTS.create(NIL);
231
    symtab  := LISTS.create(NIL);
232
    strtab  := CHL.CreateByteList();
233
 
7597 akron1 234
    IF amd64 THEN
7693 akron1 235
        BaseAdr := exeBaseAddress64;
236
        Interpreter := linuxInterpreter64
7597 akron1 237
    ELSE
7693 akron1 238
        BaseAdr := exeBaseAddress32;
239
        Interpreter := linuxInterpreter32
7597 akron1 240
    END;
241
 
7693 akron1 242
    IF so THEN
243
        BaseAdr := dllBaseAddress
7597 akron1 244
    END;
245
 
7693 akron1 246
    lenInterpreter := LENGTH(Interpreter) + 1;
247
 
7597 akron1 248
    SizeOf.code := CHL.Length(program.code);
249
    SizeOf.data := CHL.Length(program.data);
250
    SizeOf.bss  := program.bss;
251
 
252
    ehdr.e_ident[0] := 7FH;
253
    ehdr.e_ident[1] := ORD("E");
254
    ehdr.e_ident[2] := ORD("L");
255
    ehdr.e_ident[3] := ORD("F");
256
    IF amd64 THEN
257
        ehdr.e_ident[4] := ELFCLASS64
258
    ELSE
259
        ehdr.e_ident[4] := ELFCLASS32
260
    END;
261
    ehdr.e_ident[5] := ELFDATA2LSB;
262
    ehdr.e_ident[6] := 1;
263
    ehdr.e_ident[7] := 3;
264
    FOR i := 8 TO EI_NIDENT - 1 DO
265
        ehdr.e_ident[i] := 0
266
    END;
267
 
7693 akron1 268
    IF so THEN
269
        ehdr.e_type := WCHR(ET_DYN)
270
    ELSE
271
        ehdr.e_type := WCHR(ET_EXEC)
272
    END;
273
 
7597 akron1 274
    ehdr.e_version := 1;
275
    ehdr.e_shoff := 0;
276
    ehdr.e_flags := 0;
277
    ehdr.e_shnum := WCHR(0);
278
    ehdr.e_shstrndx := WCHR(0);
279
    ehdr.e_phnum := WCHR(6);
280
 
281
    IF amd64 THEN
282
        ehdr.e_machine := WCHR(EM_8664);
283
        ehdr.e_phoff := 40H;
284
        ehdr.e_ehsize := WCHR(40H);
285
        ehdr.e_phentsize := WCHR(38H);
286
        ehdr.e_shentsize := WCHR(40H)
287
    ELSE
288
        ehdr.e_machine := WCHR(EM_386);
289
        ehdr.e_phoff := 34H;
290
        ehdr.e_ehsize := WCHR(34H);
291
        ehdr.e_phentsize := WCHR(20H);
292
        ehdr.e_shentsize := WCHR(28H)
293
    END;
294
 
295
    SizeOf.header := ORD(ehdr.e_ehsize) + ORD(ehdr.e_phentsize) * ORD(ehdr.e_phnum);
296
 
297
    phdr[interp].p_type := 3;
298
    phdr[interp].p_offset := SizeOf.header;
7693 akron1 299
    phdr[interp].p_vaddr := BaseAdr + phdr[interp].p_offset;
300
    phdr[interp].p_paddr := phdr[interp].p_vaddr;
301
    phdr[interp].p_filesz := lenInterpreter;
302
    phdr[interp].p_memsz := lenInterpreter;
7597 akron1 303
    phdr[interp].p_flags := PF_R;
304
    phdr[interp].p_align := 1;
305
 
306
    phdr[dyn].p_type := 2;
307
    phdr[dyn].p_offset := phdr[interp].p_offset + phdr[interp].p_filesz;
7693 akron1 308
    phdr[dyn].p_vaddr := BaseAdr + phdr[dyn].p_offset;
309
    phdr[dyn].p_paddr := phdr[dyn].p_vaddr;
310
 
311
    hashtab := CHL.CreateIntList();
312
 
8859 leency 313
    CHL.PushInt(hashtab, STRINGS.HashStr(""));
7693 akron1 314
    NewSym(CHL.PushStr(strtab, ""), 0, 0, 0X, 0X, 0X);
8859 leency 315
    CHL.PushInt(hashtab, STRINGS.HashStr("dlopen"));
7693 akron1 316
    NewSym(CHL.PushStr(strtab, "dlopen"), 0, 0, 12X, 0X, 0X);
8859 leency 317
    CHL.PushInt(hashtab, STRINGS.HashStr("dlsym"));
7693 akron1 318
    NewSym(CHL.PushStr(strtab, "dlsym"), 0, 0, 12X, 0X, 0X);
319
 
320
    IF so THEN
321
        item := program.exp_list.first;
322
        WHILE item # NIL DO
323
            ASSERT(CHL.GetStr(program.export, item(BIN.EXPRT).nameoffs, Name));
8859 leency 324
            CHL.PushInt(hashtab, STRINGS.HashStr(Name));
7693 akron1 325
            NewSym(CHL.PushStr(strtab, Name), item(BIN.EXPRT).label, 0, 12X, 0X, 0X);
326
            item := item.next
327
        END;
328
        ASSERT(CHL.GetStr(program.data, program.modname, Name))
329
    END;
330
 
331
    symCount := LISTS.count(symtab);
332
 
8097 maxcodehac 333
    bucket := CHL.CreateIntList();
334
    chain  := CHL.CreateIntList();
7693 akron1 335
 
336
    FOR i := 1 TO symCount DO
337
        CHL.PushInt(bucket, 0);
338
        CHL.PushInt(chain, 0)
339
    END;
340
 
341
    MakeHash(bucket, chain, symCount);
342
 
343
    NewDyn(DT_NEEDED, CHL.PushStr(strtab, "libdl.so.2"));
344
    NewDyn(DT_STRTAB, 0);
345
    NewDyn(DT_STRSZ, CHL.Length(strtab));
346
    NewDyn(DT_SYMTAB, 0);
347
 
7597 akron1 348
    IF amd64 THEN
7693 akron1 349
        NewDyn(DT_SYMENT, 24);
350
        NewDyn(DT_RELA, 0);
351
        NewDyn(DT_RELASZ, 48);
352
        NewDyn(DT_RELAENT, 24)
7597 akron1 353
    ELSE
7693 akron1 354
        NewDyn(DT_SYMENT, 16);
355
        NewDyn(DT_REL, 0);
356
        NewDyn(DT_RELSZ, 16);
357
        NewDyn(DT_RELENT, 8)
7597 akron1 358
    END;
7693 akron1 359
 
360
    NewDyn(DT_HASH, 0);
361
 
362
    IF so THEN
363
        NewDyn(DT_SONAME, CHL.PushStr(strtab, Name));
364
        NewDyn(DT_INIT, 0);
365
        NewDyn(DT_FINI, 0)
366
    END;
367
 
368
    NewDyn(DT_NULL, 0);
369
 
370
    Offset.symtab := LISTS.count(dynamic) * (8 + 8 * ORD(amd64));
371
    Offset.reltab := Offset.symtab + symCount * (16 + 8 * ORD(amd64));
372
    Offset.hash   := Offset.reltab + (8 + 16 * ORD(amd64)) * 2;
373
    Offset.strtab := Offset.hash + (symCount * 2 + 2) * 4;
374
 
8097 maxcodehac 375
    DynAdr := phdr[dyn].p_offset + BaseAdr;
7693 akron1 376
 
8097 maxcodehac 377
    item := LISTS.getidx(dynamic, 1); item(Elf32_Dyn).d_val := Offset.strtab + DynAdr;
378
    item := LISTS.getidx(dynamic, 3); item(Elf32_Dyn).d_val := Offset.symtab + DynAdr;
379
    item := LISTS.getidx(dynamic, 5); item(Elf32_Dyn).d_val := Offset.reltab + DynAdr;
380
    item := LISTS.getidx(dynamic, 8); item(Elf32_Dyn).d_val := Offset.hash   + DynAdr;
7693 akron1 381
 
382
    phdr[dyn].p_filesz := Offset.strtab + CHL.Length(strtab) + 8 + 8 * ORD(amd64);
383
    phdr[dyn].p_memsz  := phdr[dyn].p_filesz;
384
 
7597 akron1 385
    phdr[dyn].p_flags := PF_R;
386
    phdr[dyn].p_align := 1;
387
 
388
    offset := 0;
389
 
390
    phdr[header].p_type := 1;
391
    phdr[header].p_offset := offset;
7693 akron1 392
    phdr[header].p_vaddr := BaseAdr;
393
    phdr[header].p_paddr := BaseAdr;
8097 maxcodehac 394
    phdr[header].p_filesz := SizeOf.header + lenInterpreter + phdr[dyn].p_filesz;
7693 akron1 395
    phdr[header].p_memsz  := phdr[header].p_filesz;
7597 akron1 396
    phdr[header].p_flags := PF_R + PF_W;
397
    phdr[header].p_align := 1000H;
7693 akron1 398
 
8097 maxcodehac 399
    INC(offset, phdr[header].p_filesz);
7693 akron1 400
    VA := BaseAdr + offset + 1000H;
7597 akron1 401
 
402
    phdr[text].p_type := 1;
403
    phdr[text].p_offset := offset;
404
    phdr[text].p_vaddr := VA;
405
    phdr[text].p_paddr := VA;
406
    phdr[text].p_filesz := SizeOf.code;
407
    phdr[text].p_memsz := SizeOf.code;
408
    phdr[text].p_flags := PF_X + PF_R;
409
    phdr[text].p_align := 1000H;
410
 
411
    ehdr.e_entry := phdr[text].p_vaddr;
7693 akron1 412
 
8097 maxcodehac 413
    INC(offset, phdr[text].p_filesz);
7693 akron1 414
    VA := BaseAdr + offset + 2000H;
7597 akron1 415
    pad := (16 - VA MOD 16) MOD 16;
416
 
417
    phdr[data].p_type := 1;
418
    phdr[data].p_offset := offset;
419
    phdr[data].p_vaddr := VA;
420
    phdr[data].p_paddr := VA;
421
    phdr[data].p_filesz := SizeOf.data + pad;
422
    phdr[data].p_memsz := SizeOf.data + pad;
423
    phdr[data].p_flags := PF_R + PF_W;
424
    phdr[data].p_align := 1000H;
7693 akron1 425
 
8097 maxcodehac 426
    INC(offset, phdr[data].p_filesz);
7693 akron1 427
    VA := BaseAdr + offset + 3000H;
7597 akron1 428
 
429
    phdr[bss].p_type := 1;
430
    phdr[bss].p_offset := offset;
431
    phdr[bss].p_vaddr := VA;
432
    phdr[bss].p_paddr := VA;
433
    phdr[bss].p_filesz := 0;
434
    phdr[bss].p_memsz := SizeOf.bss + 16;
435
    phdr[bss].p_flags := PF_R + PF_W;
436
    phdr[bss].p_align := 1000H;
437
 
8097 maxcodehac 438
    Address.Code   := ehdr.e_entry;
439
    Address.Data   := phdr[data].p_vaddr + pad;
440
    Address.Bss    := WR.align(phdr[bss].p_vaddr, 16);
441
    Address.Import := 0;
7597 akron1 442
 
8097 maxcodehac 443
    PE32.fixup(program, Address, amd64);
444
 
7693 akron1 445
    item := symtab.first;
446
    WHILE item # NIL DO
447
        IF item(Elf32_Sym).value # 0 THEN
448
            INC(item(Elf32_Sym).value, ehdr.e_entry)
449
        END;
450
        item := item.next
451
    END;
452
 
453
    IF so THEN
454
        item := LISTS.getidx(dynamic, 10); item(Elf32_Dyn).d_val := ehdr.e_entry;
455
        item := LISTS.getidx(dynamic, 11); item(Elf32_Dyn).d_val := BIN.GetLabel(program, fini) + ehdr.e_entry
456
    END;
457
 
8097 maxcodehac 458
    WR.Create(FileName);
7597 akron1 459
 
460
    FOR i := 0 TO EI_NIDENT - 1 DO
8097 maxcodehac 461
        WR.WriteByte(ehdr.e_ident[i])
7597 akron1 462
    END;
463
 
8097 maxcodehac 464
    Write16(ehdr.e_type);
465
    Write16(ehdr.e_machine);
7597 akron1 466
 
8097 maxcodehac 467
    WR.Write32LE(ehdr.e_version);
7597 akron1 468
    IF amd64 THEN
8097 maxcodehac 469
        WR.Write64LE(ehdr.e_entry);
470
        WR.Write64LE(ehdr.e_phoff);
471
        WR.Write64LE(ehdr.e_shoff)
7597 akron1 472
    ELSE
8097 maxcodehac 473
        WR.Write32LE(ehdr.e_entry);
474
        WR.Write32LE(ehdr.e_phoff);
475
        WR.Write32LE(ehdr.e_shoff)
7597 akron1 476
    END;
8097 maxcodehac 477
    WR.Write32LE(ehdr.e_flags);
7597 akron1 478
 
8097 maxcodehac 479
    Write16(ehdr.e_ehsize);
480
    Write16(ehdr.e_phentsize);
481
    Write16(ehdr.e_phnum);
482
    Write16(ehdr.e_shentsize);
483
    Write16(ehdr.e_shnum);
484
    Write16(ehdr.e_shstrndx);
7597 akron1 485
 
486
    IF amd64 THEN
8097 maxcodehac 487
        WritePH64(phdr[interp]);
488
        WritePH64(phdr[dyn]);
489
        WritePH64(phdr[header]);
490
        WritePH64(phdr[text]);
491
        WritePH64(phdr[data]);
492
        WritePH64(phdr[bss])
7597 akron1 493
    ELSE
8097 maxcodehac 494
        WritePH(phdr[interp]);
495
        WritePH(phdr[dyn]);
496
        WritePH(phdr[header]);
497
        WritePH(phdr[text]);
498
        WritePH(phdr[data]);
499
        WritePH(phdr[bss])
7597 akron1 500
    END;
501
 
7693 akron1 502
    FOR i := 0 TO lenInterpreter - 1 DO
8097 maxcodehac 503
        WR.WriteByte(ORD(Interpreter[i]))
7597 akron1 504
    END;
505
 
506
    IF amd64 THEN
7693 akron1 507
        item := dynamic.first;
508
        WHILE item # NIL DO
8097 maxcodehac 509
            WR.Write64LE(item(Elf32_Dyn).d_tag);
510
            WR.Write64LE(item(Elf32_Dyn).d_val);
7693 akron1 511
            item := item.next
512
        END;
513
 
514
        item := symtab.first;
515
        WHILE item # NIL DO
8097 maxcodehac 516
            WR.Write32LE(item(Elf32_Sym).name);
517
            WR.WriteByte(ORD(item(Elf32_Sym).info));
518
            WR.WriteByte(ORD(item(Elf32_Sym).other));
519
            Write16(item(Elf32_Sym).shndx);
520
            WR.Write64LE(item(Elf32_Sym).value);
521
            WR.Write64LE(item(Elf32_Sym).size);
7693 akron1 522
            item := item.next
523
        END;
524
 
8097 maxcodehac 525
        WR.Write64LE(phdr[dyn].p_filesz + DynAdr - 16);
526
        WR.Write32LE(1);
527
        WR.Write32LE(1);
528
        WR.Write64LE(0);
529
        WR.Write64LE(phdr[dyn].p_filesz + DynAdr - 8);
530
        WR.Write32LE(1);
531
        WR.Write32LE(2);
532
        WR.Write64LE(0)
7693 akron1 533
 
7597 akron1 534
    ELSE
7693 akron1 535
        item := dynamic.first;
536
        WHILE item # NIL DO
8097 maxcodehac 537
            WR.Write32LE(item(Elf32_Dyn).d_tag);
538
            WR.Write32LE(item(Elf32_Dyn).d_val);
7693 akron1 539
            item := item.next
540
        END;
541
 
542
        item := symtab.first;
543
        WHILE item # NIL DO
8097 maxcodehac 544
            WR.Write32LE(item(Elf32_Sym).name);
545
            WR.Write32LE(item(Elf32_Sym).value);
546
            WR.Write32LE(item(Elf32_Sym).size);
547
            WR.WriteByte(ORD(item(Elf32_Sym).info));
548
            WR.WriteByte(ORD(item(Elf32_Sym).other));
549
            Write16(item(Elf32_Sym).shndx);
7693 akron1 550
            item := item.next
551
        END;
552
 
8097 maxcodehac 553
        WR.Write32LE(phdr[dyn].p_filesz + DynAdr - 8);
554
        WR.Write32LE(00000101H);
555
        WR.Write32LE(phdr[dyn].p_filesz + DynAdr - 4);
556
        WR.Write32LE(00000201H)
7693 akron1 557
 
8097 maxcodehac 558
    END;
8859 leency 559
 
8097 maxcodehac 560
    WR.Write32LE(symCount);
561
    WR.Write32LE(symCount);
7693 akron1 562
 
8097 maxcodehac 563
    FOR i := 0 TO symCount - 1 DO
564
        WR.Write32LE(CHL.GetInt(bucket, i))
565
    END;
7693 akron1 566
 
8097 maxcodehac 567
    FOR i := 0 TO symCount - 1 DO
568
        WR.Write32LE(CHL.GetInt(chain, i))
569
    END;
7693 akron1 570
 
8097 maxcodehac 571
    CHL.WriteToFile(strtab);
8859 leency 572
 
8097 maxcodehac 573
    IF amd64 THEN
574
        WR.Write64LE(0);
575
        WR.Write64LE(0)
576
    ELSE
577
        WR.Write32LE(0);
8859 leency 578
        WR.Write32LE(0)
579
    END;
7693 akron1 580
 
8097 maxcodehac 581
    CHL.WriteToFile(program.code);
7597 akron1 582
    WHILE pad > 0 DO
8097 maxcodehac 583
        WR.WriteByte(0);
7597 akron1 584
        DEC(pad)
585
    END;
8097 maxcodehac 586
    CHL.WriteToFile(program.data);
587
    WR.Close;
588
    UTILS.chmod(FileName)
7597 akron1 589
END write;
590
 
591
 
7983 leency 592
END ELF.