Dynamische Funktionszeiger



  • hmm. naja. nachdem ich den thread nochmal durchlas, kam mir die frage auf: wieso meinen einige hier, dass es mit c nicht möglich sei, funktionen bei ihrem namen aufzurufen?

    es geht, ist aber nicht portable und setzt voraus, dass eine vollständige symboltabelle für die internen funktionen existiert. für die so/dll-funktionen hat man eh immer eine.
    hier ein beispiel für unixoide systeme (sollte auf allen so laufen):

    #include <stdlib.h>
    #include <stdio.h>
    #include <dlfcn.h>
    
    int test()
    {
    	printf("test() wurde aufgerufen.\n");
    	return 0;
    }
    
    int main()
    {
    	void* handle;
    	handle = dlopen(0,RTLD_LAZY); //öffnen der globale symbol tabelle
    	if (!handle)
    	{
                    //das kann eigentlich nicht passieren.
    		printf("Unable to open global symbol table.\n"); 
    		exit(0);
    	}
    	((int(*)())dlsym(handle,"test"))(); //hier der aufruf der funktion "test" mittels ihres namens.
    //EDIT ich sollte noch darauf hinweisen, dass man natürlich auch alle per
    //so eingebunden funktionen aufrufen kann:
    	((int(*)())(((void*(*)(void*,const char*))dlsym(handle,"dlsym"))(handle,"test")))();
    	dlclose(handle); //saubere schweinchen räumen hinterher wieder auf
    	return 0;
    }
    

    kompilierbar bspw so: gcc main.c -ldl -rdynamic
    das -rdynamic ist wichtig, sonst kann es mit internen funktionen oder anderen ungenutzten funktionen schief gehen.

    ist alles in allem schönes sauberes c mit ein bisschen posix-spaß.

    ich nehme mal an, dass es unter windows etwas äquivalentes zu dlopen und co gibt. da kenne ich mich aber nicht so aus.

    achja: wenn irgendjemand auf die hirnverbrannte idee kommt, dass tatsächlich als alternative zu nutzen, werde ich ihm im traum erscheinen, bis er es wieder lässt. 😉



  • Ja, unter Windows würde sowas auch gehen:
    Du schreibst dir alle benötigten Funktionen in eine extra DLL und machst dann ungefähr sowas:

    ...
    std::string fn_name;
    read_fn_name_from_db(fn_name);
    
    HMODULE lib_handle = LoadLibrary("myfunctions.dll");
    my_fn = (void (*)(void))GetProcAddress(lib_handle, fn_name.c_str());
    
    (my_fn)();
    ...
    

    Aber wie ghorst schon schreibt: Das ist böse 😃

    Grüße,

    Martin



  • sicher das es keine möglichkeit gibt auf die symboltabelle des programms zuzugreifen? würde mich jetzt wundern. (oder habe ich dich nur durch die nutzung von dlopen verwirrt? unter unix ist mit dem paramter 0 anstelle des namens einer lib gemeint, dass man die symboltabelle des aktuellen programms inklusive aller gelandenen libs haben will.)



  • Bei DLLs ist das ja unumgänglich, aber es gibt IMO gar keinen technischen Grund, warum es eine Symboltabelle des Programms geben sollte.



  • es gibt sie zwangsweise beim linken und sie werden normalerweise auch nicht entfernt, da sie bspw für die einsprungsadresse genutzt werden. wie bei main oder dem heiß geliebten wndproc. auch gibt es ein paar tricks bei denen es notwendig ist, von einer dll auf prozeduren aus dem hauptprogramm zuzugreifen.
    (wenn ich mich dumpf an meine windows-zeiten erinnere, hatte die programme da alle symboltabellen.)

    die frage ist daher eher, wie man darauf zugreift?



  • Man braucht genau einen Einsprungpunkt. Für WndProc und sonstige Callbacks reichen die aufgelösten Adressen, dazu braucht man keine Namen. Für die main natürlich auch nicht.
    Tricks, bei denen man von der DLL aufs Hauptprogramm zugreift, erledigt man, indem man der DLL die Adressen der Funktionen übergibt. Wieder: Callback.
    Ich hab zwar nicht viel Ahnung von der Winapi, und es mag sein, dass es aus ganz obskuren Gründen diese Symboltabellen wirklich gibt. Aber eine technische Notwendigkeit seh ich nach wie vor nicht. Unter Unix scheinen das ja die Debug-Symbole zu sein, die man auch ohne Probleme wegstrippen kann (womit dann auch dlsym fehlschlägt.)



  • du kannst die meisten wegstrippen. ein paar bleiben über. wenn du pic, was manchmal auch für executables nützlich sein kann, haben willst, bleiben alle, die exportierte und ähnliche funktionen betreffen, über, da hier die einsprungadressen für die einzelnen routinen erst bei programmstart ermittelt werden.

    absolut notwendig ist die symboltabelle nicht, das ist keine frage. nur ist sie halt hinreichend oft vorhanden und wer so einen murkscode schreiben will, der wird schon die kontrolle über sein hauptprogramm haben...

    dlsym wird nach dem strippen für alle aufrufe fehlschlagen (edit: das nächstemal erst probieren... das ganze funktioniert auch, nachdem man die datei gestript hat.), die keinen eintrag haben, aus dem gleichen grund ist auch das kompilieren mit -rdynamic wichtig, da sonst schon die einträge für nicht benutzte funktionen fehlen würden.

    achja: wndproc ist kein callback im klassischen sinne und für main brauchst du entweder einen festen oder einen dynamischen einsprungpunkt. letzterer aus der symboltabelle.

    zu den debugsymbolen: die sind was anderes. die umfassen so lustigen sachen wie variablen namen und codezeilen.



  • Bashar schrieb:

    Ich hab zwar nicht viel Ahnung von der Winapi, und es mag sein, dass es aus ganz obskuren Gründen diese Symboltabellen wirklich gibt. Aber eine technische Notwendigkeit seh ich nach wie vor nicht.

    in DLLs (hat ja schon jemand geschrieben) stecken tatsächlich meistens die namen drin (oder eine nummer), allerdings sehen diese namen etwas anders aus (eine funktion 'int hallo (int x)' steht in der dll z.b. als _hallo@4). irgendwie müssen die funktionen einer dll ja gefunden werden.
    bei normalen 'exen' findet man nur die namen, wenn debug-info mit drin stecken.
    🙂



  • Undertaker schrieb:

    bei normalen 'exen' findet man nur die namen, wenn debug-info mit drin stecken.

    wie ich gerade mal aus langeweile festellte: du irrst. mit und ohne debug-info sind symbolnamen enthalten...



  • ghorst schrieb:

    Undertaker schrieb:

    bei normalen 'exen' findet man nur die namen, wenn debug-info mit drin stecken.

    wie ich gerade mal aus langeweile festellte: du irrst. mit und ohne debug-info sind symbolnamen enthalten...

    es sind namen von funktionen aus externen DLLs, z.b. 'kernel32.dll' drin, aber nicht die namen von eigenen funktionen.
    🙂



  • also ich finde in exe dateien (auch solchen ohne debug informationen) diverse einträge, die eindeutig zu den programmen gehören...

    btw. ich hasse coff/pe.



  • ghorst schrieb:

    also ich finde in exe dateien (auch solchen ohne debug informationen) diverse einträge, die eindeutig zu den programmen gehören...

    ja, irgendwelche strings und konstantes zeugs um variablen zu initialisieren, aber funktionsnamen sollten nicht drin sein (es sei denn, du machst was falsch und hast doch debug-infos mit dabei).
    🙂



  • ich kann eine symboltabelle von einer stringtabelle unterscheiden... dazu weiß ich sogar auch noch, wie man debug-infos ein- und abschaltet.


Anmelden zum Antworten