기능 포인터
초기 단계에서 합법적으로 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 이너
GLIBC의 링커 LD에는 로컬 기호가 포함되어 있습니다 _environ 그리고 초기화되었지만 추출하기가 다소 어렵습니다. 내가 찾은 또 다른 방법이 있지만 약간 까다 롭고 다소 신뢰할 수 없습니다.
링커의 진입 점에서 _시작 스택 만 초기화됩니다. 프로그램 인수 및 환경 값은 스택을 통해 프로세스로 전송됩니다. 인수는 다음 순서로 저장됩니다.
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")));