Puntero de funciones
No encontré ninguna forma de usar Env en la etapa temprana legalmente. La función de resolución se ejecuta en enlazador incluso antes, que las funciones preinit_array. La única forma legal de resolver esto es usar el puntero de la función y decidir qué función usar en la función .Preinit_Array:
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 y gnu ld Inners
El enlazador de GLIBC LD contiene un símbolo local _reinar Y se inicializa, pero es bastante difícil extraerlo. Hay otra forma en que encontré, pero es un poco complicado y poco confiable.
En el punto de entrada de Linker _comienzo Solo se inicializa la pila. Los argumentos del programa y los valores ambientales se envían al proceso a través de la pila. Los argumentos se almacenan en el siguiente orden:
Argc, argv, argv + 1, ..., argv + argc - 1, nulo, env ...
Linker Ld comparte un símbolo global _dl_argv, que apunta a este lugar en la pila. Con la ayuda, podemos extraer todas las variables necesarias:
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")));