Pointeur de fonction
Je n'ai trouvé aucun moyen d'utiliser Env à un stade précoce légalement. La fonction Resolver s'exécute dans Linker encore plus tôt, que les fonctions preinit_array. Le seul moyen légal de résoudre ceci est d'utiliser le pointeur de fonction et de décider quelle fonction utiliser en fonction de .preinit_array section:
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
Linker LD de GLIBC contient un symbole local _environ Et il est initialisé, mais il est assez difficile de l'extraire. Il y a une autre façon que j'ai trouvée, mais c'est un peu délicat et plutôt peu fiable.
Au point d'entrée de Linker _début Seule la pile est initialisée. Les arguments du programme et les valeurs environnementales sont envoyées au processus via la pile. Les arguments sont stockés dans l'ordre suivant:
Argc, argv, argv + 1, ..., argv + argc - 1, null, env ...
Linker LD partage un symbole mondial _dl_argv, qui pointe vers cet endroit sur la pile. Avec l'aide, nous pouvons extraire toutes les variables nécessaires:
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")));