Dynamisk länkning och shared objects i FreeBSD

From Peters wiki
Revision as of 21:11, 6 January 2012 by Peter (talk | contribs)
Jump to navigation Jump to search

Problem med dynamisk länkning är ofta det som strular när man ska kompilera länka ihop något större program. Särskilt om man inte är root på systemet och måste installera sina program på andra ställen än systemets standardställen.

Exempel: myapp & libfoo.so

Vi börjar med ett exempel på ett litet program som består av en exekverbar fil + en so-fil. Detta exempel kommer sedan användas för att åskådliggöra problemen runt so-filer och dynamisk länkning. Vår filstruktur i exemplet är:

.
├── Makefile
├── lib
│   ├── Makefile
│   ├── foo.c
│   └── foo.h
└── main.c

Länka utan sökväg till runtime loadern

Bygga och länka libfoo.so

Källkoden till libfoo.so ligger i foo.c och dess interface i foo.h. När vi kompilerar koden måste vi använda -fPIC flaggan. Vi använder det fullständiga kommandot: Template:Error

För att sedan länka ihop libfoo.so så använder vi följande kommando:

user $ gcc -shared -o libfoo.so foo.o

Optionen -shared används för att skapa ett shared object (so-fil).

Bygga och länka myapp

Vår exekverbar fil består av källkoden main.c men behöver en funktion i libfoo.so för att kunna köras. Vi kompilerar källkoden med kommandot:

Template:Box Kommando

För att länka programmet myapp kör vi kommandot: Template:Box Kommando

Om man nu försöker köra myapp kommer man få följande fel: Template:Box Kommando När programmet myapp ska laddas hittar loadern inte libfoo.so filen. För att lösa problem kan vi sätta variabeln LD_LIBRARY_PATH och peka ut var vår libfoo.so ligger. Nu kommer loadern hitta libfoo.so och myapp går att köra. Denna lösning har dock många nackdelar.

Länka med absolut eller relativ sökväg till runtime loadern

För att slippa behöva sätta LD_LIBRARY_PATH vid exekvering kan sökvägar byggas in i ELF filen vid länkning. Loadern kommer vid exekvering använda dessa för att hitta de dynamiskt länkade so-filerna. Innan länkning, sätt LD_RUN_PATH till att innehålla sökvägen till libfoo.so. Sen länka som ovan.

Vi kan nu köra myapp utan att behöva sätta LD_LIBRARY_PATH. Man kan kolla vilka sökvägar som är inbyggda i ELF-filen genom att köra kommandot: Template:Box Kommando

LD_RUN_PATH byggs in i ELF-filen, så vid exekvering hittas libfoo.so. Det finns dock ett undantag där LD_RUN_PATH inte byggs in, och det är om någon annan sökväg anges via -rpath kommandot till länkaren. Då ignoreras LD_RUN_PATH helt. Så ett bättre sätt är att alltid ange sökvägarna explicit vid länkningen.

Bygg och länka libfoo.so som ovan, men länka myapp med följande kommando: Template:Box Kommando

Nackdelen med en absolutsökväg är att libfoo.so måste ligga på samma ställe överallt programmet myapp ska köra. Så en relativ sökväg kan tyckas vara bättre. Då behöver bara myapp och libfoo.so relativt ligga på samma ställe. Låt och ändra till en relativ sökväg genom att länka myapp med kommandot: Template:Box Kommando

Vi kan nu köra myapp, men bara när vi står i samma katalog som myapp själv. Så relativ sökväg löser inte heller problemet att kunna köra myapp från olika ställen.

Länka med sökväg via $ORIGIN till runtime loadern

För att lösa problemet med relativ sökväg till libfoo.so, så ska vi använda oss av $ORIGIN i den relativa sökvägen. $ORIGIN löses upp till den aktuella platsen som myapp ligger vid exekveringen. Tyvärr så är namnet $ORIGIN illa valt då $ betyder olika saker i Makefiler, skal etc. Om vi vill köra kommandot i ett bash-skal så behöver vi lägga till ett \ före $-tecknet: Template:Box Kommando I FreeBSD måste vi också lägga till optionen -z origin till länkaren för att ange att objektet ev. använder sig av en $ORIGIN sökväg.

Nu kan myapp och libfoo.so läggas på olika ställen och ändå kunna exekveras. Det enda som krävs är att libfoo.so alltid ligger i en katalog som heter lib under myapp filen.