DynamicLoader: Cleanup and prepare for TLS

This commit is contained in:
Bananymous 2025-04-15 23:13:51 +03:00
parent d7e6df1e44
commit 254fd80088
1 changed files with 124 additions and 29 deletions

View File

@ -10,6 +10,12 @@
#include <sys/syscall.h> #include <sys/syscall.h>
#include <unistd.h> #include <unistd.h>
#if defined(__x86_64__)
#define ELF_R_SYM ELF64_R_SYM
#elif defined(__i686__)
#define ELF_R_SYM ELF32_R_SYM
#endif
extern "C" extern "C"
__attribute__((naked)) __attribute__((naked))
void _start() void _start()
@ -141,6 +147,8 @@ struct LoadedElf
ElfNativeFileHeader file_header; ElfNativeFileHeader file_header;
ElfNativeDynamic* dynamics; ElfNativeDynamic* dynamics;
int fd;
uintptr_t base; uintptr_t base;
uintptr_t hash; uintptr_t hash;
@ -210,20 +218,71 @@ static ElfNativeSymbol* find_symbol(const LoadedElf& elf, const char* name)
} }
template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA> template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA>
static void handle_copy_relocation(const LoadedElf& elf, const RelocT& reloc) static bool is_tls_relocation(const RelocT& reloc)
{ {
#if defined(__x86_64__) #if defined(__x86_64__)
if (ELF64_R_TYPE(reloc.r_info) != R_X86_64_COPY) switch (ELF64_R_TYPE(reloc.r_info))
return; {
const uint32_t symbol_index = ELF64_R_SYM(reloc.r_info); case R_X86_64_DTPMOD64:
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64:
case R_X86_64_TLSGD:
case R_X86_64_TLSLD:
case R_X86_64_DTPOFF32:
case R_X86_64_GOTTPOFF:
case R_X86_64_TPOFF32:
return true;
}
#elif defined(__i686__) #elif defined(__i686__)
if (ELF32_R_TYPE(reloc.r_info) != R_386_COPY) switch (ELF32_R_TYPE(reloc.r_info))
return; {
const uint32_t symbol_index = ELF32_R_SYM(reloc.r_info); case R_386_TLS_TPOFF:
case R_386_TLS_IE:
case R_386_TLS_GOTIE:
case R_386_TLS_LE:
case R_386_TLS_GD:
case R_386_TLS_LDM:
case R_386_TLS_GD_32:
case R_386_TLS_GD_PUSH:
case R_386_TLS_GD_CALL:
case R_386_TLS_GD_POP:
case R_386_TLS_LDM_32:
case R_386_TLS_LDM_PUSH:
case R_386_TLS_LDM_CALL:
case R_386_TLS_LDM_POP:
case R_386_TLS_LDO_32:
case R_386_TLS_IE_32:
case R_386_TLS_LE_32:
case R_386_TLS_DTPMOD32:
case R_386_TLS_DTPOFF32:
case R_386_TLS_TPOFF32:
return true;
}
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif #endif
return false;
}
template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA>
static bool is_copy_relocation(const RelocT& reloc)
{
#if defined(__x86_64__)
return ELF64_R_TYPE(reloc.r_info) == R_X86_64_COPY;
#elif defined(__i686__)
return ELF32_R_TYPE(reloc.r_info) == R_386_COPY;
#else
#error "unsupported architecture"
#endif
}
template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA>
static void handle_copy_relocation(const LoadedElf& elf, const RelocT& reloc)
{
if (!is_copy_relocation(reloc))
return;
const uint32_t symbol_index = ELF_R_SYM(reloc.r_info);
if (symbol_index == 0) if (symbol_index == 0)
print_error_and_exit("copy relocation without a symbol", 0); print_error_and_exit("copy relocation without a symbol", 0);
@ -262,25 +321,47 @@ static void handle_copy_relocation(const LoadedElf& elf, const RelocT& reloc)
} }
template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA> template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA>
static uintptr_t handle_relocation(const LoadedElf& elf, const RelocT& reloc, bool resolve_symbols) static void handle_tls_relocation(const LoadedElf& elf, const RelocT& reloc)
{ {
uintptr_t symbol_address = 0; if (!is_tls_relocation(reloc))
return;
#if defined(__x86_64__) #if defined(__x86_64__)
if (ELF64_R_TYPE(reloc.r_info) == R_X86_64_COPY) switch (ELF64_R_TYPE(reloc.r_info))
return 0; {
const uint32_t symbol_index = ELF64_R_SYM(reloc.r_info); default:
print(STDERR_FILENO, "unsupported tls reloc type ");
print_uint(STDERR_FILENO, ELF64_R_TYPE(reloc.r_info));
print(STDERR_FILENO, " in ");
print(STDERR_FILENO, elf.path);
print_error_and_exit("", 0);
}
#elif defined(__i686__) #elif defined(__i686__)
if (ELF32_R_TYPE(reloc.r_info) == R_386_COPY) switch (ELF32_R_TYPE(reloc.r_info))
return 0; {
const uint32_t symbol_index = ELF32_R_SYM(reloc.r_info); default:
print(STDERR_FILENO, "unsupported tls reloc type ");
print_uint(STDERR_FILENO, ELF64_R_TYPE(reloc.r_info));
print(STDERR_FILENO, " in ");
print(STDERR_FILENO, elf.path);
print_error_and_exit("", 0);
}
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif #endif
}
template<typename RelocT> requires BAN::is_same_v<RelocT, ElfNativeRelocation> || BAN::is_same_v<RelocT, ElfNativeRelocationA>
static uintptr_t handle_relocation(const LoadedElf& elf, const RelocT& reloc, bool resolve_symbols)
{
if (is_copy_relocation(reloc) || is_tls_relocation(reloc))
return 0;
const uint32_t symbol_index = ELF_R_SYM(reloc.r_info);
if (resolve_symbols == !symbol_index) if (resolve_symbols == !symbol_index)
return 0; return 0;
uintptr_t symbol_address = 0;
if (symbol_index) if (symbol_index)
{ {
const auto& symbol = *reinterpret_cast<ElfNativeSymbol*>(elf.symtab + symbol_index * elf.syment); const auto& symbol = *reinterpret_cast<ElfNativeSymbol*>(elf.symtab + symbol_index * elf.syment);
@ -314,6 +395,9 @@ static uintptr_t handle_relocation(const LoadedElf& elf, const RelocT& reloc, bo
symbol_address = 0; symbol_address = 0;
} }
} }
if (ELF_ST_TYPE(symbol.st_info) == STT_TLS)
print_error_and_exit("relocating TLS symbol", 0);
} }
size_t size = 0; size_t size = 0;
@ -451,6 +535,14 @@ static void relocate_elf(LoadedElf& elf, bool lazy_load)
for (size_t i = 0; i < elf.relasz / elf.relaent; i++) for (size_t i = 0; i < elf.relasz / elf.relaent; i++)
handle_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent), true); handle_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent), true);
// do tls relocations
if (elf.rel && elf.relent)
for (size_t i = 0; i < elf.relsz / elf.relent; i++)
handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocation*>(elf.rel + i * elf.relent));
if (elf.rela && elf.relaent)
for (size_t i = 0; i < elf.relasz / elf.relaent; i++)
handle_tls_relocation(elf, *reinterpret_cast<ElfNativeRelocationA*>(elf.rela + i * elf.relaent));
// do jumprel relocations // do jumprel relocations
if (elf.jmprel && elf.pltrelsz) if (elf.jmprel && elf.pltrelsz)
{ {
@ -527,17 +619,19 @@ static void handle_dynamic(LoadedElf& elf)
switch (dynamic.d_tag) switch (dynamic.d_tag)
{ {
case DT_PLTGOT: dynamic.d_un.d_ptr += elf.base; break; case DT_PLTGOT:
case DT_HASH: dynamic.d_un.d_ptr += elf.base; break; case DT_HASH:
case DT_STRTAB: dynamic.d_un.d_ptr += elf.base; break; case DT_STRTAB:
case DT_SYMTAB: dynamic.d_un.d_ptr += elf.base; break; case DT_SYMTAB:
case DT_RELA: dynamic.d_un.d_ptr += elf.base; break; case DT_RELA:
case DT_INIT: dynamic.d_un.d_ptr += elf.base; break; case DT_INIT:
case DT_FINI: dynamic.d_un.d_ptr += elf.base; break; case DT_FINI:
case DT_REL: dynamic.d_un.d_ptr += elf.base; break; case DT_REL:
case DT_JMPREL: dynamic.d_un.d_ptr += elf.base; break; case DT_JMPREL:
case DT_INIT_ARRAY: dynamic.d_un.d_ptr += elf.base; break; case DT_INIT_ARRAY:
case DT_FINI_ARRAY: dynamic.d_un.d_ptr += elf.base; break; case DT_FINI_ARRAY:
dynamic.d_un.d_ptr += elf.base;
break;
} }
switch (dynamic.d_tag) switch (dynamic.d_tag)
@ -593,8 +687,6 @@ static void handle_dynamic(LoadedElf& elf)
const auto& loaded_elf = load_elf(realpath, library_fd); const auto& loaded_elf = load_elf(realpath, library_fd);
dynamic.d_un.d_ptr = reinterpret_cast<uintptr_t>(&loaded_elf); dynamic.d_un.d_ptr = reinterpret_cast<uintptr_t>(&loaded_elf);
syscall(SYS_CLOSE, library_fd);
} }
// do relocations without symbols // do relocations without symbols
@ -830,6 +922,7 @@ static LoadedElf& load_elf(const char* path, int fd)
auto& elf = s_loaded_files[s_loaded_file_count++]; auto& elf = s_loaded_files[s_loaded_file_count++];
elf.base = base; elf.base = base;
elf.fd = fd;
elf.dynamics = nullptr; elf.dynamics = nullptr;
memcpy(&elf.file_header, &file_header, sizeof(file_header)); memcpy(&elf.file_header, &file_header, sizeof(file_header));
strcpy(elf.path, path); strcpy(elf.path, path);
@ -945,12 +1038,14 @@ uintptr_t _entry(int argc, char* argv[], char* envp[])
init_random(); init_random();
auto& elf = load_elf(argv[0], execfd); auto& elf = load_elf(argv[0], execfd);
syscall(SYS_CLOSE, fd);
fini_random(); fini_random();
relocate_elf(elf, true); relocate_elf(elf, true);
initialize_environ(envp); initialize_environ(envp);
call_init_funcs(elf, true); call_init_funcs(elf, true);
for (size_t i = 0; i < s_loaded_file_count; i++)
syscall(SYS_CLOSE, s_loaded_files[i].fd);
return elf.base + elf.file_header.e_entry; return elf.base + elf.file_header.e_entry;
} }