forked from Bananymous/banan-os
				
			DynamicLoader/LibC: lazy malloc environ
This allows DynamicLoader to just set the value of global environ symbol without libc needing to malloc it at startup
This commit is contained in:
		
							parent
							
								
									3721dadd72
								
							
						
					
					
						commit
						4f49d60e4a
					
				|  | @ -14,11 +14,14 @@ | |||
| #include <strings.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/syscall.h> | ||||
| #include <sys/weak_alias.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include <icxxabi.h> | ||||
| 
 | ||||
| extern "C" char** environ; | ||||
| char** __environ; | ||||
| weak_alias(__environ, environ); | ||||
| static bool s_environ_malloced = false; | ||||
| 
 | ||||
| extern "C" __attribute__((weak)) void _fini(); | ||||
| 
 | ||||
|  | @ -516,27 +519,35 @@ int putenv(char* string) | |||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!environ) | ||||
| 	if (!s_environ_malloced) | ||||
| 	{ | ||||
| 		environ = (char**)malloc(sizeof(char*) * 2); | ||||
| 		if (!environ) | ||||
| 		size_t env_count = 0; | ||||
| 		while (environ[env_count]) | ||||
| 			env_count++; | ||||
| 
 | ||||
| 		char** new_environ = static_cast<char**>(malloc((env_count + 1) * sizeof(char*))); | ||||
| 		if (new_environ == nullptr) | ||||
| 			return -1; | ||||
| 		environ[0] = string; | ||||
| 		environ[1] = nullptr; | ||||
| 		return 0; | ||||
| 		for (size_t i = 0; i < env_count; i++) | ||||
| 		{ | ||||
| 			const size_t bytes = strlen(environ[i]) + 1; | ||||
| 			new_environ[i] = (char*)malloc(bytes); | ||||
| 			memcpy(new_environ[i], environ[i], bytes); | ||||
| 		} | ||||
| 		new_environ[env_count] = nullptr; | ||||
| 
 | ||||
| 		environ = new_environ; | ||||
| 		s_environ_malloced = true; | ||||
| 	} | ||||
| 
 | ||||
| 	int cnt = 0; | ||||
| 	for (int i = 0; string[i]; i++) | ||||
| 		if (string[i] == '=') | ||||
| 			cnt++; | ||||
| 	if (cnt != 1) | ||||
| 	const char* eq_addr = strchr(string, '='); | ||||
| 	if (eq_addr == nullptr) | ||||
| 	{ | ||||
| 		errno = EINVAL; | ||||
| 		return -1; | ||||
| 	} | ||||
| 
 | ||||
| 	int namelen = strchr(string, '=') - string; | ||||
| 	size_t namelen = eq_addr - string; | ||||
| 	for (int i = 0; environ[i]; i++) | ||||
| 	{ | ||||
| 		if (strncmp(environ[i], string, namelen + 1) == 0) | ||||
|  | @ -547,15 +558,15 @@ int putenv(char* string) | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	int env_count = 0; | ||||
| 	size_t env_count = 0; | ||||
| 	while (environ[env_count]) | ||||
| 		env_count++; | ||||
| 
 | ||||
| 	char** new_envp = (char**)malloc(sizeof(char*) * (env_count + 2)); | ||||
| 	char** new_envp = static_cast<char**>(malloc(sizeof(char*) * (env_count + 2))); | ||||
| 	if (new_envp == nullptr) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	for (int i = 0; i < env_count; i++) | ||||
| 	for (size_t i = 0; i < env_count; i++) | ||||
| 		new_envp[i] = environ[i]; | ||||
| 	new_envp[env_count] = string; | ||||
| 	new_envp[env_count + 1] = nullptr; | ||||
|  |  | |||
|  | @ -16,31 +16,12 @@ | |||
| #include <termios.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| char** __environ; | ||||
| extern char** environ __attribute__((weak, alias("__environ"))); | ||||
| extern "C" char** environ; | ||||
| 
 | ||||
| extern "C" void _init_libc(char** _environ) | ||||
| { | ||||
| 	static bool is_initialized = false; | ||||
| 	if (is_initialized) | ||||
| 		return; | ||||
| 	is_initialized = true; | ||||
| 
 | ||||
| 	if (!_environ) | ||||
| 		return; | ||||
| 
 | ||||
| 	size_t env_count = 0; | ||||
| 	while (_environ[env_count]) | ||||
| 		env_count++; | ||||
| 
 | ||||
| 	environ = (char**)malloc(sizeof(char*) * env_count + 1); | ||||
| 	for (size_t i = 0; i < env_count; i++) | ||||
| 	{ | ||||
| 		size_t bytes = strlen(_environ[i]) + 1; | ||||
| 		environ[i] = (char*)malloc(bytes); | ||||
| 		memcpy(environ[i], _environ[i], bytes); | ||||
| 	} | ||||
| 	environ[env_count] = nullptr; | ||||
| 	if (::environ == nullptr) | ||||
| 		::environ = environ; | ||||
| } | ||||
| 
 | ||||
| void _exit(int status) | ||||
|  |  | |||
|  | @ -857,16 +857,27 @@ static LoadedElf& load_elf(const char* path, int fd) | |||
| 	return elf; | ||||
| } | ||||
| 
 | ||||
