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 <strings.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| #include <sys/syscall.h> | #include <sys/syscall.h> | ||||||
|  | #include <sys/weak_alias.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| #include <icxxabi.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(); | extern "C" __attribute__((weak)) void _fini(); | ||||||
| 
 | 
 | ||||||
|  | @ -516,27 +519,35 @@ int putenv(char* string) | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!environ) | 	if (!s_environ_malloced) | ||||||
| 	{ | 	{ | ||||||
| 		environ = (char**)malloc(sizeof(char*) * 2); | 		size_t env_count = 0; | ||||||
| 		if (!environ) | 		while (environ[env_count]) | ||||||
|  | 			env_count++; | ||||||
|  | 
 | ||||||
|  | 		char** new_environ = static_cast<char**>(malloc((env_count + 1) * sizeof(char*))); | ||||||
|  | 		if (new_environ == nullptr) | ||||||
| 			return -1; | 			return -1; | ||||||
| 		environ[0] = string; | 		for (size_t i = 0; i < env_count; i++) | ||||||
| 		environ[1] = nullptr; | 		{ | ||||||
| 		return 0; | 			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; | 	const char* eq_addr = strchr(string, '='); | ||||||
| 	for (int i = 0; string[i]; i++) | 	if (eq_addr == nullptr) | ||||||
| 		if (string[i] == '=') |  | ||||||
| 			cnt++; |  | ||||||
| 	if (cnt != 1) |  | ||||||
| 	{ | 	{ | ||||||
| 		errno = EINVAL; | 		errno = EINVAL; | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	int namelen = strchr(string, '=') - string; | 	size_t namelen = eq_addr - string; | ||||||
| 	for (int i = 0; environ[i]; i++) | 	for (int i = 0; environ[i]; i++) | ||||||
| 	{ | 	{ | ||||||
| 		if (strncmp(environ[i], string, namelen + 1) == 0) | 		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]) | 	while (environ[env_count]) | ||||||
| 		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) | 	if (new_envp == nullptr) | ||||||
| 		return -1; | 		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[i] = environ[i]; | ||||||
| 	new_envp[env_count] = string; | 	new_envp[env_count] = string; | ||||||
| 	new_envp[env_count + 1] = nullptr; | 	new_envp[env_count + 1] = nullptr; | ||||||
|  |  | ||||||
|  | @ -16,31 +16,12 @@ | ||||||
| #include <termios.h> | #include <termios.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| char** __environ; | extern "C" char** environ; | ||||||
| extern char** environ __attribute__((weak, alias("__environ"))); |  | ||||||
| 
 | 
 | ||||||
| extern "C" void _init_libc(char** _environ) | extern "C" void _init_libc(char** _environ) | ||||||
| { | { | ||||||
| 	static bool is_initialized = false; | 	if (::environ == nullptr) | ||||||
| 	if (is_initialized) | 		::environ = environ; | ||||||
| 		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; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void _exit(int status) | void _exit(int status) | ||||||
|  |  | ||||||
|  | @ -857,16 +857,27 @@ static LoadedElf& load_elf(const char* path, int fd) | ||||||
| 	return elf; | 	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"); | 	uintptr_t environ = SYM_NOT_FOUND; | ||||||
| 	if (_init_libc == nullptr) | 	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; | 		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) | 	if (elf.has_called_init) | ||||||
| 		return; | 		return; | ||||||
|  | @ -879,11 +890,12 @@ static void call_init_funcs(LoadedElf& elf, char** envp, bool skip) | ||||||
| 			if (dynamic.d_tag == DT_NULL) | 			if (dynamic.d_tag == DT_NULL) | ||||||
| 				break; | 				break; | ||||||
| 			if (dynamic.d_tag == DT_NEEDED) | 			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; | 		return; | ||||||
| 
 | 
 | ||||||
| 	using init_t = void(*)(); | 	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++) | 	for (size_t i = 0; i < elf.init_arraysz / sizeof(init_t); i++) | ||||||
| 		reinterpret_cast<init_t*>(elf.init_array)[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" | extern "C" | ||||||
|  | @ -922,6 +931,7 @@ int _entry(int argc, char** argv, char** envp, int fd) | ||||||
| 	fini_random(); | 	fini_random(); | ||||||
| 
 | 
 | ||||||
| 	relocate_elf(elf, true); | 	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); | 	call_entry_point(argc, argv, envp, elf.base + elf.file_header.e_entry); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue