Forum: Compiler & IDEs shared Lib: ungenutzte Funktionen entfernen (GCC)


von olpo (Gast)


Lesenswert?

Hallo,


ich möchte eine Shared-Lib bauen und alle ungenutzten Funktionen vom 
Compilier- bzw. Link-Vorgang rausnehmen.

Bei einem normalen Programm kann sich GCC & LD an der main() 
runterhangeln, und so ungenutzte Funktionen erkennen und rausschmeißen.

Doch wie mache ich das bei einer Shared-Lib?
Hier weiß die Toolchain ja erstmal nicht, welche Funktionen später 
genutzt werden, und welche nicht.

Ich muss also einzelne Funktionen als Einsprungpunkt, Quasi-main(), 
markieren können.

Wie mache ich das? Ich welche GCC & LD Flags muss ich setzen?



Danke

von Oliver S. (oliverso)


Lesenswert?

Hm...

Wie der Name schon sagt, ist eine shared lib shared. Was willst du da 
rauswerfen?

Oliver

von Marcus (Gast)


Lesenswert?

Hi,
Das solltest du gar nicht machen, da es eine shared lib ist, kann es ja 
auch sein, dass die auch von einem anderem Programm genutzen werden 
soll.
Wenn das dann Sachen aufrufen möchte, die du rausgeworfen hast, stürzt 
es ab.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

olpo schrieb:
> Doch wie mache ich das bei einer Shared-Lib?

Du nimmst einfach mal nur die rein, die du später auch brauchen
wirst …

von olpo (Gast)


Lesenswert?

Marcus schrieb:
> Das solltest du gar nicht machen, da es eine shared lib ist, kann es ja
> auch sein, dass die auch von einem anderem Programm genutzen werden
> soll.
> Wenn das dann Sachen aufrufen möchte, die du rausgeworfen hast, stürzt
> es ab.

Das sind berechtigte Sorgen, aber ich weiß was ich mache.
Ist ja auch nicht so wichtig, warum das in diesem speziellen Projekt 
notwendig ist.

Jörg W. schrieb:
> Du nimmst einfach mal nur die rein, die du später auch brauchen
> wirst …

Ja, das wäre die alternative Methode.
Alles, bis auf benötigten Funktionen auskommentieren, und bei Errors 
Stück für Stück wieder einkommentieren.

Da ich faul bin, möchte ich aber, das GCC & LD das für mich übernehmen.

von physiker (Gast)


Lesenswert?


von Oliver S. (oliverso)


Lesenswert?

olpo schrieb:
> Das sind berechtigte Sorgen, aber ich weiß was ich mache.

Ja nee, ist klar...

Was ist für dich eine Shared lib?

Denn üblicherweise versteht man darunter eine lib, erst zur Laufzeit vom 
Programm geladen geladen wird. Unter diesen Umständen ist deine Frage 
daher völlig sinnlos. Was also willst du wirklich?

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

olpo schrieb:
> Alles, bis auf benötigten Funktionen auskommentieren, und bei Errors
> Stück für Stück wieder einkommentieren.

Das ist die trial&error-Methode.

Die beste Methode wäre ein sauberes Konzept …

von wendelsberg (Gast)


Lesenswert?

olpo schrieb:
> Das sind berechtigte Sorgen, aber ich weiß was ich mache.

Na offensichtlich nicht, sonst wuerdest Du hier nicht fragen.
Eine shared Lib wird ja ueberhaupt nicht einkompiliert, sondern das 
fertige Programm weiss nur, welche Routine in welcher Lib benutzt werden 
muss. Bei der Installation des Programms wird ggf. ueberprueft, ob es 
die fragliche Lib auf dem System gibt.

wendelsberg

von olpo (Gast)


Lesenswert?

Im Embedded Bereich muss man halt auch mal hacken.

Die Lib. ist viel zu groß für die Plattform und hat ewig viele 
Abhängigkeiten, die sich nicht so einfach quer-kompilieren lassen.
Ich weiß auch genau, welche Programme die Lib. nutzen werden.

Das klingt hässlich, ist mir klar.
Aber es muss ja nicht jeder Thread in eine Grundsatzdiskussion ausarten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

olpo schrieb:

> Die Lib. ist viel zu groß für die Plattform

Wenn du eine shared lib hast, hast du doch vermutlich auch ein
System, welches virtual memory unterstützt.  Dann ist das eigentlich
egal, denn es wird (halt mit Granularität ganzer Speicherseiten) ja
nur das in den Speicher geladen, was auch gebraucht wird.

> und hat ewig viele
> Abhängigkeiten, die sich nicht so einfach quer-kompilieren lassen.

Gut, das ist ein anderes Ding.

> Ich weiß auch genau, welche Programme die Lib. nutzen werden.

Auf einem unixoiden System könnte man mit objdump -R analysieren,
welche dynamischen Symbole diese Programme benutzen.  Damit kannst
du dir dann eine Liste anfertigen lassen.

von wendelsberg (Gast)


Lesenswert?

Und warum nutzt man da eine shared Lib?
Der normale Weg waere doch, (wenn die Lib nicht fuer andere Programme 
gebraucht wird, was der Fall zu sein scheint) die benoetigten Funktionen 
fest einzukompilieren.
Und da baut der gcc nur das ein was er fuer noetig haelt.

wendelsberg

von Rolf Magnus (Gast)


Lesenswert?

olpo schrieb:
> Das sind berechtigte Sorgen, aber ich weiß was ich mache.
> Ist ja auch nicht so wichtig, warum das in diesem speziellen Projekt
> notwendig ist.

Dann versteht nur leider keiner, was du willst und kann dir somit keine 
sinnvolle Antwort geben.

> Jörg W. schrieb:
>> Du nimmst einfach mal nur die rein, die du später auch brauchen
>> wirst …
>
> Ja, das wäre die alternative Methode.
> Alles, bis auf benötigten Funktionen auskommentieren, und bei Errors
> Stück für Stück wieder einkommentieren.

Warum hast du überhaupt Funktionen reingemacht, die du nicht brauchst?

> Da ich faul bin, möchte ich aber, das GCC & LD das für mich übernehmen.

Und das programmübergreifend? Schließlich ist der Zweck einer Shared Lib 
ja, von mehreren Programmen genutzt zu werden. Oder hast du nur ein 
einziges Programm? Dann wäre die Frage, wozu überhaupt eine Shared Lib.
Irgendwie ergibt das alles keinen Sinn.

von The D. (thedaz)


Lesenswert?

Meines Wissens kann man zur Linkzeit des main Programms nur nicht 
benötigte libraries automatisch entfernen lassen. Der Linker darf aus 
naheliegenden Gründen nicht beim linken des main Programms die 
angezogene shared library modifizieren. Da beim linken der shared 
library die Anforderungen des main Programms unbekannt sind kann der 
linker auch hier nichts optimieren.

Der einzige Weg aus der Misere ist der vorhin genannte, nämlich allen 
code (inkl des codes, der ursprünglich in der shared library war) in ein 
einziges executable zu kompilieren und linken. Dann haben compiler & 
linker alle Informationen um die unnötigen Teile zu eliminieren.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

The D. schrieb:
> Der einzige Weg aus der Misere ist der vorhin genannte, nämlich allen
> code (inkl des codes, der ursprünglich in der shared library war) in ein
> einziges executable zu kompilieren und linken.

Und sei es nur testhalber – wenn man sich dabei ein Mapfile vom
Linker anlegen lässt, kann man anhand dessen rausfusseln, was aus
der Bibliothek tatsächlich notwendig war.  Basierend auf dieser
Information könnte man eine passende shared lib zurechtdengeln.

von temp (Gast)


Lesenswert?

Ich kann olop schon verstehen. Angenommen jemand baut sich eine 
Pluginschnittstelle um Module dynamisch laden zu können. un weiter 
angenommen das Hauptprogramm benötigt nur 3 Funktionen aus dem Plugin: 
init(), run(), deinit().
Wenn ich unter Windows eine dll schreibe, sorge ich dafür, dass diese 3 
Funtionen als "__declspec(dllexport)" gekennzeichnet werden. Damit weiß 
der Linker, aus dieser dll brauche ich außer diesen 3 Funktionen nur 
noch die die davon abhängig sind. Wie macht man sowas einem gcc unter 
Linux klar?