| static void call_init_libc(LoadedElf& elf, char** envp) | ||||
| static void initialize_environ(char** envp) | ||||
| { | ||||
| 	const auto* _init_libc = find_symbol(elf, "_init_libc"); | ||||
| 	if (_init_libc == nullptr) | ||||
| 	uintptr_t environ = SYM_NOT_FOUND; | ||||
| 	for (size_t i = 0; i < s_loaded_file_count; i++) | ||||
| 	{ | ||||
| 		const auto* match = find_symbol(s_loaded_files[i], "environ"); | ||||
| 		if (match == nullptr) | ||||
| 			continue; | ||||
| 		if (environ == SYM_NOT_FOUND || ELF_ST_BIND(match->st_info) != STB_WEAK) | ||||
| 			environ = s_loaded_files[i].base + match->st_value; | ||||
| 		if (ELF_ST_BIND(match->st_info) != STB_WEAK) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (environ == SYM_NOT_FOUND) | ||||
| 		return; | ||||
| 	using _init_libc_t = void(*)(char**); | ||||
| 	reinterpret_cast<_init_libc_t>(elf.base + _init_libc->st_value)(envp); | ||||
| 
 | ||||
| 	*reinterpret_cast<char***>(environ) = envp; | ||||
| } | ||||
| 
 | ||||
| static void call_init_funcs(LoadedElf& elf, char** envp, bool skip) | ||||
| static void call_init_funcs(LoadedElf& elf, bool is_main_elf) | ||||
| { | ||||
| 	if (elf.has_called_init) | ||||
| 		return; | ||||
|  | @ -879,11 +890,12 @@ static void call_init_funcs(LoadedElf& elf, char** envp, bool skip) | |||
| 			if (dynamic.d_tag == DT_NULL) | ||||
| 				break; | ||||
| 			if (dynamic.d_tag == DT_NEEDED) | ||||
| 				call_init_funcs(*reinterpret_cast<LoadedElf*>(dynamic.d_un.d_ptr), envp, false); | ||||
| 				call_init_funcs(*reinterpret_cast<LoadedElf*>(dynamic.d_un.d_ptr), false); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (elf.has_called_init || skip) | ||||
| 	// main executable calls its init functions in _start
 | ||||
| 	if (elf.has_called_init || is_main_elf) | ||||
| 		return; | ||||
| 
 | ||||
| 	using init_t = void(*)(); | ||||
|  | @ -892,10 +904,7 @@ static void call_init_funcs(LoadedElf& elf, char** envp, bool skip) | |||
| 	for (size_t i = 0; i < elf.init_arraysz / sizeof(init_t); i++) | ||||
| 		reinterpret_cast<init_t*>(elf.init_array)[i](); | ||||
| 
 | ||||
| 	if (strcmp(elf.path, "/usr/lib/libc.so") == 0) | ||||
| 		call_init_libc(elf, envp); | ||||
| 
 | ||||
| 	elf.has_called_init = true; | ||||
| } | ||||
| 
 | ||||
| extern "C" | ||||
|  | @ -922,6 +931,7 @@ int _entry(int argc, char** argv, char** envp, int fd) | |||
| 	fini_random(); | ||||
| 
 | ||||
| 	relocate_elf(elf, true); | ||||
| 	call_init_funcs(elf, envp, true); | ||||
| 	initialize_environ(envp); | ||||
| 	call_init_funcs(elf, true); | ||||
| 	call_entry_point(argc, argv, envp, elf.base + elf.file_header.e_entry); | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue