DynamicLoader: Cleanup and prepare for TLS
This commit is contained in:
		
							parent
							
								
									d7e6df1e44
								
							
						
					
					
						commit
						254fd80088
					
				|  | @ -10,6 +10,12 @@ | |||
| #include <sys/syscall.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" | ||||
| __attribute__((naked)) | ||||
| void _start() | ||||
|  | @ -141,6 +147,8 @@ struct LoadedElf | |||
| 	ElfNativeFileHeader file_header; | ||||
| 	ElfNativeDynamic* dynamics; | ||||
| 
 | ||||
| 	int fd; | ||||
| 
 | ||||
| 	uintptr_t base; | ||||
| 
 | ||||
| 	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> | ||||
| static void handle_copy_relocation(const LoadedElf& elf, const RelocT& reloc) | ||||
| static bool is_tls_relocation(const RelocT& reloc) | ||||
| { | ||||
| #if defined(__x86_64__) | ||||
| 	if (ELF64_R_TYPE(reloc.r_info) != R_X86_64_COPY) | ||||
| 		return; | ||||
| 	const uint32_t symbol_index = ELF64_R_SYM(reloc.r_info); | ||||
| 	switch (ELF64_R_TYPE(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__) | ||||
| 	if (ELF32_R_TYPE(reloc.r_info) != R_386_COPY) | ||||
| 		return; | ||||
| 	const uint32_t symbol_index = ELF32_R_SYM(reloc.r_info); | ||||
| 	switch (ELF32_R_TYPE(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 | ||||
| 	#error "unsupported architecture" | ||||
| #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) | ||||
| 		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> | ||||
| 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 (ELF64_R_TYPE(reloc.r_info) == R_X86_64_COPY) | ||||
| 		return 0; | ||||
| 	const uint32_t symbol_index = ELF64_R_SYM(reloc.r_info); | ||||
| 	switch (ELF64_R_TYPE(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__) | ||||
| 	if (ELF32_R_TYPE(reloc.r_info) == R_386_COPY) | ||||
| 		return 0; | ||||
| 	const uint32_t symbol_index = ELF32_R_SYM(reloc.r_info); | ||||
| 	switch (ELF32_R_TYPE(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 | ||||
| 	#error "unsupported architecture" | ||||
| #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) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	uintptr_t symbol_address = 0; | ||||
| 	if (symbol_index) | ||||
| 	{ | ||||
| 		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; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if (ELF_ST_TYPE(symbol.st_info) == STT_TLS) | ||||
| 			print_error_and_exit("relocating TLS symbol", 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++) | ||||
| 			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
 | ||||
| 	if (elf.jmprel && elf.pltrelsz) | ||||
| 	{ | ||||
|  | @ -527,17 +619,19 @@ static void handle_dynamic(LoadedElf& elf) | |||
| 
 | ||||
| 		switch (dynamic.d_tag) | ||||
| 		{ | ||||
| 			case DT_PLTGOT:     dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_HASH:       dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_STRTAB:     dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_SYMTAB:     dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_RELA:       dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_INIT:       dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_FINI:       dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_REL:        dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_JMPREL:     dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_INIT_ARRAY: dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_FINI_ARRAY: dynamic.d_un.d_ptr += elf.base; break; | ||||
| 			case DT_PLTGOT: | ||||
| 			case DT_HASH: | ||||
| 			case DT_STRTAB: | ||||
| 			case DT_SYMTAB: | ||||
| 			case DT_RELA: | ||||
| 			case DT_INIT: | ||||
| 			case DT_FINI: | ||||
| 			case DT_REL: | ||||
| 			case DT_JMPREL: | ||||
| 			case DT_INIT_ARRAY: | ||||
| 			case DT_FINI_ARRAY: | ||||
| 				dynamic.d_un.d_ptr += elf.base; | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		switch (dynamic.d_tag) | ||||
|  | @ -593,8 +687,6 @@ static void handle_dynamic(LoadedElf& elf) | |||
| 
 | ||||
| 		const auto& loaded_elf = load_elf(realpath, library_fd); | ||||
| 		dynamic.d_un.d_ptr = reinterpret_cast<uintptr_t>(&loaded_elf); | ||||
| 
 | ||||
| 		syscall(SYS_CLOSE, library_fd); | ||||
| 	} | ||||
| 
 | ||||
| 	// 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++]; | ||||
| 	elf.base = base; | ||||
| 	elf.fd = fd; | ||||
| 	elf.dynamics = nullptr; | ||||
| 	memcpy(&elf.file_header, &file_header, sizeof(file_header)); | ||||
| 	strcpy(elf.path, path); | ||||
|  | @ -945,12 +1038,14 @@ uintptr_t _entry(int argc, char* argv[], char* envp[]) | |||
| 
 | ||||
| 	init_random(); | ||||
| 	auto& elf = load_elf(argv[0], execfd); | ||||
| 	syscall(SYS_CLOSE, fd); | ||||
| 	fini_random(); | ||||
| 
 | ||||
| 	relocate_elf(elf, true); | ||||
| 	initialize_environ(envp); | ||||
| 	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; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue