Funktionszeiger
Ich fand keine Möglichkeit, Env im frühen Stadium legal zu verwenden. Die Resolver -Funktion wird noch früher in Linker ausgeführt, als Preinit_array -Funktionen. Die einzige rechtliche Möglichkeit, dies zu beheben, besteht darin, den Funktionszeiger zu verwenden und zu entscheiden, welche Funktion in der Funktion des Abschnitts .preinit_array verwendet werden soll:
extern char** environ;
int(*f)();
void preinit(int argc, char **argv, char **envp) {
f = f1;
environ = envp; // actually, it is done a bit later
char *v = getenv("TOTO");
if (v && strcmp(v, "ok") == 0) {
f = f2;
}
}
__attribute__((section(".preinit_array"))) typeof(preinit) *__preinit = preinit;
ifunc & gnu ld Inners
Der Linker LD von Glibc enthält ein lokales Symbol _Environ Und es wird initialisiert, aber es ist ziemlich schwierig, es zu extrahieren. Es gibt einen anderen Weg, den ich gefunden habe, aber es ist ein bisschen schwierig und ziemlich unzuverlässig.
Bei Linkers Einstiegspunkt _Anfang Nur Stack wird initialisiert. Programmargumente und Umgebungswerte werden über Stack an den Prozess gesendet. Argumente werden in der folgenden Reihenfolge gespeichert:
argc, argv, argv + 1, ..., argv + argc - 1, null, env ...
Linker LD teilt ein globales Symbol _dl_argv, die auf diesen Ort auf dem Stapel hinweist. Mit Hilfe können wir alle notwendigen Variablen extrahieren:
extern char** environ;
extern char **_dl_argv;
char** get_environ() {
int argc = *(int*)(_dl_argv - 1);
char **my_environ = (char**)(_dl_argv + argc + 1);
return my_environ;
}
typeof(f1) * resolve_f() {
environ = get_environ();
const char *var = getenv("TOTO");
if (var && strcmp(var, "ok") == 0) {
return f2;
}
return f1;
}
int f() __attribute__((ifunc("resolve_f")));