Browse Source

Make some fixes to libc and linker to allow environ to be set before initializers run

K. Lange 3 years ago
parent
commit
b42bec5b70
2 changed files with 27 additions and 9 deletions
  1. 19 7
      libc/main.c
  2. 8 2
      linker/linker.c

+ 19 - 7
libc/main.c

@@ -52,9 +52,14 @@ DEFN_SYSCALL3(chown, SYS_CHOWN, char *, int, int);
 extern void _init();
 extern void _fini();
 
-char ** environ;
+char ** environ = NULL;
 int _environ_size = 0;
+char * _argv_0 = NULL;
 
+char ** __argv = NULL;
+extern char ** __get_argv(void) {
+	return __argv;
+}
 
 extern void __stdio_init_buffers(void);
 
@@ -65,13 +70,14 @@ void _exit(int val){
 	__builtin_unreachable();
 }
 
-char * _argv_0 = NULL;
+__attribute__((constructor))
+static void _libc_init(void) {
+	__stdio_init_buffers();
 
-void pre_main(int (*main)(int,char**), int argc, char * argv[]) {
 	unsigned int x = 0;
 	unsigned int nulls = 0;
 	for (x = 0; 1; ++x) {
-		if (!argv[x]) {
+		if (!__get_argv()[x]) {
 			++nulls;
 			if (nulls == 2) {
 				break;
@@ -79,12 +85,18 @@ void pre_main(int (*main)(int,char**), int argc, char * argv[]) {
 			continue;
 		}
 		if (nulls == 1) {
-			environ = &argv[x];
+			environ = &__get_argv()[x];
 			break;
 		}
 	}
-	_argv_0 = argv[0];
-	__stdio_init_buffers();
+	_argv_0 = __get_argv()[0];
+}
+
+void pre_main(int (*main)(int,char**), int argc, char * argv[]) {
+	if (!__get_argv()) {
+		__argv = argv;
+		_libc_init();
+	}
 	_init();
 	_exit(main(argc, argv));
 }

+ 8 - 2
linker/linker.c

@@ -368,8 +368,6 @@ static int object_relocate(elf_t * object) {
 				uintptr_t x = sym->st_value + object->base;
 				if (need_symbol_for_type(type) || (type == 5)) {
 					symname = (char *)((uintptr_t)object->dyn_string_table + sym->st_name);
-				}
-				if (((sym->st_shndx == 0) && need_symbol_for_type(type)) || (type == 5)) {
 					if (symname && hashmap_has(dumb_symbol_table, symname)) {
 						x = (uintptr_t)hashmap_get(dumb_symbol_table, symname);
 					} else {
@@ -554,6 +552,11 @@ static char * dlerror_ld(void) {
 	return this_error;
 }
 
+static void * _argv_value = NULL;
+static char * argv_value(void) {
+	return _argv_value;
+}
+
 typedef struct {
 	char * name;
 	void * symbol;
@@ -563,6 +566,7 @@ ld_exports_t ld_builtin_exports[] = {
 	{"dlsym", object_find_symbol},
 	{"dlclose", dlclose_ld},
 	{"dlerror", dlerror_ld},
+	{"__get_argv", argv_value},
 	{NULL, NULL},
 };
 
@@ -577,6 +581,8 @@ int main(int argc, char * argv[]) {
 		file = argv[2];
 	}
 
+	_argv_value = argv+arg_offset;
+
 	char * trace_ld_env = getenv("LD_DEBUG");
 	if ((trace_ld_env && (!strcmp(trace_ld_env,"1") || !strcmp(trace_ld_env,"yes")))) {
 		__trace_ld = 1;