mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-06-02 17:58:00 +00:00
727 lines
25 KiB
C
727 lines
25 KiB
C
#include "ld.h"
|
|
|
|
#include "../../libs/include/sysbase.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");
|
|
}
|
|
|
|
void *memcpy(void *dest, const void *src, __SIZE_TYPE__ n)
|
|
{
|
|
__UINT8_TYPE__ *d = dest;
|
|
const __UINT8_TYPE__ *s = src;
|
|
while (n--)
|
|
*d++ = *s++;
|
|
return dest;
|
|
}
|
|
|
|
void *memset(void *s, int c, __SIZE_TYPE__ n)
|
|
{
|
|
__UINT8_TYPE__ *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 DynamicArrayTags Tag)
|
|
{
|
|
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
|
|
|
Elf64_Phdr ItrProgramHeader;
|
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
|
{
|
|
memcpy(&ItrProgramHeader, (__UINT8_TYPE__ *)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_TYPE__ *)ElfFile + ItrProgramHeader.p_offset);
|
|
for (__SIZE_TYPE__ i = 0; i < ItrProgramHeader.p_filesz / sizeof(struct Elf64_Dyn); i++)
|
|
{
|
|
if (Dynamic[i].d_tag == Tag)
|
|
{
|
|
// debug("Found dynamic tag %d at %#lx [d_val: %#lx].", Tag, &Dynamic[i], Dynamic[i].d_un.d_val);
|
|
return &Dynamic[i];
|
|
}
|
|
if (Dynamic[i].d_tag == DT_NULL)
|
|
{
|
|
// debug("Reached end of dynamic tag list for tag %d.", Tag);
|
|
return (void *)0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// debug("Dynamic tag %d not found.", Tag);
|
|
return (void *)0;
|
|
}
|
|
|
|
Elf64_Sym *ELFGetSymbol(uintptr_t ElfFile, char *SymbolName)
|
|
{
|
|
struct Elf64_Dyn *_SymTab = ELFGetDynamicTag((void *)ElfFile, DT_SYMTAB);
|
|
struct Elf64_Dyn *_StrTab = ELFGetDynamicTag((void *)ElfFile, DT_STRTAB);
|
|
Elf64_Sym *DynSym = (Elf64_Sym *)(ElfFile + _SymTab->d_un.d_ptr);
|
|
char *DynStr = (char *)(ElfFile + _StrTab->d_un.d_ptr);
|
|
|
|
for (int i = 0; i < _SymTab->d_un.d_val; i++)
|
|
{
|
|
if (strcmp(DynStr + DynSym[i].st_name, SymbolName) == 0)
|
|
return &DynSym[i];
|
|
}
|
|
PrintNL("ELFGetSymbol: Symbol not found!");
|
|
return (Elf64_Sym *)0;
|
|
}
|
|
|
|
void (*ELF_LAZY_RESOLVE_MAIN(struct LibAddressCollection *Info, long RelIndex))()
|
|
{
|
|
char DbgBuff[32];
|
|
if (Info)
|
|
{
|
|
struct LibAddressCollection *tmp = Info;
|
|
PrintNL("_______");
|
|
// The last entry is the null entry (Valid == false) which determines the end of the list.
|
|
while (tmp->Valid)
|
|
{
|
|
Print("-- ");
|
|
Print(tmp->Name);
|
|
Print(" ");
|
|
ltoa(RelIndex, DbgBuff, 10);
|
|
Print(DbgBuff);
|
|
PrintNL(" --");
|
|
uintptr_t BaseAddress = __UINTPTR_MAX__;
|
|
|
|
Elf64_Phdr ItrProgramHeader;
|
|
|
|
for (Elf64_Half i = 0; i < ((Elf64_Ehdr *)tmp->ElfFile)->e_phnum; i++)
|
|
{
|
|
memcpy(&ItrProgramHeader, (__UINT8_TYPE__ *)tmp->ElfFile + ((Elf64_Ehdr *)tmp->ElfFile)->e_phoff + ((Elf64_Ehdr *)tmp->ElfFile)->e_phentsize * i, sizeof(Elf64_Phdr));
|
|
BaseAddress = MIN(BaseAddress, ItrProgramHeader.p_vaddr);
|
|
}
|
|
|
|
ltoa((long)tmp->MemoryImage, DbgBuff, 16);
|
|
Print("mmImg 0x");
|
|
PrintNL(DbgBuff);
|
|
|
|
ltoa(BaseAddress, DbgBuff, 16);
|
|
Print("BAddr 0x");
|
|
PrintNL(DbgBuff);
|
|
|
|
struct Elf64_Dyn *_JmpRel = ELFGetDynamicTag((void *)tmp->ElfFile, DT_JMPREL);
|
|
struct Elf64_Dyn *_SymTab = ELFGetDynamicTag((void *)tmp->ElfFile, DT_SYMTAB);
|
|
struct Elf64_Dyn *_StrTab = ELFGetDynamicTag((void *)tmp->ElfFile, DT_STRTAB);
|
|
|
|
if (!_JmpRel)
|
|
{
|
|
PrintNL("No DT_JMPREL");
|
|
goto RetryNextLib;
|
|
}
|
|
else if (RelIndex >= _JmpRel->d_un.d_val / sizeof(Elf64_Rela))
|
|
{
|
|
PrintNL("RelIndex is greater than the number of relocations");
|
|
goto RetryNextLib;
|
|
}
|
|
|
|
if (!_SymTab)
|
|
{
|
|
PrintNL("No DT_SYMTAB");
|
|
goto RetryNextLib;
|
|
}
|
|
|
|
if (!_StrTab)
|
|
{
|
|
PrintNL("No DT_STRTAB");
|
|
goto RetryNextLib;
|
|
}
|
|
|
|
if (!_JmpRel && !_SymTab && !_StrTab)
|
|
goto RetryNextLib;
|
|
|
|
Elf64_Rela *JmpRel = (Elf64_Rela *)(tmp->MemoryImage + (_JmpRel->d_un.d_ptr - BaseAddress));
|
|
Elf64_Sym *SymTab = (Elf64_Sym *)(tmp->MemoryImage + (_SymTab->d_un.d_ptr - BaseAddress));
|
|
char *DynStr = (char *)(tmp->MemoryImage + (_StrTab->d_un.d_ptr - BaseAddress));
|
|
|
|
Elf64_Rela *Rel = JmpRel + RelIndex;
|
|
Elf64_Addr *GOTEntry = (Elf64_Addr *)(tmp->MemoryImage + Rel->r_offset);
|
|
|
|
int RelType = ELF64_R_TYPE(Rel->r_info);
|
|
|
|
switch (RelType)
|
|
{
|
|
case R_X86_64_NONE:
|
|
{
|
|
PrintNL("R_X86_64_NONE");
|
|
if (*GOTEntry == 0)
|
|
{
|
|
PrintNL("GOTEntry is 0");
|
|
break;
|
|
}
|
|
Lock = 0;
|
|
return (void (*)()) * GOTEntry;
|
|
}
|
|
case R_X86_64_JUMP_SLOT:
|
|
{
|
|
PrintNL("R_X86_64_JUMP_SLOT");
|
|
int SymIndex = ELF64_R_SYM(Rel->r_info);
|
|
Elf64_Sym *Sym = SymTab + SymIndex;
|
|
|
|
if (Sym->st_name)
|
|
{
|
|
char *SymName = DynStr + Sym->st_name; /* I think i get this wrong */
|
|
Print("SymName: ");
|
|
PrintNL(SymName);
|
|
|
|
Elf64_Sym *LibSym = ELFGetSymbol(tmp->ElfFile, SymName);
|
|
if (LibSym)
|
|
{
|
|
*GOTEntry = (Elf64_Addr)(tmp->MemoryImage + LibSym->st_value);
|
|
|
|
ltoa(*GOTEntry, DbgBuff, 16);
|
|
Print("*GOTEntry: 0x");
|
|
PrintNL(DbgBuff);
|
|
|
|
Lock = 0;
|
|
return (void (*)()) * GOTEntry;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ltoa(RelType, DbgBuff, 10);
|
|
Print("RelType not supported ");
|
|
PrintNL(DbgBuff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
RetryNextLib:
|
|
PrintNL("Retrying next lib");
|
|
tmp = tmp->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
|
|
;
|
|
}
|
|
|
|
/* This function is a mess and needs to be cleaned up. */
|
|
/*
|
|
bool ELFDynamicReallocation(void *ElfFile, void *MemoryImage)
|
|
{
|
|
debug("ELF dynamic reallocation for image at %#lx.", ElfFile);
|
|
|
|
Elf64_Ehdr *ELFHeader = (Elf64_Ehdr *)ElfFile;
|
|
uintptr_t BaseAddress = UINTPTR_MAX;
|
|
size_t ElfAppSize = 0;
|
|
Elf64_Phdr ItrPhdr;
|
|
|
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
|
{
|
|
memcpy(&ItrPhdr,
|
|
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
|
sizeof(Elf64_Phdr));
|
|
BaseAddress = MIN(BaseAddress, ItrPhdr.p_vaddr);
|
|
}
|
|
|
|
for (Elf64_Half i = 0; i < ELFHeader->e_phnum; i++)
|
|
{
|
|
memcpy(&ItrPhdr,
|
|
(uint8_t *)ElfFile + ELFHeader->e_phoff + ELFHeader->e_phentsize * i,
|
|
sizeof(Elf64_Phdr));
|
|
uintptr_t SegmentEnd = ItrPhdr.p_vaddr - BaseAddress + ItrPhdr.p_memsz;
|
|
ElfAppSize = MAX(ElfAppSize, SegmentEnd);
|
|
}
|
|
|
|
debug("BaseAddress: %#lx Size: %ld", BaseAddress, ElfAppSize);
|
|
|
|
Elf64_Dyn *_GOTEntry = (Elf64_Dyn *)ELFGetDynamicTag(ElfFile, DT_PLTGOT);
|
|
Elf64_Dyn *_Rela = ELFGetDynamicTag(ElfFile, DT_RELA);
|
|
Elf64_Dyn *_RelaEnt = ELFGetDynamicTag(ElfFile, DT_RELAENT);
|
|
Elf64_Dyn *_JmpRel = ELFGetDynamicTag(ElfFile, DT_JMPREL);
|
|
Elf64_Dyn *_SymTab = ELFGetDynamicTag(ElfFile, DT_SYMTAB);
|
|
Elf64_Dyn *_StrTab = ELFGetDynamicTag(ElfFile, DT_STRTAB);
|
|
Elf64_Dyn *RelaSize = ELFGetDynamicTag(ElfFile, DT_RELASZ);
|
|
Elf64_Dyn *PltRelSize = ELFGetDynamicTag(ElfFile, DT_PLTRELSZ);
|
|
|
|
Elf64_Addr *GOTEntry = (Elf64_Addr *)((uintptr_t)(_GOTEntry->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
|
Elf64_Dyn *Rela = (Elf64_Dyn *)((uintptr_t)(_Rela->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
|
Elf64_Dyn *RelaEnt = (Elf64_Dyn *)((uintptr_t)(_RelaEnt->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
|
Elf64_Dyn *JmpRel = (Elf64_Dyn *)((uintptr_t)(_JmpRel->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
|
Elf64_Dyn *SymTab = (Elf64_Dyn *)((uintptr_t)(_SymTab->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
|
Elf64_Dyn *StrTab = (Elf64_Dyn *)((uintptr_t)(_StrTab->d_un.d_ptr - BaseAddress) + (uintptr_t)MemoryImage);
|
|
|
|
debug("GOTEntry: %#lx [%#lx]", _GOTEntry, GOTEntry);
|
|
debug("Rela: %#lx [%#lx]", _Rela, Rela);
|
|
debug("RelaEnt: %#lx [%#lx]", _RelaEnt, RelaEnt);
|
|
debug("JmpRel: %#lx [%#lx]", _JmpRel, JmpRel);
|
|
debug("SymTab: %#lx [%#lx]", _SymTab, SymTab);
|
|
debug("StrTab: %#lx [%#lx]", _StrTab, StrTab);
|
|
if (RelaSize)
|
|
debug("RelaSize: %ld", RelaSize->d_un.d_val);
|
|
if (PltRelSize)
|
|
debug("PltRelSize: %ld", PltRelSize->d_un.d_val);
|
|
|
|
Elf64_Xword PltRelSizeVal = PltRelSize ? PltRelSize->d_un.d_val : 0;
|
|
Elf64_Xword RelaSizeVal = RelaSize ? RelaSize->d_un.d_val : 0;
|
|
|
|
Elf64_Xword PltRelSizeValCount = PltRelSizeVal / sizeof(Elf64_Rela);
|
|
Elf64_Xword RelaSizeValCount = RelaSizeVal / sizeof(Elf64_Rela);
|
|
|
|
debug("PltRelSizeVal: %ld", PltRelSizeVal);
|
|
debug("RelaSizeVal: %ld", RelaSizeVal);
|
|
debug("PltRelSizeValCount: %ld", PltRelSizeValCount);
|
|
debug("RelaSizeValCount: %ld", RelaSizeValCount);
|
|
|
|
for (Elf64_Xword i = 0; i < PltRelSizeValCount; i++)
|
|
{
|
|
Elf64_Rela *RelaF = (Elf64_Rela *)((uintptr_t)JmpRel + i);
|
|
Elf64_Xword RelaType = ELF64_R_TYPE(RelaF->r_info);
|
|
debug("Itr %ld Type %ld", i, RelaType);
|
|
|
|
switch (RelaType)
|
|
{
|
|
case R_X86_64_NONE:
|
|
{
|
|
debug("No relocation needed");
|
|
break;
|
|
}
|
|
case R_X86_64_JUMP_SLOT:
|
|
{
|
|
debug("Relocation for jump slot");
|
|
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
|
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)SymTab + SymIndex);
|
|
char *SymName = (char *)((uintptr_t)StrTab + Sym->st_name);
|
|
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
|
|
|
Elf64_Addr *GOTEntry = (Elf64_Addr *)RelaF->r_offset;
|
|
if (Sym->st_value)
|
|
{
|
|
fixme("Not implemented");
|
|
*GOTEntry = (Elf64_Addr)ElfFile + Sym->st_value;
|
|
}
|
|
// else
|
|
// *GOTEntry = (Elf64_Addr)ElfLazyResolver;
|
|
|
|
// Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + ELF64_R_SYM(RelaF->r_info) * sizeof(Elf64_Sym));
|
|
// char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
|
// void *SymAddr = (void *)Lib->Address + Sym->st_value;
|
|
// debug("Symbol %s at %#lx", SymName, SymAddr);
|
|
// *(void **)(RelaF->r_offset + (uintptr_t)ElfFile) = SymAddr;
|
|
break;
|
|
}
|
|
case R_X86_64_RELATIVE:
|
|
{
|
|
debug("Relative relocation");
|
|
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
|
*Ptr = (uintptr_t)MemoryImage + RelaF->r_addend;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
fixme("RelaType %d", RelaType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (Elf64_Xword i = 0; i < RelaSizeValCount; i++)
|
|
{
|
|
Elf64_Rela *RelaF = (Elf64_Rela *)((uintptr_t)ElfFile + (uintptr_t)Rela + i);
|
|
Elf64_Xword RelaType = ELF64_R_TYPE(RelaF->r_info);
|
|
debug("Itr %ld Type %ld", i, RelaType);
|
|
|
|
switch (RelaType)
|
|
{
|
|
case R_X86_64_NONE:
|
|
{
|
|
debug("No relocation needed");
|
|
break;
|
|
}
|
|
case R_X86_64_64:
|
|
{
|
|
debug("64-bit relocation");
|
|
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
|
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + SymIndex);
|
|
char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
|
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
|
|
|
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
|
*Ptr = (uintptr_t)MemoryImage + Sym->st_value + RelaF->r_addend;
|
|
break;
|
|
}
|
|
case R_X86_64_GLOB_DAT:
|
|
{
|
|
debug("Global data relocation");
|
|
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
|
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + SymIndex);
|
|
char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
|
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
|
|
|
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
|
*Ptr = (uintptr_t)MemoryImage + Sym->st_value;
|
|
break;
|
|
}
|
|
case R_X86_64_RELATIVE:
|
|
{
|
|
debug("Relative relocation");
|
|
Elf64_Xword SymIndex = ELF64_R_SYM(RelaF->r_info);
|
|
Elf64_Sym *Sym = (Elf64_Sym *)((uintptr_t)ElfFile + (uintptr_t)SymTab + SymIndex);
|
|
char *SymName = (char *)((uintptr_t)ElfFile + (uintptr_t)StrTab + Sym->st_name);
|
|
debug("Symbol %s at %#lx", SymName, Sym->st_value);
|
|
|
|
uintptr_t *Ptr = (uintptr_t *)((uintptr_t)ElfFile + RelaF->r_offset);
|
|
*Ptr = (uintptr_t)MemoryImage + RelaF->r_addend;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
fixme("RelaType %d", RelaType);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
|
|
ELFDynamicReallocation(ElfFile, MemoryImage);
|
|
|
|
LibAddressCollection *LibsForLazyResolver = (LibAddressCollection *)ELFBase.TmpMem->RequestPages(TO_PAGES(sizeof(LibAddressCollection)), true);
|
|
memset(LibsForLazyResolver, 0, sizeof(LibAddressCollection));
|
|
LibAddressCollection *LFLRTmp = LibsForLazyResolver;
|
|
debug("LibsForLazyResolver: %#lx", LibsForLazyResolver);
|
|
|
|
if (NeededLibraries.size() > 0)
|
|
{
|
|
VirtualFileSystem::Node *ParentNode = ExFile->Node->Parent; // Working Directory
|
|
if (ParentNode)
|
|
{
|
|
char *WorkingDirAbsolutePath = vfs->GetPathFromNode(ParentNode);
|
|
debug("Working directory: \"%s\"", WorkingDirAbsolutePath);
|
|
|
|
int LibCount = 0;
|
|
foreach (auto Library in NeededLibraries)
|
|
{
|
|
char LibPath[256];
|
|
strcpy(LibPath, WorkingDirAbsolutePath);
|
|
strcat(LibPath, "/");
|
|
strcat(LibPath, Library);
|
|
debug("Searching for \"%s\"...", LibPath);
|
|
|
|
bool AlreadyTried = false;
|
|
|
|
LibPathRetry:
|
|
VirtualFileSystem::FILE *LibNode = vfs->Open(LibPath);
|
|
|
|
if (LibNode->Status != VirtualFileSystem::FileStatus::OK)
|
|
{
|
|
vfs->Close(LibNode);
|
|
if (!AlreadyTried)
|
|
{
|
|
debug("Library \"%s\" not found, retrying... (%#x)", LibPath, LibNode->Status);
|
|
memset(LibPath, 0, 256);
|
|
strcpy(LibPath, "/system/lib/");
|
|
strcat(LibPath, Library);
|
|
AlreadyTried = true;
|
|
goto LibPathRetry;
|
|
}
|
|
else
|
|
warn("Failed to load library \"%s\" (%#x)", Library, LibNode->Status);
|
|
}
|
|
else
|
|
{
|
|
debug("Library found \"%s\" (%#x)", LibPath, LibNode->Status);
|
|
SharedLibraries *sl = AddLibrary(Library, (void *)LibNode->Node->Address, LibNode->Node->Length);
|
|
strcpy(LFLRTmp->Name, Library);
|
|
LFLRTmp->ElfFile = (uintptr_t *)sl->Address;
|
|
LFLRTmp->MemoryImage = (uintptr_t *)sl->MemoryImage;
|
|
LFLRTmp->ParentElfFile = (uintptr_t *)ElfFile;
|
|
LFLRTmp->ParentMemoryImage = (uintptr_t *)MemoryImage;
|
|
LFLRTmp->Valid = true;
|
|
debug("LIBRARY: %s, %#lx, %#lx", Library, LFLRTmp->ElfFile, LFLRTmp->MemoryImage);
|
|
|
|
LFLRTmp->Next = (LibAddressCollection *)ELFBase.TmpMem->RequestPages(TO_PAGES(sizeof(LibAddressCollection)), true);
|
|
LFLRTmp = LFLRTmp->Next;
|
|
memset(LFLRTmp, 0, sizeof(LibAddressCollection));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error("Couldn't get the parent node from path %s", vfs->GetPathFromNode(ExFile->Node));
|
|
}
|
|
}
|
|
|
|
ELFAddLazyResolverToGOT(ElfFile, MemoryImage, LibsForLazyResolver);
|
|
*/
|
|
|
|
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_FILE, (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_FILE, (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;
|
|
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;
|
|
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->MemoryImage)->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);
|
|
}
|