PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Shared Lib Problem



schoppenhauer
19-06-2007, 02:43
Hallo.

Ich versuche mich grade an dynamic linking mit C unter Linux. Ich mache zum Test folgendes:

Eine Datei dltest.c mit dem Inhalt


#include <stdio.h>

void hello () {
printf ("Hello World.\n");
}


Die ich compiliere mit den Kommandos

$ gcc -c -fPIC -DPIC dltest.c
$ gcc -shared -Wall dltest.o -lc -Wl,-soname -o dltest.so

Eine Datei test.c mit dem Inhalt


#include <stdio.h>
#include <dlfcn.h>

int main (int argc, char* argv[]) {
if (argc != 3) {
printf("Fehler");
return -1;
}
void* handle = dlopen(argv[1], RTLD_LAZY);
if (!handle) printf("Could not load %s\nError:%s\n", argv[1], dlerror());

typedef void (*hello_t)();
dlerror();
hello_t hello = (hello_t) dlsym (handle, argv[2]);
const char* dlsym_error = dlerror();
if (dlsym_error) {
printf("Fehler: %s\n", dlsym_error);
dlclose(handle);
return -1;
}
hello();

dlclose(handle);

return 0;
}

die ich compiliere mit

$ gcc -o test test.c -ldl

Alles quick and dirty, sollte nur mal ein Test sein, ob das Ganze funktioniert.

So. Nun hatte ich mir erhofft, dass der Aufruf


./test dltest.so hello

Irgendwie die entsprechende Funktion ausführt. Das ist leider nicht so, ich bekomme die Fehlermeldung


Fehler: ./test: undefined symbol: hello
Speicherzugriffsfehler

Bleibt die Frage: Was mache ich falsch. Sicherlich ein Anfängerfehler, aber keine Ahnung.

peschmae
19-06-2007, 07:52
Also bei mir funktioniert das - vorausgesetzt natürlich die Bibliothek dltest.so ist im Suchpfad für Bibliotheken (entweder in /etc/ld.so.conf(.d) oder in der Umgebungsvariable LD_LIBRARY_PATH)



peschmae@sid:/tmp/dl$ ./test dltest.so hello
Could not load dltest.so
Error:dltest.so: cannot open shared object file: No such file or directory
Fehler: ./test: undefined symbol: hello
Speicherzugriffsfehler
peschmae@sid:/tmp/dl$ LD_LIBRARY_PATH=. ./test dltest.so hello
Hello World.
peschmae@sid:/tmp/dl$


MfG Peschmä

schoppenhauer
19-06-2007, 15:22
Ah. Ich Idiot. Wenn ich ./dltest.so angebe, gehts auch... Aber seltsam... Geht es garantiert, wenn man den absoluten Pfad angibt, auch ohne dass die LD-Paths gesetzt sind, oder geht das nur zufaellig bei mir?

peschmae
19-06-2007, 16:32
Ja, laut der manpage soll das auch gehen mit absoluten (oder auch mit relativen) Pfadnamen.

Kommt natürlich immer drauf an was genau du willst, aber es ist sicher nicht üblich hier absolute Pfadnamen zu verwenden und damit dem System quasi vorzuschreiben wo genau die Bibliothek zu liegen hat. Verschiedene Systeme haben da verschiedene Konventionen und mit absoluten Pfaden machst du den Paketierern nur das Leben unnötig schwer.

MfG Peschmä

schoppenhauer
19-06-2007, 16:39
Nunja. Ich will das fuer eine Art Plugin-System (ansonsten wuerd ich das Prog gleich gegen die Library linken, und mir nicht die Arbeit mit dlsym machen).

Hab mir eigentlich gedacht, dass alle .so-Dateien in einem Verzeichnis liegen, oder in ner Konfigurationsdatei stehen oder so. Aber das wird dann schon gehen, bzw. wenn das nicht geht, kann ich das Prog dann immernoch anpassen.

Hm. Noch zwei dumme Fragen.

Zum Einen wollt ich fragen, ob man irgendwie feststellen kann, welche argumente eine Funktion, die ich mit dlsym hole, erwartet, bzw. wenigstens, wie viele Bytes oder so (ich weiss ja nicht, wie das ABI genau aussieht, ob da genauere Infos gespeichert werden).

Bzw. ob es nen fehler gibt, wenn die Signatur meines Funktionspointers falsch ist.

Zum Anderen... Kann man das auch aus anderen Input-Streams oder so machen, also muss es unbedingt eine .so-file sein, die ich lade, oder kann ich meinetwegen auch ueber ein char* oder void* den binaercode der .so-file irgendeiner funktion uebergeben (im grunde sollte das ja gehen, sobald die architektur stimmt, nachdem die dateien ja so oder so geladen werden muessen).

peschmae
20-06-2007, 08:27
Zum Einen wollt ich fragen, ob man irgendwie feststellen kann, welche argumente eine Funktion, die ich mit dlsym hole, erwartet, bzw. wenigstens, wie viele Bytes oder so (ich weiss ja nicht, wie das ABI genau aussieht, ob da genauere Infos gespeichert werden).

