Указатель функций
Я не нашел никакого способа использовать ENV на ранней стадии на законных основаниях. Функция Resolver работает в линкере даже раньше, чем функции 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 & gnu ld insers
LD LD Glibc содержит локальный символ _environ И это инициализируется, но его довольно сложно извлечь. Есть другой способ, который я нашел, но это немного сложно и довольно ненадежно.
В точке входа в линкер _Начало Только стек инициализируется. Аргументы программы и экологические значения отправляются в процесс через стек. Аргументы хранятся в следующем порядке:
argc, argv, argv + 1, ..., argv + argc - 1, null, env ...
Линкер LD делится глобальным символом _dl_argv, что указывает на это место на стеке. С помощью этого мы можем извлечь все необходимые переменные:
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")));