Frage

Der IFUNC -Mechanismus in den neuesten ELF -Tools unter (zumindest) Linux ermöglicht die Auswahl einer Implementierung einer Funktion zur Laufzeit. Schauen Sie sich das IUNC -Attribut in der GCC -Dokumentation an, um eine detailliertere Beschreibung zu erhalten: http://gcc.gnu.org/onlinedocs/gcc/function-attributes.htmlEine andere Beschreibung des Ifunc -Mekanismus: http://www.agner.org/optimize/blog/read.php?i=167

Ich möchte meine Implementierung je nach Wert einer Umgebungsvariablen auswählen. Meine Experimente zeigen mir jedoch, dass die LIBC (zumindest der Teil der Umgebung) noch nicht initialisiert wird, wenn die Resolver -Funktion ausgeführt wird. Die klassischen Schnittstellen (externes Zeichen ** Environ oder Getenv ()) funktionieren also nicht.

Weiß jemand, wie jemand in sehr frühem Stadium auf die Umgebung eines Programms in Linux zugreifen kann? Die Umgebung wird vom Kernel beim Execve (2) -Systemanruf eingerichtet, sodass er bereits bei der frühen Initialisierung irgendwo (aber genau?) Im Programmadressenraum befindet.

Vielen Dank im Voraus Vincent

Programm zum Testen:

#include <stdio.h>
#include <stdlib.h>

extern char** environ;
char** save_environ;
char* toto;
int saved=0;

extern int fonction ();

int fonction1 () {
return 1;
}

int fonction2 () {
return 2;
}

static typeof(fonction) * resolve_fonction (void) {
saved=1;
save_environ=environ;
toto=getenv("TOTO");
/* no way to choose between fonction1 and fonction2 with the TOTO envvar */
return fonction1;
}

int fonction () __attribute__ ((ifunc ("resolve_fonction")));

void print_saved() {
printf("saved: %dn", saved);
if (saved) {
printf("prev environ: %pn", save_environ);
printf("prev TOTO: %sn", toto);
}
}

int main() {

print_saved();
printf("main environ: %pn", environ);
printf("main environ[0]: %sn", environ[0]);
printf("main TOTO: %sn", getenv("TOTO"));
printf("main value: %dn", fonction());

return 0;
}

Zusammenstellung und Ausführung:

$ gcc -Wall -g ifunc.c -o ifunc
$ env TOTO=ok ./ifunc
saved: 1
prev environ: (nil)
prev TOTO: (null)
main environ: 0x7fffffffe288
main environ[0]: XDG_VTNR=7
main TOTO: ok
main value: 1
$ 

In der Resolver -Funktion, environ ist null und getenv("TOTO") Gibt NULL zurück. In dem main Funktion, die Informationen sind hier.

War es hilfreich?

Lösung

Funktionszeiger

Ich fand keine Möglichkeit, Env im frühen Stadium legal zu verwenden. Die Resolver -Funktion wird noch früher in Linker ausgeführt, als Preinit_array -Funktionen. Die einzige rechtliche Möglichkeit, dies zu beheben, besteht darin, den Funktionszeiger zu verwenden und zu entscheiden, welche Funktion in der Funktion des Abschnitts .preinit_array verwendet werden soll:

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

Der Linker LD von Glibc enthält ein lokales Symbol _Environ Und es wird initialisiert, aber es ist ziemlich schwierig, es zu extrahieren. Es gibt einen anderen Weg, den ich gefunden habe, aber es ist ein bisschen schwierig und ziemlich unzuverlässig.

Bei Linkers Einstiegspunkt _Anfang Nur Stack wird initialisiert. Programmargumente und Umgebungswerte werden über Stack an den Prozess gesendet. Argumente werden in der folgenden Reihenfolge gespeichert:

argc, argv, argv + 1, ..., argv + argc - 1, null, env ...

Linker LD teilt ein globales Symbol _dl_argv, die auf diesen Ort auf dem Stapel hinweist. Mit Hilfe können wir alle notwendigen Variablen extrahieren:

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")));
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top