Frage zu Static Library in C

Wenn man in C ein Programm mit einer static library verbindet, wird dann der gesamte Inhalt oder nur das was gebraucht wird von den jeweiligen relocatable object files ''importiert''.

Habe den standardmaessigen cmd genutzt:

$ gcc main.o –L/path/to/lib/folder –lname –o executableName

Besten Dank fuer eure Antworten im Vorraus.
 
Es kommt auf den Linker drauf an. Traditionell haben Linker stumpf alles gelinkt, was man ihnen vorgeworfen hat. Neuere Linker, wobei neuer hier auch schon mindestens die letzten 15 Jahre sind, sind intelligenter und linken nur Dinge, welche auch wirklich benötigt werden. Bei GNU ld und den dazu kompatiblen Linkern spielen zusätzlich noch einige Optionen wie --whole-archive und --start-group ... --end-group mit rein.
 
Es kommt auf den Linker drauf an. Traditionell haben Linker stumpf alles gelinkt, was man ihnen vorgeworfen hat. Neuere Linker, wobei neuer hier auch schon mindestens die letzten 15 Jahre sind, sind intelligenter und linken nur Dinge, welche auch wirklich benötigt werden. Bei GNU ld und den dazu kompatiblen Linkern spielen zusätzlich noch einige Optionen wie --whole-archive und --start-group ... --end-group mit rein.
Verhaelt sich das denn gleich wie beiner dynamic library?

Denn in einem Buch habe ich gelesen das nur der benoetigte Teil in den ram (weiss nicht genau ob ram oder memory der cpu) importiert wird, bei jedem Prozess der gestartet wird. Aber im Internet und auf Youtube finde ich verhaeuft die Aussage das die ganze dynamic library in den ram geladen wird und das alle prozesse darauf zugreifen koennen
.
 
Was zur Laufzeit im RAM liegt und was auf der Platte ist so allgemein nicht feststellbar. Stichwort Paging. "Virtuell" ist natürlich die komplette Shared Library geladen, liegt aber nicht zwangsläufig gleich im RAM.

Und ja, im Regelfall wird eine Shared-Library nur einmal geladen. Zumindest der "Nur-Lesen" Bereich wie eben der Code.
 
Müsste, wenn die ganze Lib gelinkt wird, das (statische) Executable nicht auch um diesen Betrag anwachsen - in dem Fall könnte man es mit: einmal dynamisch/einmal statisch linken feststellen?

Nach meinem Verständnis ist die Aussage im YT Video welche du ansprachst, korrekt: eine Lib wird einmal in den Speicher geladen, und dynamisch gelinkte Executables bedienen sich dann daraus - die statischen haben ja alles "selber an Bord"; ich lerne aber gerne dazu, falls das anders sein sollte.
 
Es hängt auch davon ab, wie die Library kompiliert wurde. Entsprechende Stackoverflow-Antwort. Der Linker wird keine Tiefenanalyse einer statischen Library machen, um nur den Maschinencode rauszupopeln, der auch benutzt wird (geht auch gar nicht). Wenn die Library aber entsprechend kompiliert und geschrieben ist, landet grob wirklich nur das im Programm, was auch gebraucht wird.
 
Müsste, wenn die ganze Lib gelinkt wird, das (statische) Executable nicht auch um diesen Betrag anwachsen - in dem Fall könnte man es mit: einmal dynamisch/einmal statisch linken feststellen?
Habe es mal versucht, kann es aber persoenlich nicht herauslesen:
1652381154107.png
 

Anhänge

  • 1652381043228.png
    1652381043228.png
    23,8 KB · Aufrufe: 123
Habe ueber $ readelf -s was interessantes bezueglich static libaries herausrausgefunden.

Sagen wir eine static library archiviert zum Beispiel zwei relocatable object files, a.o und b.o.
Wenn das Program nur eine einzige Funktion aus a.o braucht, wir dieses gesamte relocatable object file importiert, egal wie viel gebraucht wird. Das andere b.o wird nicht importiert.

