Ich komme für ein bisschen meiner Sommerforschung in Kernel-Arbeit. Wir versuchen, in bestimmten RTT-Berechnungen Änderungen am TCP vorzunehmen. Was ich tun möchte, ist die Ersetzung der Auflösung einer der Funktionen in tcp_input.c zu einer Funktion von einem dynamisch geladenen Kernel-Modul. Ich denke, dies würde das Tempo verbessern, in dem wir die Modifikation entwickeln und verteilen können.Kann ich eine Linux-Kernel-Funktion durch ein Modul ersetzen?
Die Funktion, an der ich interessiert bin, wurde als statisch deklariert, allerdings habe ich den Kernel mit der Funktion nonstatic neu kompiliert und von EXPORT_SYMBOL exportiert. Dies bedeutet, dass die Funktion nun für andere Module/Teile des Kernels zugänglich ist. Ich habe dies durch "cat/proc/kallsyms" verifiziert.
Jetzt möchte ich in der Lage sein, ein Modul zu laden, das die Symboladresse von der ursprünglichen zu meiner dynamisch geladenen Funktion neu schreiben kann. Wenn das Modul entladen werden soll, würde es in ähnlicher Weise die ursprüngliche Adresse wiederherstellen. Ist das ein praktikabler Ansatz? Haben Sie alle Vorschläge, wie dies besser umgesetzt werden könnte?
Danke!
Gleiche wie Overriding functionality with modules in Linux kernel
Edit:
Dies war meine eventuelle Annäherung.
Da die folgende Funktion (die ich außer Kraft setzen wollte, und nicht exportiert wird):
static void internal_function(void)
{
// do something interesting
return;
}
ändern wie folgt:
static void internal_function_original(void)
{
// do something interesting
return;
}
static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);
Dies definiert die erwartete Funktionskennung stattdessen als einen Funktionszeiger (die kann auf ähnliche Weise aufgerufen werden), wobei auf die ursprüngliche Implementierung verwiesen wird. EXPORT_SYMBOL() macht die Adresse global zugänglich, so dass wir sie von einem Modul (oder einem anderen Kernel-Speicherort) aus modifizieren können.
Jetzt können Sie einen Kernel-Modul mit dem folgende Formular schreiben:
static void (*original_function_reference)(void);
extern void (*internal_function)(void);
static void new_function_implementation(void)
{
// do something new and interesting
// return
}
int init_module(void)
{
original_function_reference = internal_function;
internal_function = &new_function_implementation;
return 0;
}
void cleanup_module(void)
{
internal_function = original_function_reference;
}
Dieses Modul ersetzt die ursprüngliche Implementierung mit einer dynamisch geladenen Version. Nach dem Entladen wird die ursprüngliche Referenz (und Implementierung) wiederhergestellt. In meinem speziellen Fall habe ich einen neuen Schätzer für die RTT in TCP zur Verfügung gestellt. Mit einem Modul kann ich kleine Verbesserungen vornehmen und den Test neu starten, ohne den Kernel neu kompilieren und neu starten zu müssen.
Ich ging die Route, die Sie vorgeschlagen, beim Hinzufügen eines globalen Hooks. Es war einfach zu implementieren und lieferte genau das, was ich brauchte. Danke für die Information bezüglich der Symbolauflösung. Ich hatte keine Quelle gefunden, die eindeutig erklärte, wie und wann auf die Symboltabelle zugegriffen wurde (bei jedem Funktionsaufruf oder nur bei der Verknüpfung). Dies war ein nützlicher Ratschlag. –