von The D. (thedaz)


Lesenswert?

temp schrieb:
> Ich kann olop schon verstehen. Angenommen jemand baut sich eine
> Pluginschnittstelle um Module dynamisch laden zu können. un weiter
> angenommen das Hauptprogramm benötigt nur 3 Funktionen aus dem Plugin:
> init(), run(), deinit().
> Wenn ich unter Windows eine dll schreibe, sorge ich dafür, dass diese 3
> Funtionen als "__declspec(dllexport)" gekennzeichnet werden. Damit weiß
> der Linker, aus dieser dll brauche ich außer diesen 3 Funktionen nur
> noch die die davon abhängig sind. Wie macht man sowas einem gcc unter
> Linux klar?

Das Problem ist doch, dass die shared library schon fertig gebaut als 
binary file vorliegt und komplett in den Speicher geladen werden muss, 
auch wenn nur 3 Symbole daraus vom main Programm benutzt werden. Besser 
wäre es, wenn die monolithische library in mehrere kleine shared libs 
zerlegt werden würde und main nur die eine benötigte lib mit den 
notwendigen Symbolen anziehen könnte.

Alternativ ist es vielleicht möglich, eine static library zu bauen und 
zum main Programm zu linken. Ich bin da allerdings nicht der Experte.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

The D. schrieb:
> Das Problem ist doch, dass die shared library schon fertig gebaut als
> binary file vorliegt und komplett in den Speicher geladen werden muss,

Das ist Dein Denkfehler. Aus der Shared Lib wird nur das geladen, was 
auch läuft. Macht jedes pagende Linux so.

Das Problem des TO ist überhaupt kein Problem. Ich verstehe auch nicht, 
was der ganze Zirkus soll.

Ist das Programm das einzige, was die Lib benutzt, kann er sie statisch 
dazulinken. Ist das Programm nicht das einzige, muss er sich abfinden, 
dass die Lib auch genutzt wird.

Einerseits weiß der TO nicht, was sein Programm aus der Lib so alles 
braucht, aber er gibt vor, genau zu wissen, was die anderen Programme 
von der Lib benötigen.

Das passt alles nicht zusammen.

: Bearbeitet durch Moderator
von olpo (Gast)


Lesenswert?

Uijuijui, warum immer diese Grundsatzdiskussionen?
Das Bauprozess ist kompliziert, und bin zu faul mich hier hier lang und 
breit zu rechtfertigen, warum ich welche Lösung bevorzuge.

Das ist mein Problem:
Ich baue eine Shared Library und möchte alle Funktionen rausschmeißen, 
die ich später nicht brauche.
Man muss der Toolchain also irgendwie sagen, welche Symbole genutzt 
werden.

Wer weiß, wie das geht, bitte melden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

olpo schrieb:
> Wer weiß, wie das geht, bitte melden.

Es geht nur, indem du sie gar nicht erst einbaust.  Eine shared
lib ist ein fix und fertig gelinktes Objekt, aus dem kannst du
(anders als aus einer statischen Library) nicht nachträglich
irgendwas wieder entfernen – genausowenig, wie du aus einer
ausführbaren Datei noch was entfernen könntest.

von olpo (Gast)


Lesenswert?

Hi Jörg,

ich denke, hier gibt's ein Verständnis-Problem.
Wir reden wohl aneinander vorbei.

Jörg W. schrieb:
> Es geht nur, indem du sie gar nicht erst einbaust.

Und genau das kann GCC doch.
C_FLAGS = -ffunction-sections -fdata-sections
LD_FLAGS = --gc-sections

Damit scheißt GCC alle Funktionen raus, die von main() nie erreicht 
werden können.

Und ich vermute, dass das beim Bau einer Shared-Lib ebenfalls möglich 
ist. Man müsste GCC nur beibringen, welche Funktion er hier als 
quasi-main() betrachten soll.
Andere Funktionen, die von dort nicht erreicht werden können: Raus!

von Oliver S. (oliverso)


Lesenswert?

olpo schrieb:
> ich denke, hier gibt's ein Verständnis-Problem.

Das hast du voll erfasst. Zu Shared libs gibt es kein Main. Die sind 
dafür gedacht, beliebig vielen und vor allen verschiedenen Programmen 
die Funktionalität zur Verfügung zu stellen, die der Programmierer in 
sie hineinschreibt. Vom Konzept her ist es daher völlig sinnlos, von 
dieser Funktionalität beim linken irgend etwas wieder zu entfernen.

Beim statischen Linken wirft der Linker die ungenutzten Funktionen raus.
Das wäre auch die einzige Variante, die dir eventuell weiterhilft. Bau 
halt eine statisch gelinkte Version des Programms, ohne die Lib 
dazuzulinken. Der Linker wird dir dann sagen, welche Funktionen er 
vermisst.

Die wirst du dann von Hand in der Shared Lib suchen müssen.

Automatisch geht es nicht.

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

olpo schrieb:
> Und genau das kann GCC doch.

Nein, kann er nicht.

Wurde dir jetzt schon x-mal erklärt, aber du willst es offensichtlich
nicht wahrhaben.

Das, was du dafür missbrauchen willst, ist wohl ursprünglich mal dazu
geschaffen worden, bei C++ zwangsweise generierte Sachen (wie default
constructors) durch den Linker eliminieren zu lassen, wenn dieser
am Ende bemerkt, dass irgendwas niemals referenziert wird.  Für eine
shared lib müsste er dann aber alles rauswerfen, denn in dem Moment,
da der Linker diese baut, wird ja rein gar nichts referenziert.

von olpo (Gast)


Lesenswert?

Jörg W. schrieb:
>> Und genau das kann GCC doch.
>
> Nein, kann er nicht.

http://www.mikrocontroller.net/articles/GCC:_unbenutzte_Funktionen_entfernen

Oliver S. schrieb:
> Zu Shared libs gibt es kein Main.

Deshalb schreibe ich 'quasi-main()'.
GCC, nimm die Funktion foo() und guck, welche anderen Funktionen du 
erreichen kannst. Alle anderen schmeiße raus.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

olpo schrieb:
> Jörg W. schrieb:
>>> Und genau das kann GCC doch.
>>
>> Nein, kann er nicht.
>
> http://www.mikrocontroller.net/articles/GCC:_unbenutzte_Funktionen_entfernen

Nur, weil da einer die Überschrift etwas unglücklich (oder für das
Zielpublikum passend) formuliert hat, macht es das deshalb nicht
korrekt.

Aber du hast ja sowieso deine vorgefertigte Meinung und alle, die dir
sagen, dass das so nicht geht, wissen halt bloß nicht, wie's geht.

Damit kann ich dir leider nicht mehr helfen.

von Marc (Gast)


Lesenswert?

Wenn die ganze Riege der Stänkerer (mittlerweile samt Mod) mal 
wenigstens versuchen würde zu verstehen, was OP will, wäre allen 
geholfen.

Seine Vorstellungen sind absolut nachvollziehbar.

Kann man unter Linux (bzw. eher bei ELf) wirklich keine Unterscheidung 
haben, welche Funktionen exportiert sind?

Bei PE ist das kein Problem, und eben dafür wird __dllexport genutzt.

Und wenn die möglichen Einsprungpunkte damit klar sind, kann auch normal 
gestrippt werden. Konzeptionell, ob das unter Linux/ELF geht, weiß ich 
nicht.

Dieses ganze Gemäkele von wegen "kann alles aufgerufen werden" ist 
entweder ein Verständnisproblem von euch oder eine Restriktion der 
Linux-Gegebenheiten. In beiden Fällen wäre ein konzilianterer Ton 
angebracht.

von Marc (Gast)


Lesenswert?