Nicht der gesamte Inhalt der static library wird importiert, sondern nur die gesamten relocatable object files von welchen auch etwas gebraucht wird.

Eine static library ist halt am Ende doch nur ein Archiv und kein ELF file. Es vereinfacht eigentlich nur denn compile Prozess, mehr nicht.

$ gcc main.o a.o b.o c.o d.o ..... -o main

==
$ gcc main.o -L/path/to/lib -lalphabet -o main
 
Bei Barematal-Targets bin ich gewohnt/erwarte ich, dass beim Linken nur die benötigten Symbole der Lib im Binary landen. Da überprüfen wir zum Teil, ob unerwartete Symbole im Binary sind, um versteckte Funktionalität "auszuschließen". (Insbesondere hätten wir Erklärungsbedarf wenn Symbole, die *malloc oder free heißen im Binary landen). Wenn man so linkt, dass das gesamte Binary im RAM vom MCU liegt, würde es mit der gesamten libm und libc etwas eng....

Bei GNU ld ist es wohl so, dass er per default unbekannte Symbole nur in später genannten libs sucht, außer man spielt (wie von @Yamagi erwähnt) mit groups und whole-archive.


Dynamisch linken ist auch so eine Sache:
Die Frage ist da, was man erwartet:
Gibt man z.B. -lfoo -lbar an:
  • Will man, dass libfoo und libbar in der DT_NEEDED-Section landen? Oder nur die benötigten shared libs?
  • Wenn der Linker sieht, dass nur libfoo benötigt wird? Erwartest du libbar in DT_NEEDED? Oder nicht?
  • Wenn nun aber am Zielsystem fun1 nicht in libfoo sondern libbar liegt? (Ich weiß, dann ist vermutlich das Buildsystem kaputt/seltsam[1]). Sollte dann der Linker nicht einfach alle angegeben Libs nach DT_NEEDED schreiben?
Aber das sind Fragen der Erwartungshaltung.

Das dynamische Linken löst dann der ld.so auf, je nach Konfiguration löst er alle Symbole beim Startup auf (LD_BIND_NOW), oder erst wenn es benötigt wird. Mit dem LD_AUDIT-Interface kann man auch schön sehen, was der ld.so macht und viele "lutige" Sachen machen [alternative Libs unterschieben,.....].


Wenn man dann den Spaß noch steigern will, beschäftigt man sich mit weak und strong symbols und der Reihenfolge der Funktionen im cinit-Sections (der ld.so führt diese in der "falschen" Reihenfolge aus - der Bug wird erst gefixt, wenn man einen relevanten Use Case vorzeigen kann).....


PS: Sorry, wenn ich abschweife....
 
Der Linker wird keine Tiefenanalyse einer statischen Library machen, um nur den Maschinencode rauszupopeln, der auch benutzt wird (geht auch gar nicht). Wenn die Library aber entsprechend kompiliert und geschrieben ist, landet grob wirklich nur das im Programm, was auch gebraucht wird.
Ergänzend dazu:
Statische Bibliotheken sind ja eigentlich "nur" ar-Archive. Früher(TM) wurden statische Bibliotheken auch oft so implementiert, dass jede "öffentliche" Funktion in ihrem eigenen object file landet, und die Hilfsfunktionen dann als static deklariert dazu gepackt wurde. Auf diese Weise kann der Linker dann nur die benötigten object files aus dem Archiv holen. Damit braucht der Linker dann auch keine Tiefenanalyse machen, sondern braucht bloß ein Äquivalient zu nm(1) oder ähnliches aufrufen.
 
Ein interessantes Thema. In C programmieren war für mich mal ein Hobby, in dem ich mich ab und an mal wieder versuche. Ich habe deshalb jetzt noch mal nachgesehen was konkret der Unterschied zwischen statischem und dynamischem Linken ist. Die für mich beste Erklärung fand ich hier:
Dynamisch oder statisch linken?

Vielleicht hilft sie auch anderen beim Verständnis.
 
Zurück
Oben