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