مؤشر وظيفة
لم أجد أي وسيلة لاستخدام ENV في المرحلة المبكرة بشكل قانوني. تعمل دالة Resolver في Linker حتى وقت سابق ، من وظائف 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 على رمز محلي _environ ويتم تهيئتها ، ولكن من الصعب استخراجها. هناك طريقة أخرى وجدتها ، لكنها صعبة بعض الشيء وغير موثوق بها إلى حد ما.
عند نقطة دخول Linker _بداية تتم تهيئة المكدس فقط. يتم إرسال وسيطات البرنامج والقيم البيئية إلى العملية عبر Stack. يتم تخزين الحجج بالترتيب التالي:
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")));