forked from KolibriOS/kolibrios
498da3221e
git-svn-id: svn://kolibrios.org@8859 a494cfbc-eb01-0410-851d-a64ba20cac60
592 lines
15 KiB
Plaintext
592 lines
15 KiB
Plaintext
(*
|
|
BSD 2-Clause License
|
|
|
|
Copyright (c) 2019-2021, Anton Krotov
|
|
All rights reserved.
|
|
*)
|
|
|
|
MODULE ELF;
|
|
|
|
IMPORT BIN, WR := WRITER, CHL := CHUNKLISTS, LISTS, PE32, UTILS, STRINGS;
|
|
|
|
|
|
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;
|
|
|
|
|
|
Elf32_Dyn = POINTER TO RECORD (LISTS.ITEM)
|
|
|
|
d_tag, d_val: INTEGER
|
|
|
|
END;
|
|
|
|
|
|
Elf32_Sym = POINTER TO RECORD (LISTS.ITEM)
|
|
|
|
name, value, size: INTEGER;
|
|
info, other: CHAR;
|
|
shndx: WCHAR
|
|
|
|
END;
|
|
|
|
|
|
VAR
|
|
|
|
dynamic: LISTS.LIST;
|
|
strtab: CHL.BYTELIST;
|
|
symtab: LISTS.LIST;
|
|
|
|
hashtab, bucket, chain: CHL.INTLIST;
|
|
|
|
|
|
PROCEDURE Write16 (w: WCHAR);
|
|
BEGIN
|
|
WR.Write16LE(ORD(w))
|
|
END Write16;
|
|
|
|
|
|
PROCEDURE WritePH (ph: Elf32_Phdr);
|
|
BEGIN
|
|
WR.Write32LE(ph.p_type);
|
|
WR.Write32LE(ph.p_offset);
|
|
WR.Write32LE(ph.p_vaddr);
|
|
WR.Write32LE(ph.p_paddr);
|
|
WR.Write32LE(ph.p_filesz);
|
|
WR.Write32LE(ph.p_memsz);
|
|
WR.Write32LE(ph.p_flags);
|
|
WR.Write32LE(ph.p_align)
|
|
END WritePH;
|
|
|
|
|
|
PROCEDURE WritePH64 (ph: Elf32_Phdr);
|
|
BEGIN
|
|
WR.Write32LE(ph.p_type);
|
|
WR.Write32LE(ph.p_flags);
|
|
WR.Write64LE(ph.p_offset);
|
|
WR.Write64LE(ph.p_vaddr);
|
|
WR.Write64LE(ph.p_paddr);
|
|
WR.Write64LE(ph.p_filesz);
|
|
WR.Write64LE(ph.p_memsz);
|
|
WR.Write64LE(ph.p_align)
|
|
END WritePH64;
|
|
|
|
|
|
PROCEDURE NewDyn (tag, val: INTEGER);
|
|
VAR
|
|
dyn: Elf32_Dyn;
|
|
|
|
BEGIN
|
|
NEW(dyn);
|
|
dyn.d_tag := tag;
|
|
dyn.d_val := val;
|
|
LISTS.push(dynamic, dyn)
|
|
END NewDyn;
|
|
|
|
|
|
PROCEDURE NewSym (name, value, size: INTEGER; info, other: CHAR; shndx: WCHAR);
|
|
VAR
|
|
sym: Elf32_Sym;
|
|
|
|
BEGIN
|
|
NEW(sym);
|
|
sym.name := name;
|
|
sym.value := value;
|
|
sym.size := size;
|
|
sym.info := info;
|
|
sym.other := other;
|
|
sym.shndx := shndx;
|
|
|
|
LISTS.push(symtab, sym)
|
|
END NewSym;
|
|
|
|
|
|
PROCEDURE MakeHash (bucket, chain: CHL.INTLIST; symCount: INTEGER);
|
|
VAR
|
|
symi, hi, k: INTEGER;
|
|
|
|
BEGIN
|
|
FOR symi := 0 TO symCount - 1 DO
|
|
CHL.SetInt(chain, symi, 0);
|
|
hi := CHL.GetInt(hashtab, symi) MOD symCount;
|
|
IF CHL.GetInt(bucket, hi) # 0 THEN
|
|
k := symi;
|
|
WHILE CHL.GetInt(chain, k) # 0 DO
|
|
k := CHL.GetInt(chain, k)
|
|
END;
|
|
CHL.SetInt(chain, k, CHL.GetInt(bucket, hi))
|
|
END;
|
|
CHL.SetInt(bucket, hi, symi)
|
|
END
|
|
END MakeHash;
|
|
|
|
|
|
PROCEDURE write* (program: BIN.PROGRAM; FileName: ARRAY OF CHAR; fini: INTEGER; so, amd64: BOOLEAN);
|
|
CONST
|
|
interp = 0;
|
|
dyn = 1;
|
|
header = 2;
|
|
text = 3;
|
|
data = 4;
|
|
bss = 5;
|
|
|
|
linuxInterpreter64 = "/lib64/ld-linux-x86-64.so.2";
|
|
linuxInterpreter32 = "/lib/ld-linux.so.2";
|
|
|
|
exeBaseAddress32 = 8048000H;
|
|
exeBaseAddress64 = 400000H;
|
|
dllBaseAddress = 0;
|
|
|
|
DT_NULL = 0;
|
|
DT_NEEDED = 1;
|
|
DT_HASH = 4;
|
|
DT_STRTAB = 5;
|
|
DT_SYMTAB = 6;
|
|
DT_RELA = 7;
|
|
DT_RELASZ = 8;
|
|
DT_RELAENT = 9;
|
|
DT_STRSZ = 10;
|
|
DT_SYMENT = 11;
|
|
DT_INIT = 12;
|
|
DT_FINI = 13;
|
|
DT_SONAME = 14;
|
|
DT_REL = 17;
|
|
DT_RELSZ = 18;
|
|
DT_RELENT = 19;
|
|
|
|
VAR
|
|
ehdr: Elf32_Ehdr;
|
|
phdr: ARRAY 16 OF Elf32_Phdr;
|
|
|
|
i, BaseAdr, DynAdr, offset, pad, VA, symCount: INTEGER;
|
|
|
|
SizeOf: RECORD header, code, data, bss: INTEGER END;
|
|
|
|
Offset: RECORD symtab, reltab, hash, strtab: INTEGER END;
|
|
|
|
Interpreter: ARRAY 40 OF CHAR; lenInterpreter: INTEGER;
|
|
|
|
item: LISTS.ITEM;
|
|
|
|
Name: ARRAY 2048 OF CHAR;
|
|
|
|
Address: PE32.VIRTUAL_ADDR;
|
|
|
|
BEGIN
|
|
dynamic := LISTS.create(NIL);
|
|
symtab := LISTS.create(NIL);
|
|
strtab := CHL.CreateByteList();
|
|
|
|
IF amd64 THEN
|
|
BaseAdr := exeBaseAddress64;
|
|
Interpreter := linuxInterpreter64
|
|
ELSE
|
|
BaseAdr := exeBaseAddress32;
|
|
Interpreter := linuxInterpreter32
|
|
END;
|
|
|
|
IF so THEN
|
|
BaseAdr := dllBaseAddress
|
|
END;
|
|
|
|
lenInterpreter := LENGTH(Interpreter) + 1;
|
|
|
|
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;
|
|
|
|
IF so THEN
|
|
ehdr.e_type := WCHR(ET_DYN)
|
|
ELSE
|
|
ehdr.e_type := WCHR(ET_EXEC)
|
|
END;
|
|
|
|
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 := BaseAdr + phdr[interp].p_offset;
|
|
phdr[interp].p_paddr := phdr[interp].p_vaddr;
|
|
phdr[interp].p_filesz := lenInterpreter;
|
|
phdr[interp].p_memsz := lenInterpreter;
|
|
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 := BaseAdr + phdr[dyn].p_offset;
|
|
phdr[dyn].p_paddr := phdr[dyn].p_vaddr;
|
|
|
|
hashtab := CHL.CreateIntList();
|
|
|
|
CHL.PushInt(hashtab, STRINGS.HashStr(""));
|
|
NewSym(CHL.PushStr(strtab, ""), 0, 0, 0X, 0X, 0X);
|
|
CHL.PushInt(hashtab, STRINGS.HashStr("dlopen"));
|
|
NewSym(CHL.PushStr(strtab, "dlopen"), 0, 0, 12X, 0X, 0X);
|
|
CHL.PushInt(hashtab, STRINGS.HashStr("dlsym"));
|
|
NewSym(CHL.PushStr(strtab, "dlsym"), 0, 0, 12X, 0X, 0X);
|
|
|
|
IF so THEN
|
|
item := program.exp_list.first;
|
|
WHILE item # NIL DO
|
|
ASSERT(CHL.GetStr(program.export, item(BIN.EXPRT).nameoffs, Name));
|
|
CHL.PushInt(hashtab, STRINGS.HashStr(Name));
|
|
NewSym(CHL.PushStr(strtab, Name), item(BIN.EXPRT).label, 0, 12X, 0X, 0X);
|
|
item := item.next
|
|
END;
|
|
ASSERT(CHL.GetStr(program.data, program.modname, Name))
|
|
END;
|
|
|
|
symCount := LISTS.count(symtab);
|
|
|
|
bucket := CHL.CreateIntList();
|
|
chain := CHL.CreateIntList();
|
|
|
|
FOR i := 1 TO symCount DO
|
|
CHL.PushInt(bucket, 0);
|
|
CHL.PushInt(chain, 0)
|
|
END;
|
|
|
|
MakeHash(bucket, chain, symCount);
|
|
|
|
NewDyn(DT_NEEDED, CHL.PushStr(strtab, "libdl.so.2"));
|
|
NewDyn(DT_STRTAB, 0);
|
|
NewDyn(DT_STRSZ, CHL.Length(strtab));
|
|
NewDyn(DT_SYMTAB, 0);
|
|
|
|
IF amd64 THEN
|
|
NewDyn(DT_SYMENT, 24);
|
|
NewDyn(DT_RELA, 0);
|
|
NewDyn(DT_RELASZ, 48);
|
|
NewDyn(DT_RELAENT, 24)
|
|
ELSE
|
|
NewDyn(DT_SYMENT, 16);
|
|
NewDyn(DT_REL, 0);
|
|
NewDyn(DT_RELSZ, 16);
|
|
NewDyn(DT_RELENT, 8)
|
|
END;
|
|
|
|
NewDyn(DT_HASH, 0);
|
|
|
|
IF so THEN
|
|
NewDyn(DT_SONAME, CHL.PushStr(strtab, Name));
|
|
NewDyn(DT_INIT, 0);
|
|
NewDyn(DT_FINI, 0)
|
|
END;
|
|
|
|
NewDyn(DT_NULL, 0);
|
|
|
|
Offset.symtab := LISTS.count(dynamic) * (8 + 8 * ORD(amd64));
|
|
Offset.reltab := Offset.symtab + symCount * (16 + 8 * ORD(amd64));
|
|
Offset.hash := Offset.reltab + (8 + 16 * ORD(amd64)) * 2;
|
|
Offset.strtab := Offset.hash + (symCount * 2 + 2) * 4;
|
|
|
|
DynAdr := phdr[dyn].p_offset + BaseAdr;
|
|
|
|
item := LISTS.getidx(dynamic, 1); item(Elf32_Dyn).d_val := Offset.strtab + DynAdr;
|
|
item := LISTS.getidx(dynamic, 3); item(Elf32_Dyn).d_val := Offset.symtab + DynAdr;
|
|
item := LISTS.getidx(dynamic, 5); item(Elf32_Dyn).d_val := Offset.reltab + DynAdr;
|
|
item := LISTS.getidx(dynamic, 8); item(Elf32_Dyn).d_val := Offset.hash + DynAdr;
|
|
|
|
phdr[dyn].p_filesz := Offset.strtab + CHL.Length(strtab) + 8 + 8 * ORD(amd64);
|
|
phdr[dyn].p_memsz := phdr[dyn].p_filesz;
|
|
|
|
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 := BaseAdr;
|
|
phdr[header].p_paddr := BaseAdr;
|
|
phdr[header].p_filesz := SizeOf.header + lenInterpreter + phdr[dyn].p_filesz;
|
|
phdr[header].p_memsz := phdr[header].p_filesz;
|
|
phdr[header].p_flags := PF_R + PF_W;
|
|
phdr[header].p_align := 1000H;
|
|
|
|
INC(offset, phdr[header].p_filesz);
|
|
VA := BaseAdr + 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;
|
|
|
|
INC(offset, phdr[text].p_filesz);
|
|
VA := BaseAdr + 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;
|
|
|
|
INC(offset, phdr[data].p_filesz);
|
|
VA := BaseAdr + 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;
|
|
|
|
Address.Code := ehdr.e_entry;
|
|
Address.Data := phdr[data].p_vaddr + pad;
|
|
Address.Bss := WR.align(phdr[bss].p_vaddr, 16);
|
|
Address.Import := 0;
|
|
|
|
PE32.fixup(program, Address, amd64);
|
|
|
|
item := symtab.first;
|
|
WHILE item # NIL DO
|
|
IF item(Elf32_Sym).value # 0 THEN
|
|
INC(item(Elf32_Sym).value, ehdr.e_entry)
|
|
END;
|
|
item := item.next
|
|
END;
|
|
|
|
IF so THEN
|
|
item := LISTS.getidx(dynamic, 10); item(Elf32_Dyn).d_val := ehdr.e_entry;
|
|
item := LISTS.getidx(dynamic, 11); item(Elf32_Dyn).d_val := BIN.GetLabel(program, fini) + ehdr.e_entry
|
|
END;
|
|
|
|
WR.Create(FileName);
|
|
|
|
FOR i := 0 TO EI_NIDENT - 1 DO
|
|
WR.WriteByte(ehdr.e_ident[i])
|
|
END;
|
|
|
|
Write16(ehdr.e_type);
|
|
Write16(ehdr.e_machine);
|
|
|
|
WR.Write32LE(ehdr.e_version);
|
|
IF amd64 THEN
|
|
WR.Write64LE(ehdr.e_entry);
|
|
WR.Write64LE(ehdr.e_phoff);
|
|
WR.Write64LE(ehdr.e_shoff)
|
|
ELSE
|
|
WR.Write32LE(ehdr.e_entry);
|
|
WR.Write32LE(ehdr.e_phoff);
|
|
WR.Write32LE(ehdr.e_shoff)
|
|
END;
|
|
WR.Write32LE(ehdr.e_flags);
|
|
|
|
Write16(ehdr.e_ehsize);
|
|
Write16(ehdr.e_phentsize);
|
|
Write16(ehdr.e_phnum);
|
|
Write16(ehdr.e_shentsize);
|
|
Write16(ehdr.e_shnum);
|
|
Write16(ehdr.e_shstrndx);
|
|
|
|
IF amd64 THEN
|
|
WritePH64(phdr[interp]);
|
|
WritePH64(phdr[dyn]);
|
|
WritePH64(phdr[header]);
|
|
WritePH64(phdr[text]);
|
|
WritePH64(phdr[data]);
|
|
WritePH64(phdr[bss])
|
|
ELSE
|
|
WritePH(phdr[interp]);
|
|
WritePH(phdr[dyn]);
|
|
WritePH(phdr[header]);
|
|
WritePH(phdr[text]);
|
|
WritePH(phdr[data]);
|
|
WritePH(phdr[bss])
|
|
END;
|
|
|
|
FOR i := 0 TO lenInterpreter - 1 DO
|
|
WR.WriteByte(ORD(Interpreter[i]))
|
|
END;
|
|
|
|
IF amd64 THEN
|
|
item := dynamic.first;
|
|
WHILE item # NIL DO
|
|
WR.Write64LE(item(Elf32_Dyn).d_tag);
|
|
WR.Write64LE(item(Elf32_Dyn).d_val);
|
|
item := item.next
|
|
END;
|
|
|
|
item := symtab.first;
|
|
WHILE item # NIL DO
|
|
WR.Write32LE(item(Elf32_Sym).name);
|
|
WR.WriteByte(ORD(item(Elf32_Sym).info));
|
|
WR.WriteByte(ORD(item(Elf32_Sym).other));
|
|
Write16(item(Elf32_Sym).shndx);
|
|
WR.Write64LE(item(Elf32_Sym).value);
|
|
WR.Write64LE(item(Elf32_Sym).size);
|
|
item := item.next
|
|
END;
|
|
|
|
WR.Write64LE(phdr[dyn].p_filesz + DynAdr - 16);
|
|
WR.Write32LE(1);
|
|
WR.Write32LE(1);
|
|
WR.Write64LE(0);
|
|
WR.Write64LE(phdr[dyn].p_filesz + DynAdr - 8);
|
|
WR.Write32LE(1);
|
|
WR.Write32LE(2);
|
|
WR.Write64LE(0)
|
|
|
|
ELSE
|
|
item := dynamic.first;
|
|
WHILE item # NIL DO
|
|
WR.Write32LE(item(Elf32_Dyn).d_tag);
|
|
WR.Write32LE(item(Elf32_Dyn).d_val);
|
|
item := item.next
|
|
END;
|
|
|
|
item := symtab.first;
|
|
WHILE item # NIL DO
|
|
WR.Write32LE(item(Elf32_Sym).name);
|
|
WR.Write32LE(item(Elf32_Sym).value);
|
|
WR.Write32LE(item(Elf32_Sym).size);
|
|
WR.WriteByte(ORD(item(Elf32_Sym).info));
|
|
WR.WriteByte(ORD(item(Elf32_Sym).other));
|
|
Write16(item(Elf32_Sym).shndx);
|
|
item := item.next
|
|
END;
|
|
|
|
WR.Write32LE(phdr[dyn].p_filesz + DynAdr - 8);
|
|
WR.Write32LE(00000101H);
|
|
WR.Write32LE(phdr[dyn].p_filesz + DynAdr - 4);
|
|
WR.Write32LE(00000201H)
|
|
|
|
END;
|
|
|
|
WR.Write32LE(symCount);
|
|
WR.Write32LE(symCount);
|
|
|
|
FOR i := 0 TO symCount - 1 DO
|
|
WR.Write32LE(CHL.GetInt(bucket, i))
|
|
END;
|
|
|
|
FOR i := 0 TO symCount - 1 DO
|
|
WR.Write32LE(CHL.GetInt(chain, i))
|
|
END;
|
|
|
|
CHL.WriteToFile(strtab);
|
|
|
|
IF amd64 THEN
|
|
WR.Write64LE(0);
|
|
WR.Write64LE(0)
|
|
ELSE
|
|
WR.Write32LE(0);
|
|
WR.Write32LE(0)
|
|
END;
|
|
|
|
CHL.WriteToFile(program.code);
|
|
WHILE pad > 0 DO
|
|
WR.WriteByte(0);
|
|
DEC(pad)
|
|
END;
|
|
CHL.WriteToFile(program.data);
|
|
WR.Close;
|
|
UTILS.chmod(FileName)
|
|
END write;
|
|
|
|
|
|
END ELF. |