関数ポインター
私は法的に初期段階でENVを使用する方法を見つけませんでした。 Resolver関数は、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のリンカーLDにはローカルシンボルが含まれています _環境 初期化されていますが、抽出するのはかなり困難です。私が見つけた別の方法がありますが、それは少しトリッキーで、かなり信頼できません。
リンカーのエントリポイントで _始める スタックのみが初期化されます。プログラムの引数と環境値は、スタックを介してプロセスに送信されます。引数は次の順序で保存されます。
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")));