The D. schrieb:
> Das Problem ist doch, dass die shared library schon fertig gebaut als
> binary file vorliegt

Wie kommst du darauf? Er schrieb doch nun schon x-mal, daß er die shared 
lib gerade erst bauen will. Und in der shared lib sollen nur benötigte 
Symbole auftauchen.

Es geht überhaupt nicht um "ach guck mal, eine fremde Lib auf der 
Platte, da soll alles weg, was mein Programm gerade nicht braucht."

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marc schrieb:
> Kann man unter Linux (bzw. eher bei ELf) wirklich keine Unterscheidung
> haben, welche Funktionen exportiert sind?

Auch, wenn etwas nicht exportiert ist: warum sollte man das entfernen
können?  Es kann nur beim Import der DLL dann keiner drauf zugreifen,
aber die Module der DLL selbst können es natürlich noch.  (Gut, hier
könnte der Linker natürlich solche Sachen rauswerfen, von denen er
an dieser Stelle bemerkt, dass sie am Ende nicht aufrufbar sind.)

Um das auf deine PE-Denkweise abzubilden: deklariere jedes globale
Symbol als "dllexport", baue eine DLL – dann erwartet er jedoch, dass
einzelne Teile davon, die in seiner späteren Applikation (die beim
Linken der DLL ja nicht bekannt ist) nicht benötigt werden, gar nicht
erst in der DLL drin sind.

Wie soll das gehen?  Zu dem Zeitpunkt, da die DLL gebaut wird, sind
die potenziellen Konsumenten ja nicht bekannt.

: Bearbeitet durch Moderator
von Marc (Gast)


Lesenswert?

Genau! An eben der Stelle soll der Linker rauswerfen!

Das ist genau das, wovon OP seit Anbeginn des Threads redet. War es das 
nun wert, ihn so rüde anzugehen?

Und du hast es immer nch nicht verstanden. Nicht "alles als exportiert 
markieren". Nicht "spätere Applikation". Es gibt noch überhaupt keine 
Applikation!

Er baut nur eine Library. Er will gar nicht wissen, wer später diese Lib 
nutzt. Aber er weiß, das er in seiner Library ggf. Dinge aus 
Fremdcodestücken oder Debugcode oder Code für ganz andere Buildvarianten 
drin hat, die überflüssig sind.

Genau das, warum man auch im Nicht-shared-lib-Fall --gc-sections 
verwendet. Das ist mitnichten wegen irgendwelcher komischen C++-Dinge im 
Linker unterstützt.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marc schrieb:
> Kann man unter Linux (bzw. eher bei ELf) wirklich keine Unterscheidung
> haben, welche Funktionen exportiert sind?

Grad mal nachgelesen, ja, kann man dem Linker schon mitteilen.

Aber wie ich schon schrieb, ich denke nicht, dass das sein Problem
lösen würde.  So, wie ich olpo verstanden habe, hat er eine Sammlung
von Objekten, die halt bspw. foo(), bar() und mumble() definieren.
Aus diesen baut er eine dynamische Bibliothek.

Zur Laufzeit hat er dann eine Applikation, die gegen diese Bibliothek
gelinkt ist, die daraus aber nur foo() braucht.  Nun hätte er gern
die Bibliothek so gebaut, dass bar() und mumble() gar nicht erst drin
sind.

Das geht nur, indem man beim Bauen der Bibliothek bar() und mumble()
nicht nur nicht exportiert (das wäre dein Vergleich mit dem dllexport),
sondern indem man sie gar nicht erst in die Bibliothek hinein linkt.

Ja, machen kann man das, aber eben nicht direkt, sondern mit einem
der anderen genannten Vorschläge, indem man ermitteln lässt, was aus
dieser tatsächlich benötigt wird, um dann in einem zweiten Schritt
eine weitere dyamische Bibliothek zusammenbauen zu lassen, die nur
noch das gewünschte enthält.

Aber das gibt es nicht „aus der Dose raus“, das müsste man sich
zusammenscripten, was ich aber immer noch besser fände als die
eingangs genannte trial&error-Methode (erstmal alles auskommentieren
und dann gucken, worüber der Linker meckert).