Bzw. ob es nen fehler gibt, wenn die Signatur meines Funktionspointers falsch ist.


Das kannst du eigentlich problemlos selber testen ;)
(Btw. ja, es gibt einen Fehler)



Zum Anderen... Kann man das auch aus anderen Input-Streams oder so machen, also muss es unbedingt eine .so-file sein, die ich lade, oder kann ich meinetwegen auch ueber ein char* oder void* den binaercode der .so-file irgendeiner funktion uebergeben (im grunde sollte das ja gehen, sobald die architektur stimmt, nachdem die dateien ja so oder so geladen werden muessen).

Ich glaube nicht dass das möglich ist. Nicht wegen prinzipellen Problemen sondern weils halt keine dl...-Funktion gibt die das macht.

MfG Peschmä

schoppenhauer
20-06-2007, 13:32
Das kannst du eigentlich problemlos selber testen ;)
(Btw. ja, es gibt einen Fehler)Naja, die Frage ist ja eher, wie findet man die Signatur raus, bzw. gibt es da ne Moeglichkeit? Also wenns nen Fehler gibt, muss die Library ja auch irgendwo speichern, welche Argumente sie bekommt. Dann sollte man das doch auch rausfinden koennen.


Ich glaube nicht dass das möglich ist. Nicht wegen prinzipellen Problemen sondern weils halt keine dl...-Funktion gibt die das macht.Naja, das kann man dann ja noch schreiben, vermutlich reicht es sogar, ein unix-domain-socket oder eine fifo zu erstellen, und das dann dlopen zu uebergeben, aber das kann ich dann ja ggf. probieren.
Oder eben die Dateien in einen Tempordner zu speichern. Aber wahrscheinlich brauch ich das sowieso nicht.

Danke jedenfalls soweit. Hat mir schon sehr geholfen.

peschmae
20-06-2007, 17:40
Naja, die Frage ist ja eher, wie findet man die Signatur raus, bzw. gibt es da ne Moeglichkeit? Also wenns nen Fehler gibt, muss die Library ja auch irgendwo speichern, welche Argumente sie bekommt. Dann sollte man das doch auch rausfinden koennen.


Wozu genau? Wenn du eine Funktion ausführen willst musst du ja eh wissen was für eine Bedeutung die jeweiligen Argumente haben bzw. was du da reintun musst...

Wüsste jetzt gerade von keiner libc-Funktion die das macht. Das Programm objdum kann diesbezüglich z.B. was auslesen, aber afaik ausschliesslich wenn die Debug-Option beim Kompilieren aktiviert ist.

MfG Peschmä

schoppenhauer
20-06-2007, 18:15
Wozu genau? Wenn du eine Funktion ausführen willst musst du ja eh wissen was für eine Bedeutung die jeweiligen Argumente haben bzw. was du da reintun musst...Nunja. Nicht unbedingt. Also ich persönlich hab dadurch ggf. nur ne Kontrollierende Anwendung, aber... Man nehme mal z.B. Script-Engines her, die Funktionen aus Shared Libs ansteuern können. Die müssen ja auch irgendwie wissen, welche Signaturen deren Funktionen haben. Und Compiler und Linker letztendlich auch. Und naja... Keine Ahnung. Also ich persönlich hab dafür wie gesagt kaum eine Anwendung, aber, Java Reflections (das ist ja das direkte Java-Adäquat dazu) bieten sowas z.B. auch - natürlich ist Java wesentlich stärker abstrahiert, das heißt, man kann sowas auch wirklich leichter, soweit ich weiß ist bei C im Wesentlichen festgelegt, wie viele Bytes übergeben werden, und der Rest wird vom Compiler erledigt (da müsst ich mal probieren, ob es nen Unterschied macht, ob man void a(int) oder void a(char, char, char, char) macht - also ob er den Fehler merkt - wenn nicht orientiert er sich wohl nur an der Byte-Zahl). Jedenfalls... Irgendwas muss anscheinend eingespeichert sein, und sobald irgendwas eingespeichert ist, ist es ja auch interessant, wie man es auslesen kann.

Aber wie gesagt, das ist nur Interesse, brauchen tu ich es sicher nicht, bzw. wenn ich sowas bräuchte, dann müsste ich halt mein Plugin-System entsprechend abstrahieren.

anda_skoa
20-06-2007, 19:29
Du könntest eines der Systeme benutzen, die in C mittels Zusatzinformationen etwas ähnliches wie Reflection bewerkstelligen, also zB das GLib Objektmodell GObject.

Ciao,
_

peschmae
20-06-2007, 21:56
Jedenfalls... Irgendwas muss anscheinend eingespeichert sein, und sobald irgendwas eingespeichert ist, ist es ja auch interessant, wie man es auslesen kann.

Achso, *irgendwo* ist das natürlich schon gespeichert. Da müsste man sich an der Stelle wohl die Dokus zum ELF-Format reinziehen.

Meine Linksammlung erwähnt auch noch das hier. Habs aber nie durchgelesen: http://www.iecc.com/linker/

MfG Peschmä