功能指针
我发现在合法的早期阶段没有办法使用ENV。分辨率函数甚至比PREINIT_ARRAY函数更早地在链接器中运行。解决此问题的唯一法律方法是使用功能指针并确定在.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 inners
GLIBC的Linker LD包含一个本地符号 _environ 它是初始化的,但是很难提取它。我发现了另一种方式,但这有点棘手,而且不可靠。
在Linker的入口点 _开始 只有堆栈是初始化的。程序参数和环境价值通过堆栈发送到该过程。参数按以下顺序存储:
argc,argv,argv + 1,...,argv + argc -1,null,env ...
Linker 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")));