von Oliver S. (oliverso)


Lesenswert?

Marc schrieb:
> Er baut nur eine Library. Er will gar nicht wissen, wer später diese Lib
> nutzt. Aber er weiß...

Schön , daß du zu wissen meinst, was der TO will. Er selber schreibt 
allerdings was ganz anderes.

Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marc schrieb:

> Genau das, warum man auch im Nicht-shared-lib-Fall --gc-sections
> verwendet. Das ist mitnichten wegen irgendwelcher komischen C++-Dinge im
> Linker unterstützt.

Meines Wissens ist das der Ursprung gewesen.

Ja, hier die Referenz dazu:

https://sourceware.org/ml/bfd/1998/msg00057.html

Dass es mittlerweile gern mis^H^H^Hbenutzt wird, um seinen Code nicht
extra aufräumen zu müssen, ist ein anderes Ding.

von Marc (Gast)


Lesenswert?

Oliver S. schrieb:
> Marc schrieb:
>> Er baut nur eine Library. Er will gar nicht wissen, wer später diese Lib
>> nutzt. Aber er weiß...
>
> Schön , daß du zu wissen meinst, was der TO will. Er selber schreibt
> allerdings was ganz anderes.
>
> Oliver

Komisch. Im Urpoating findet sich genau das. Nur eine shared lib, keine 
Applikation. Daraufhin hast du ihn unsachlich angegriffen.

Ist mir egal, wie du dich nun windest. Ich kann dem OP inhaltlich nicht 
helfen.

Aber es wäre schade, wenn Leute, die wissen wie es geht, vom Krakele der 
Mehrheit inklusive Mod abgeschreckt würden oder deren abstruse 
Interpretation sich einfach zu eigen machen.

Ich denke, ich habe das Problem klarer formuliert und wenn wer helfen 
kann ist gut. Wenn nicht dann halt nicht.

Ich hin hier damit raus.

von Oliver S. (oliverso)


Lesenswert?

Marc schrieb:
> Ich denke, ich habe das Problem klarer formuliert und wenn wer helfen
> kann ist gut. Wenn nicht dann halt nicht.

Hast du nicht.

Der TO hat eine Shared Lib, die eine Menge Funktionen enthält und auch 
exportiert. Er weiß (!!!), das seine Anwendung(en) nicht alle von der 
Lib angebotenen Funktionen nutzt, und möchte, daß der Linker alle von 
seiner Anwendung ungenutzten Funktionen der Lib automatisch entfernt. Da 
geht es nicht um interne Überbleibsel von irgendwelchen Debug-Sessions, 
sondern um offiziell vom Lib-Programmier vorgesehene Funktionen.

Und das geht halt nicht automatisch, weil es eben dem Sinn und Konzept 
einer shared Lib völlig widerspricht.

Oliver

von Daniel A. (daniel-a)


Lesenswert?

Ich hatte einmal ein Modulladesystem für einen meiner HTTP und WebSocket 
Server, dort hatte ich ein Makrobasiertes system wo Shared Libraries als 
Modul verwendet wurden und nur eine generierte init funktion exportiert 
hat. Darüber wurden dann generierte C-Wrapperfunktionspointer 
ausgetauscht, und diese wurden von generierten klassen aufgerufen. 
Exceptions wurden auch abgefangen und dort durchgeschleust. Der sinn des 
ganzen war eine c kompatible schnitstelle, ein sauberes Interface, 
erweiterungsmögluchkeiten ohne verschedene Server/Modul versionen 
inkompatiebel zu machen, etc.

Der springende punkt ist, die init funktion war der einzige 
Einsprungspunkt (abgesehen von den default symbolen eines so), und code 
der über diesen nicht erreichbar war war überflüssig. Es macht sinn 
anzunehmen, dass man diesen code vom Linker automatisiert Isolieren und 
entfernen lassen kann. Ich werde mal nach dem Ding suchen und etwas mit 
dem "used" attribut herumspielen und ein par Compilerflags herumspielen, 
um herauszufinden, ob dies möglich ist.

PS: Eventuell gibt es auch bei BusyBox etwas zu finden, die haben dort 
konventionen und Dinge im makefile, um die Grösse zu vergleichen & 
Optimieren.

von Bernd K. (prof7bit)


Lesenswert?

Der Befehl KEEP() im linker script hat was damit zu tun.

von Daniel A. (daniel-a)


Lesenswert?

OK, Ich denke ich habe hinbekommen/wiedergefunden was der TO will. Ich 
habe folgenden Code ausprobiert, eimal mit symbol_a und einmal 
auskommentiert:
1
#include <stdio.h>
2
3
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
4
5
int symbol_a();
6
EXPORT_SYMBOL void symbol_b();
7
void symbol_b();
8
9
void symbol_b(){
10
  printf("Hello!");
11
}
12
13
void symbol_c(){
14
  printf("World!");
15
}
16
17
int symbol_a(){
18
  return 10;
19
}

Kompiliert habe ich es so:
1
gcc -Wall -Wextra -pedantic -Werror -ldl -fvisibility=hidden -Os -fPIC -std=c11 -ffunction-sections -fdata-sections -c test.c -o test.o
2
gcc test.o -Wl,--unresolved-symbols=report-all,--allow-shlib-undefined -shared -Wl,--gc-sections,--strip-all -o libtest.so

Ein diff des Resultats mit symbol_a() und mit symbol_a() auskommentiert 
war Identisch. objdump -T liefert:
1
00000000000005a0 l    d  .init  0000000000000000              .init
2
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
3
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
4
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __printf_chk
5
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
6
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
7
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize
8
0000000000201038 g    D  .data  0000000000000000  Base        _edata
9
0000000000201040 g    D  .bss  0000000000000000  Base        _end
10
0000000000201038 g    D  .bss  0000000000000000  Base        __bss_start
11
00000000000005a0 g    DF .init  0000000000000000  Base        _init
12
0000000000000714 g    DF .fini  0000000000000000  Base        _fini
13
0000000000000700 g    DF .text  0000000000000013  Base        symbol_b

Funktionstest:
1
void symbol_b();
2
3
int main(){
4
  symbol_b();
5
}
1
gcc main.c ./libtest.so -o main && ./main
Ausgabe:
1
Hello!
Funktioniert also.



Erklärung wie es Funktioniert:
Die Optionen:
1
  -Wall -Wextra -pedantic -Werror -std=c11
Sind nicht relevent, ich nutze diese einfach immer.
1
  -ldl -fPIC -shared
Die braucht man glaub ich bei dynamischen shared objects.
1
  -fvisibility=hidden
Macht alle Symbole per default unsichtbar.
1
__attribute__ ((visibility ("default")))
Macht ein Symbol sichtbar.
1
  -ffunction-sections -fdata-sections
Funktionen & Daten in Sections packen.
1
  -Wl,--gc-sections,--strip-all
Linker, Alle Symbole/Sections/etc. die über die Exportierten Symbole 
nicht erreichbar sind entfernen.
1
  -Wl,--unresolved-symbols=report-all,--allow-shlib-undefined
Das braucht man wenn man verhindern will dass man vergisst eine Lib zur 
Lib dazuzulinken, oder so. (bin mir da nichtmehr ganz sicher)

von Oliver S. (oliverso)


Lesenswert?

Und jetzt machst du das ganze mit drei gleichwertigen und voneinander 
unabhängigen exportierten Symbolen, wovon das aufrufende Programm aber 
nur eins nutzt. Die anderen beiden sollen durch irgend eine Magie 
automatisch entfernt werden. Das wäre das, was der TO will.

Oliver

von Bernd K. (prof7bit)


Lesenswert?

Was spricht dagegen die library als static library mit 
ffunction-sections zu bauen (und vielleicht sogar mit flto) und dann mit 
gc-sections (und vielleicht sogar flto) zu linken? Das würde die 
Forderungen des Threaderstellers vollumfänglich erfüllen (und im Falle 
von LTO sogar übererfüllen).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.