2023-05-04 05:00:47 +03:00

548 lines
17 KiB
C

#include "ld.h"
#include "../../libs/include/libsys/base.h"
#include "../../../Kernel/syscalls.h"
#include "../../../Kernel/ipc.h"
#include "elf.h"
uintptr_t RequestPages(size_t Count)
{
return syscall1(_RequestPages, Count);
}
int FreePages(uintptr_t Address, size_t Count)
{
return syscall2(_FreePages, Address, Count);
}
int IPC(enum IPCCommand Command, enum IPCType Type, int ID, int Flags, void *Buffer, size_t Size)
{
return syscall6(_IPC, (long)Command, (long)Type, (long)ID, (long)Flags, (long)Buffer, (long)Size);
}
uintptr_t KernelCTL(enum KCtl Command, uint64_t Arg1, uint64_t Arg2, uint64_t Arg3, uint64_t Arg4)
{
return syscall5(_KernelCTL, Command, Arg1, Arg2, Arg3, Arg4);
}
struct LibAddressCollection
{
char Name[32];
uintptr_t ElfFile;
uintptr_t MemoryImage;
uintptr_t ParentElfFile;
uintptr_t ParentMemoryImage;
struct LibAddressCollection *Next;
char Valid;
};
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
static char Lock = 0;
__attribute__((naked, used, no_stack_protector)) void ELF_LAZY_RESOLVE_STUB()
{
while (Lock == 1)
;
__asm__ __volatile__("mfence\n");
Lock = 1;
__asm__ __volatile__("pop %r11\n"
"pop %r10\n"
"push %rdi\n"
"push %rsi\n"
"push %rdx\n"
"push %rcx\n"
"push %r8\n"
"push %r9\n"
"mov %r11, %rdi\n" // Move the first argument to rdi (libs collection)
"mov %r10, %rsi\n" // Move the second argument to rsi (rel index)
"call ELF_LAZY_RESOLVE_MAIN\n"
"mov %rax, %r11\n" // Move the return value to r11
"pop %r9\n"
"pop %r8\n"
"pop %rcx\n"
"pop %rdx\n"
"pop %rsi\n"
"pop %rdi\n"
"jmp *%r11\n"); // Jump to the return value
}
int abs(int i) { return i < 0 ? -i : i; }
void swap(char *x, char *y)
{
char t = *x;
*x = *y;
*y = t;
}
char *reverse(char *Buffer, int i, int j)
{
while (i < j)
swap(&Buffer[i++], &Buffer[j--]);
return Buffer;
}
char *ltoa(long Value, char *Buffer, int Base)
{
if (Base < 2 || Base > 32)
return Buffer;
long n = (long)abs((int)Value);
int i = 0;
while (n)
{
int r = n % Base;
if (r >= 10)
Buffer[i++] = 65 + (r - 10);
else
Buffer[i++] = 48 + r;
n = n / Base;
}
if (i == 0)
Buffer[i++] = '0';
if (Value < 0 && Base == 10)
Buffer[i++] = '-';
Buffer[i] = '\0';
return reverse(Buffer, 0, i - 1);
}
static inline void PutCharToKernelConsole(char c)
{
__asm__ __volatile__("syscall"
:
: "a"(1), "D"(c), "S"(0)
: "rcx", "r11", "memory");
}
void Print__(char *String)
{
for (short i = 0; String[i] != '\0'; i++)
PutCharToKernelConsole(String[i]);
}
void PrintNL__(char *String)
{
Print__(String);
Print__("\n");
}
#define Print(x) Print__(x)
#define PrintNL(x) PrintNL__(x)
#if (0)
#define PrintDbg(x) Print__(x)
#define PrintDbgNL(x) PrintNL__(x)
#define ltoaDbg(x, y, z) ltoa(x, y, z)
#else
#define PrintDbg(x)
#define PrintDbgNL(x)
#define ltoaDbg(x, y, z)
#endif
void *memcpy(void *dest, const void *src, size_t n)
{
uint8_t *d = dest;
const uint8_t *s = src;
while (n--)
*d++ = *s++;
return dest;
}
void *memset(void *s, int c, size_t n)
{
uint8_t *p = s;
while (n--)
*p++ = c;
}
int strcmp(const char *l, const char *r)
{
for (; *l == *r && *l; l++, r++)
;
return *(unsigned char *)l - *(unsigned char *)r;
}
struct Elf64_Dyn *ELFGetDynamicTag(void *ElfFile, enum DynamicTags Tag)
{
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
Elf64_Phdr ItrProgramHeader;
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
{
memcpy(&ItrProgramHeader, (uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i, sizeof(Elf64_Phdr));
if (ItrProgramHeader.p_type == PT_DYNAMIC)
{
struct Elf64_Dyn *Dynamic = (struct Elf64_Dyn *)((uint8_t *)ElfFile + ItrProgramHeader.p_offset);
for (size_t i = 0; i < ItrProgramHeader.p_filesz / sizeof(struct Elf64_Dyn); i++)
{
if (Dynamic[i].d_tag == Tag)
return &Dynamic[i];
if (Dynamic[i].d_tag == DT_NULL)
return (void *)0;
}
}
}
return (void *)0;
}
Elf64_Shdr *GetELFSheader(Elf64_Ehdr *Header)
{
Elf64_Off SheaderOffset = Header->e_shoff;
return (Elf64_Shdr *)((uintptr_t)Header + SheaderOffset);
}
Elf64_Shdr *GetELFSection(Elf64_Ehdr *Header, uint64_t Index)
{
Elf64_Shdr *Sheader = GetELFSheader(Header);
return &Sheader[Index];
}
char *GetELFStringTable(Elf64_Ehdr *Header)
{
if (Header->e_shstrndx == SHN_UNDEF)
return NULL;
return (char *)Header + GetELFSection(Header, Header->e_shstrndx)->sh_offset;
}
Elf64_Sym *ELFLookupSymbol(Elf64_Ehdr *Header, const char *Name)
{
Elf64_Shdr *SymbolTable = NULL;
Elf64_Shdr *StringTable = NULL;
Elf64_Sym *Symbol = NULL;
char *String = NULL;
for (Elf64_Half i = 0; i < Header->e_shnum; i++)
{
Elf64_Shdr *shdr = GetELFSection(Header, i);
switch (shdr->sh_type)
{
case SHT_SYMTAB:
SymbolTable = shdr;
StringTable = GetELFSection(Header, shdr->sh_link);
break;
default:
{
break;
}
}
}
if (SymbolTable == NULL || StringTable == NULL)
return NULL;
for (size_t i = 0; i < (SymbolTable->sh_size / sizeof(Elf64_Sym)); i++)
{
Symbol = (Elf64_Sym *)((uintptr_t)Header + SymbolTable->sh_offset + (i * sizeof(Elf64_Sym)));
String = (char *)((uintptr_t)Header + StringTable->sh_offset + Symbol->st_name);
if (strcmp(String, Name) == 0)
return (void *)Symbol;
}
return NULL;
}
void (*ELF_LAZY_RESOLVE_MAIN(struct LibAddressCollection *Info, long RelIndex))()
{
char DbgBuff[32];
if (Info)
{
struct LibAddressCollection *CurLib = Info;
PrintDbgNL("_______");
// The last entry is the null entry (Valid == false) which determines the end of the list.
while (CurLib->Valid)
{
PrintDbg("-- ");
PrintDbg(CurLib->Name);
PrintDbg(" ");
ltoaDbg(RelIndex, DbgBuff, 10);
PrintDbg(DbgBuff);
PrintDbgNL(" --");
uintptr_t lib_BaseAddress = __UINTPTR_MAX__;
uintptr_t app_BaseAddress = __UINTPTR_MAX__;
Elf64_Phdr ItrProgramHeader;
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)CurLib->ElfFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader,
(uint8_t *)CurLib->ElfFile +
((Elf64_Ehdr *)CurLib->ElfFile)->e_phoff +
((Elf64_Ehdr *)CurLib->ElfFile)->e_phentsize * i,
sizeof(Elf64_Phdr));
lib_BaseAddress = MIN(lib_BaseAddress, ItrProgramHeader.p_vaddr);
}
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)CurLib->ParentElfFile)->e_phnum; i++)
{
memcpy(&ItrProgramHeader,
(uint8_t *)CurLib->ParentElfFile +
((Elf64_Ehdr *)CurLib->ParentElfFile)->e_phoff +
((Elf64_Ehdr *)CurLib->ParentElfFile)->e_phentsize * i,
sizeof(Elf64_Phdr));
app_BaseAddress = MIN(app_BaseAddress, ItrProgramHeader.p_vaddr);
}
struct Elf64_Dyn *lib_JmpRel = ELFGetDynamicTag((void *)CurLib->ElfFile, DT_JMPREL);
struct Elf64_Dyn *lib_SymTab = ELFGetDynamicTag((void *)CurLib->ElfFile, DT_SYMTAB);
struct Elf64_Dyn *lib_StrTab = ELFGetDynamicTag((void *)CurLib->ElfFile, DT_STRTAB);
struct Elf64_Dyn *app_JmpRel = ELFGetDynamicTag((void *)CurLib->ParentElfFile, DT_JMPREL);
struct Elf64_Dyn *app_SymTab = ELFGetDynamicTag((void *)CurLib->ParentElfFile, DT_SYMTAB);
struct Elf64_Dyn *app_StrTab = ELFGetDynamicTag((void *)CurLib->ParentElfFile, DT_STRTAB);
if (!lib_JmpRel)
{
PrintNL("No DT_JMPREL");
goto RetryNextLib;
}
else if (RelIndex >= lib_JmpRel->d_un.d_val / sizeof(Elf64_Rela))
{
PrintNL("RelIndex is greater than the number of relocations");
goto RetryNextLib;
}
if (!lib_SymTab)
{
PrintNL("No DT_SYMTAB");
goto RetryNextLib;
}
if (!lib_StrTab)
{
PrintNL("No DT_STRTAB");
goto RetryNextLib;
}
if (!lib_JmpRel && !lib_SymTab && !lib_StrTab)
goto RetryNextLib;
Elf64_Rela *_lib_JmpRel = (Elf64_Rela *)(CurLib->MemoryImage + (lib_JmpRel->d_un.d_ptr - lib_BaseAddress));
Elf64_Sym *_lib_SymTab = (Elf64_Sym *)(CurLib->MemoryImage + (lib_SymTab->d_un.d_ptr - lib_BaseAddress));
Elf64_Rela *_app_JmpRel = (Elf64_Rela *)(CurLib->ParentMemoryImage + (app_JmpRel->d_un.d_ptr - app_BaseAddress));
Elf64_Sym *_app_SymTab = (Elf64_Sym *)(CurLib->ParentMemoryImage + (app_SymTab->d_un.d_ptr - app_BaseAddress));
char *lib_DynStr = (char *)(CurLib->MemoryImage + (lib_StrTab->d_un.d_ptr - lib_BaseAddress));
char *app_DynStr = (char *)(CurLib->ParentMemoryImage + (app_StrTab->d_un.d_ptr - app_BaseAddress));
Elf64_Rela *Rel = _app_JmpRel + RelIndex;
Elf64_Addr *GOTEntry = (Elf64_Addr *)(Rel->r_offset);
int RelType = ELF64_R_TYPE(Rel->r_info);
switch (RelType)
{
case R_X86_64_NONE:
{
PrintDbgNL("R_X86_64_NONE");
if (*GOTEntry == 0)
{
PrintDbgNL("GOTEntry is 0");
break;
}
Lock = 0;
return (void (*)()) * GOTEntry;
}
case R_X86_64_JUMP_SLOT:
{
PrintDbgNL("R_X86_64_JUMP_SLOT");
int SymIndex = ELF64_R_SYM(Rel->r_info);
Elf64_Sym *Sym = _app_SymTab + SymIndex;
if (Sym->st_name)
{
char *SymName = app_DynStr + Sym->st_name;
PrintDbg("SymName: ");
PrintDbgNL(SymName);
Elf64_Sym *LibSym = ELFLookupSymbol((Elf64_Ehdr *)CurLib->ElfFile, SymName);
PrintDbg("LibSym: 0x");
ltoaDbg((long)LibSym, DbgBuff, 16);
PrintDbgNL(DbgBuff);
if (LibSym)
{
*GOTEntry = (Elf64_Addr)(CurLib->MemoryImage + LibSym->st_value);
ltoa(*GOTEntry, DbgBuff, 16);
PrintDbg("*GOTEntry: 0x");
PrintDbgNL(DbgBuff);
Lock = 0;
return (void (*)()) * GOTEntry;
}
PrintDbgNL("Not found in lib");
}
break;
}
default:
{
ltoa(RelType, DbgBuff, 10);
Print("RelType not supported ");
PrintNL(DbgBuff);
break;
}
}
RetryNextLib:
PrintDbgNL("Retrying next lib");
CurLib = CurLib->Next;
}
}
Lock = 0;
__asm__ __volatile__("mfence\n");
Print("Symbol index ");
ltoa(RelIndex, DbgBuff, 10);
Print(DbgBuff);
PrintNL(" not found");
int ExitCode = 0x51801;
syscall1(_Exit, ExitCode);
while (1) // Make sure we don't return
;
}
struct InterpreterIPCDataLibrary
{
char Name[128];
};
typedef struct
{
char Path[256];
void *ElfFile;
void *MemoryImage;
struct InterpreterIPCDataLibrary Libraries[64];
} InterpreterIPCData;
/* Preload */
int ld_main()
{
/* Prevent race condition. */
uintptr_t KCTL_ret = KernelCTL(KCTL_IS_CRITICAL, 0, 0, 0, 0);
do
{
syscall1(_Sleep, 250);
KCTL_ret = KernelCTL(KCTL_IS_CRITICAL, 0, 0, 0, 0);
} while (KCTL_ret == SYSCALL_ACCESS_DENIED);
if (KCTL_ret == false)
return -4;
/* Everything is ok, continue. */
return 0;
}
bool ELFAddLazyResolverToGOT(void *ElfFile, void *MemoryImage, struct LibAddressCollection *Libs)
{
struct Elf64_Dyn *Dyn = (struct Elf64_Dyn *)ELFGetDynamicTag(ElfFile, DT_PLTGOT);
if (!Dyn)
return false;
Elf64_Addr *GOT = (Elf64_Addr *)Dyn->d_un.d_ptr;
GOT[1] = (uintptr_t)Libs;
GOT[2] = (uintptr_t)ELF_LAZY_RESOLVE_STUB;
return true;
}
/* Actual load */
int ld_load(int argc, char *argv[], char *envp[])
{
uintptr_t PageSize = KernelCTL(KCTL_GET_PAGE_SIZE, 0, 0, 0, 0);
int PagesForIPCDataStruct = sizeof(InterpreterIPCData) / PageSize + 1;
InterpreterIPCData *IPCBuffer = (InterpreterIPCData *)RequestPages(PagesForIPCDataStruct);
int IPC_ID = IPC(IPC_CREATE, IPC_TYPE_MessagePassing, 0, 0, "LOAD", sizeof(InterpreterIPCData));
while (true)
{
IPC(IPC_LISTEN, IPC_TYPE_MessagePassing, IPC_ID, 1, NULL, 0);
IPC(IPC_WAIT, IPC_TYPE_MessagePassing, IPC_ID, 0, NULL, 0);
int IPCResult = IPC(IPC_READ, IPC_TYPE_MessagePassing, IPC_ID, 0, IPCBuffer, PageSize);
if (IPCResult == IPC_E_CODE_Success)
break;
}
struct LibAddressCollection *LibsForLazyResolver = (struct LibAddressCollection *)RequestPages(sizeof(struct LibAddressCollection) / PageSize + 1);
for (size_t i = 0; i < 64; i++)
{
if (IPCBuffer->Libraries[i].Name[0] == '\0')
break;
uintptr_t lib_addr = KernelCTL(KCTL_GET_ELF_LIB_FILE, (uint64_t)IPCBuffer->Libraries[i].Name, 0, 0, 0);
uintptr_t lib_mm_image = KernelCTL(KCTL_GET_ELF_LIB_MEMORY_IMAGE, (uint64_t)IPCBuffer->Libraries[i].Name, 0, 0, 0);
if (lib_addr == 0 || lib_mm_image == 0)
{
enum SyscallsErrorCodes ret = KernelCTL(KCTL_REGISTER_ELF_LIB, (uint64_t)IPCBuffer->Libraries[i].Name, (uint64_t)IPCBuffer->Libraries[i].Name, 0, 0);
if (ret != SYSCALL_OK)
{
PrintNL("Failed to register ELF lib");
return -0x11B;
}
lib_addr = KernelCTL(KCTL_GET_ELF_LIB_FILE, (uint64_t)IPCBuffer->Libraries[i].Name, 0, 0, 0);
lib_mm_image = KernelCTL(KCTL_GET_ELF_LIB_MEMORY_IMAGE, (uint64_t)IPCBuffer->Libraries[i].Name, 0, 0, 0);
}
if (LibsForLazyResolver->Next == NULL)
{
LibsForLazyResolver->Valid = true;
LibsForLazyResolver->ElfFile = (uintptr_t)lib_addr;
LibsForLazyResolver->MemoryImage = (uintptr_t)lib_mm_image;
LibsForLazyResolver->ParentElfFile = (uintptr_t)IPCBuffer->ElfFile;
LibsForLazyResolver->ParentMemoryImage = (uintptr_t)IPCBuffer->MemoryImage;
for (size_t j = 0; j < 32; j++)
LibsForLazyResolver->Name[j] = IPCBuffer->Libraries[i].Name[j];
LibsForLazyResolver->Next = (struct LibAddressCollection *)RequestPages(sizeof(struct LibAddressCollection) / PageSize + 1);
memset(LibsForLazyResolver->Next, 0, sizeof(struct LibAddressCollection));
continue;
}
struct LibAddressCollection *CurrentLibsForLazyResolver = LibsForLazyResolver;
while (CurrentLibsForLazyResolver->Next != NULL)
CurrentLibsForLazyResolver = CurrentLibsForLazyResolver->Next;
CurrentLibsForLazyResolver->Valid = true;
CurrentLibsForLazyResolver->ElfFile = (uintptr_t)lib_addr;
CurrentLibsForLazyResolver->MemoryImage = (uintptr_t)lib_mm_image;
CurrentLibsForLazyResolver->ParentElfFile = (uintptr_t)IPCBuffer->ElfFile;
CurrentLibsForLazyResolver->ParentMemoryImage = (uintptr_t)IPCBuffer->MemoryImage;
for (size_t j = 0; j < 32; j++)
CurrentLibsForLazyResolver->Name[j] = IPCBuffer->Libraries[i].Name[j];
CurrentLibsForLazyResolver->Next = (struct LibAddressCollection *)RequestPages(sizeof(struct LibAddressCollection) / PageSize + 1);
memset(CurrentLibsForLazyResolver->Next, 0, sizeof(struct LibAddressCollection));
}
struct LibAddressCollection *CurrentLibsForLazyResolver = LibsForLazyResolver;
if (!ELFAddLazyResolverToGOT(IPCBuffer->ElfFile, IPCBuffer->MemoryImage, LibsForLazyResolver))
{
PrintNL("Failed to add lazy resolver to GOT");
return -0x607;
}
Elf64_Addr Entry = ((Elf64_Ehdr *)IPCBuffer->ElfFile)->e_entry;
IPC(IPC_DELETE, IPC_TYPE_MessagePassing, IPC_ID, 0, NULL, 0);
FreePages((uintptr_t)IPCBuffer, PagesForIPCDataStruct);
return ((int (*)(int, char *[], char *[]))Entry)(argc, argv, envp);
}