Subversion Repositories Kolibri OS

Rev

Rev 7983 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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