(* BSD 2-Clause License Copyright (c) 2019, Anton Krotov All rights reserved. *) MODULE ELF; IMPORT BIN, WR := WRITER, CHL := CHUNKLISTS; CONST EI_NIDENT = 16; ET_EXEC = 2; ET_DYN = 3; EM_386 = 3; EM_8664 = 3EH; ELFCLASS32 = 1; ELFCLASS64 = 2; ELFDATA2LSB = 1; ELFDATA2MSB = 2; PF_X = 1; PF_W = 2; PF_R = 4; TYPE Elf32_Ehdr = RECORD e_ident: ARRAY EI_NIDENT OF BYTE; e_type, e_machine: WCHAR; e_version, e_entry, e_phoff, e_shoff, e_flags: INTEGER; e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum, e_shstrndx: WCHAR END; Elf32_Phdr = RECORD p_type, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, p_flags, p_align: INTEGER END; FILE = WR.FILE; PROCEDURE align (n, _align: INTEGER): INTEGER; BEGIN IF n MOD _align # 0 THEN n := n + _align - (n MOD _align) END RETURN n END align; PROCEDURE Write16 (file: FILE; w: WCHAR); BEGIN WR.Write16LE(file, ORD(w)) END Write16; PROCEDURE WritePH (file: FILE; ph: Elf32_Phdr); BEGIN WR.Write32LE(file, ph.p_type); WR.Write32LE(file, ph.p_offset); WR.Write32LE(file, ph.p_vaddr); WR.Write32LE(file, ph.p_paddr); WR.Write32LE(file, ph.p_filesz); WR.Write32LE(file, ph.p_memsz); WR.Write32LE(file, ph.p_flags); WR.Write32LE(file, ph.p_align) END WritePH; PROCEDURE WritePH64 (file: FILE; ph: Elf32_Phdr); BEGIN WR.Write32LE(file, ph.p_type); WR.Write32LE(file, ph.p_flags); WR.Write64LE(file, ph.p_offset); WR.Write64LE(file, ph.p_vaddr); WR.Write64LE(file, ph.p_paddr); WR.Write64LE(file, ph.p_filesz); WR.Write64LE(file, ph.p_memsz); WR.Write64LE(file, ph.p_align) END WritePH64; PROCEDURE fixup (program: BIN.PROGRAM; text, data, bss: INTEGER; amd64: BOOLEAN); VAR reloc: BIN.RELOC; L, delta: INTEGER; BEGIN reloc := program.rel_list.first(BIN.RELOC); WHILE reloc # NIL DO L := BIN.get32le(program.code, reloc.offset); delta := 3 - reloc.offset - text - 7 * ORD(amd64); CASE reloc.opcode OF |BIN.PICDATA: BIN.put32le(program.code, reloc.offset, L + data + delta) |BIN.PICCODE: BIN.put32le(program.code, reloc.offset, BIN.GetLabel(program, L) + text + delta) |BIN.PICBSS: BIN.put32le(program.code, reloc.offset, L + bss + delta) END; reloc := reloc.next(BIN.RELOC) END; END fixup; PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; amd64: BOOLEAN); CONST interp = 0; dyn = 1; header = 2; text = 3; data = 4; bss = 5; VAR ehdr: Elf32_Ehdr; phdr: ARRAY 16 OF Elf32_Phdr; i, LoadAdr, offset, pad, VA: INTEGER; SizeOf: RECORD header, code, data, bss: INTEGER END; File: FILE; str: ARRAY 40 OF CHAR; lstr: INTEGER; Dyn: ARRAY 350 OF BYTE; BEGIN IF amd64 THEN str := "/lib64/ld-linux-x86-64.so.2" ELSE str := "/lib/ld-linux.so.2" END; lstr := LENGTH(str); IF amd64 THEN LoadAdr := 400000H ELSE LoadAdr := 08048000H END; SizeOf.code := CHL.Length(program.code); SizeOf.data := CHL.Length(program.data); SizeOf.bss := program.bss; ehdr.e_ident[0] := 7FH; ehdr.e_ident[1] := ORD("E"); ehdr.e_ident[2] := ORD("L"); ehdr.e_ident[3] := ORD("F"); IF amd64 THEN ehdr.e_ident[4] := ELFCLASS64 ELSE ehdr.e_ident[4] := ELFCLASS32 END; ehdr.e_ident[5] := ELFDATA2LSB; ehdr.e_ident[6] := 1; ehdr.e_ident[7] := 3; FOR i := 8 TO EI_NIDENT - 1 DO ehdr.e_ident[i] := 0 END; ehdr.e_type := WCHR(ET_EXEC); ehdr.e_version := 1; ehdr.e_shoff := 0; ehdr.e_flags := 0; ehdr.e_shnum := WCHR(0); ehdr.e_shstrndx := WCHR(0); ehdr.e_phnum := WCHR(6); IF amd64 THEN ehdr.e_machine := WCHR(EM_8664); ehdr.e_phoff := 40H; ehdr.e_ehsize := WCHR(40H); ehdr.e_phentsize := WCHR(38H); ehdr.e_shentsize := WCHR(40H) ELSE ehdr.e_machine := WCHR(EM_386); ehdr.e_phoff := 34H; ehdr.e_ehsize := WCHR(34H); ehdr.e_phentsize := WCHR(20H); ehdr.e_shentsize := WCHR(28H) END; SizeOf.header := ORD(ehdr.e_ehsize) + ORD(ehdr.e_phentsize) * ORD(ehdr.e_phnum); phdr[interp].p_type := 3; phdr[interp].p_offset := SizeOf.header; phdr[interp].p_vaddr := LoadAdr + phdr[interp].p_offset; phdr[interp].p_paddr := LoadAdr + phdr[interp].p_offset; phdr[interp].p_filesz := lstr + 1; phdr[interp].p_memsz := lstr + 1; phdr[interp].p_flags := PF_R; phdr[interp].p_align := 1; phdr[dyn].p_type := 2; phdr[dyn].p_offset := phdr[interp].p_offset + phdr[interp].p_filesz; phdr[dyn].p_vaddr := LoadAdr + phdr[dyn].p_offset; phdr[dyn].p_paddr := LoadAdr + phdr[dyn].p_offset; IF amd64 THEN phdr[dyn].p_filesz := 0A0H; phdr[dyn].p_memsz := 0A0H ELSE phdr[dyn].p_filesz := 50H; phdr[dyn].p_memsz := 50H END; phdr[dyn].p_flags := PF_R; phdr[dyn].p_align := 1; offset := 0; phdr[header].p_type := 1; phdr[header].p_offset := offset; phdr[header].p_vaddr := LoadAdr; phdr[header].p_paddr := LoadAdr; IF amd64 THEN phdr[header].p_filesz := 305H; phdr[header].p_memsz := 305H ELSE phdr[header].p_filesz := 1D0H; phdr[header].p_memsz := 1D0H END; phdr[header].p_flags := PF_R + PF_W; phdr[header].p_align := 1000H; offset := offset + phdr[header].p_filesz; VA := LoadAdr + offset + 1000H; phdr[text].p_type := 1; phdr[text].p_offset := offset; phdr[text].p_vaddr := VA; phdr[text].p_paddr := VA; phdr[text].p_filesz := SizeOf.code; phdr[text].p_memsz := SizeOf.code; phdr[text].p_flags := PF_X + PF_R; phdr[text].p_align := 1000H; ehdr.e_entry := phdr[text].p_vaddr; offset := offset + phdr[text].p_filesz; VA := LoadAdr + offset + 2000H; pad := (16 - VA MOD 16) MOD 16; phdr[data].p_type := 1; phdr[data].p_offset := offset; phdr[data].p_vaddr := VA; phdr[data].p_paddr := VA; phdr[data].p_filesz := SizeOf.data + pad; phdr[data].p_memsz := SizeOf.data + pad; phdr[data].p_flags := PF_R + PF_W; phdr[data].p_align := 1000H; offset := offset + phdr[data].p_filesz; VA := LoadAdr + offset + 3000H; phdr[bss].p_type := 1; phdr[bss].p_offset := offset; phdr[bss].p_vaddr := VA; phdr[bss].p_paddr := VA; phdr[bss].p_filesz := 0; phdr[bss].p_memsz := SizeOf.bss + 16; phdr[bss].p_flags := PF_R + PF_W; phdr[bss].p_align := 1000H; fixup(program, phdr[text].p_vaddr, phdr[data].p_vaddr + pad, align(phdr[bss].p_vaddr, 16), amd64); File := WR.Create(FileName); FOR i := 0 TO EI_NIDENT - 1 DO WR.WriteByte(File, ehdr.e_ident[i]) END; Write16(File, ehdr.e_type); Write16(File, ehdr.e_machine); WR.Write32LE(File, ehdr.e_version); IF amd64 THEN WR.Write64LE(File, ehdr.e_entry); WR.Write64LE(File, ehdr.e_phoff); WR.Write64LE(File, ehdr.e_shoff) ELSE WR.Write32LE(File, ehdr.e_entry); WR.Write32LE(File, ehdr.e_phoff); WR.Write32LE(File, ehdr.e_shoff) END; WR.Write32LE(File, ehdr.e_flags); Write16(File, ehdr.e_ehsize); Write16(File, ehdr.e_phentsize); Write16(File, ehdr.e_phnum); Write16(File, ehdr.e_shentsize); Write16(File, ehdr.e_shnum); Write16(File, ehdr.e_shstrndx); IF amd64 THEN WritePH64(File, phdr[interp]); WritePH64(File, phdr[dyn]); WritePH64(File, phdr[header]); WritePH64(File, phdr[text]); WritePH64(File, phdr[data]); WritePH64(File, phdr[bss]) ELSE WritePH(File, phdr[interp]); WritePH(File, phdr[dyn]); WritePH(File, phdr[header]); WritePH(File, phdr[text]); WritePH(File, phdr[data]); WritePH(File, phdr[bss]) END; FOR i := 0 TO lstr DO WR.WriteByte(File, ORD(str[i])) END; i := 0; IF amd64 THEN BIN.InitArray(Dyn, i, "01000000000000000E000000000000000500000000000000DC02400000000000"); BIN.InitArray(Dyn, i, "0A00000000000000190000000000000006000000000000004C02400000000000"); BIN.InitArray(Dyn, i, "0B00000000000000180000000000000007000000000000009402400000000000"); BIN.InitArray(Dyn, i, "0800000000000000300000000000000009000000000000001800000000000000"); BIN.InitArray(Dyn, i, "0400000000000000C40240000000000000000000000000000000000000000000"); BIN.InitArray(Dyn, i, "0000000000000000000000000000000000000000000000000100000012000000"); BIN.InitArray(Dyn, i, "0000000000000000000000000000000008000000120000000000000000000000"); BIN.InitArray(Dyn, i, "0000000000000000F50240000000000001000000010000000000000000000000"); BIN.InitArray(Dyn, i, "FD02400000000000010000000200000000000000000000000100000003000000"); BIN.InitArray(Dyn, i, "0000000001000000020000000000000000646C6F70656E00646C73796D006C69"); BIN.InitArray(Dyn, i, "62646C2E736F2E320000000000000000000000000000000000") ELSE BIN.InitArray(Dyn, i, "010000000E00000005000000AF8104080A000000190000000600000057810408"); BIN.InitArray(Dyn, i, "0B00000010000000110000008781040812000000100000001300000008000000"); BIN.InitArray(Dyn, i, "0400000097810408000000000000000000000000000000000000000000000000"); BIN.InitArray(Dyn, i, "0100000000000000000000001200000008000000000000000000000012000000"); BIN.InitArray(Dyn, i, "C881040801010000CC8104080102000001000000030000000000000001000000"); BIN.InitArray(Dyn, i, "020000000000000000646C6F70656E00646C73796D006C6962646C2E736F2E32"); BIN.InitArray(Dyn, i, "000000000000000000") END; WR.Write(File, Dyn, i); CHL.WriteToFile(File, program.code); WHILE pad > 0 DO WR.WriteByte(File, 0); DEC(pad) END; CHL.WriteToFile(File, program.data); WR.Close(File) END write; END ELF.