Dynamisk länkning och shared objects i FreeBSD: Difference between revisions

From Peters wiki
Jump to navigation Jump to search
mNo edit summary
Line 18: Line 18:


=== Bygga och länka libfoo.so ===
=== 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 {{ic|-fPIC}} flaggan. Vi använder det fullständiga kommandot:
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 {{ic|-fPIC}} flaggan. Vi använder det fullständiga kommandot:
{{Cmd|<nowiki>gcc -std=c99 -Wall -Wextra -O2 -fPIC -c foo.c</nowiki>}}
{{Cmd|<nowiki>gcc -std=c99 -Wall -Wextra -O2 -fPIC -c foo.c</nowiki>}}
Line 26: Line 27:


=== Bygga och länka myapp ===
=== 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:
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:


Line 38: Line 40:


== Länka med absolut eller relativ sökväg till runtime loadern ==
== 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:
För att slippa behöva sätta {{ic|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 {{ic|LD_RUN_PATH}} till att innehålla sökvägen till libfoo.so. Sen länka som ovan.
{{Box Kommando|Lista runtime sökvägar i ELF-fil|
 
<pre>
Vi kan nu köra myapp utan att behöva sätta {{ic|LD_LIBRARY_PATH}}. Man kan kolla vilka sökvägar som är inbyggda i ELF-filen genom att köra kommandot:
readelf -Wa myapp | grep RPATH
{{Cmd|<nowiki>readelf -Wa ./myapp | grep RPATH</nowiki>|output=0x000000000000000f (RPATH)              Library rpath: [/<path>/lib]}}
0x000000000000000f (RPATH)              Library rpath: [/<path>/lib]
</pre>}}


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.
{{ic|LD_RUN_PATH}} byggs in i ELF-filen, så vid exekvering hittas libfoo.so. Det finns dock ett undantag där {{ic|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 {{ic|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:
Bygg och länka libfoo.so som ovan, men länka myapp med följande kommando:
{{Box Kommando|Länka myapp med absolut sökväg till libfoo.so|
{{Cmd|gcc -Llib -Wl,-rpath,<path>/lib -o myapp main.o -lfoo}}
<pre>
gcc -Llib -Wl,-rpath,/<path>/lib -o myapp main.o -lfoo
</pre>}}


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:
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:
{{Box Kommando|Länka myapp med relativ sökväg till libfoo.so|
{{Cmd|gcc -Llib -Wl,-rpath,./lib -o myapp main.o -lfoo}}
<pre>
gcc -Llib -Wl,-rpath,./lib -o myapp main.o -lfoo
</pre>}}


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.
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.
Line 65: Line 58:
== Länka med sökväg via $ORIGIN till runtime loadern ==
== 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:
För att lösa problemet med relativ sökväg till libfoo.so, så ska vi använda oss av {{ic|$ORIGIN}} i den relativa sökvägen. {{ic|$ORIGIN}} löses upp till den aktuella platsen som myapp ligger vid exekveringen. Tyvärr så är namnet {{ic|$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:
{{Box Kommando|Länka myapp med $ORIGIN|
{{Cmd|gcc -Llib -Wl,-rpath,\$ORIGIN/lib -Wl,-z,origin -o myapp main.o -lfoo}}
<pre>
I FreeBSD måste vi också lägga till optionen {{ic|-z origin}} till länkaren för att ange att objektet ev. använder sig av {{ic|$ORIGIN}}.
gcc -Llib -Wl,-rpath,\$ORIGIN/lib -Wl,-z,origin -o myapp main.o -lfoo
</pre>}}
I FreeBSD måste vi också lägga till optionen <tt>-z origin</tt> 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.
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.


[[Category:FreeBSD]]
[[Category:FreeBSD]]

Revision as of 21:46, 6 January 2012

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:

user $ gcc -std=c99 -Wall -Wextra -O2 -fPIC -c foo.c

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:

user $ gcc -std=c99 -Wall -Wextra -Wno-unused -O2 -Ilib -c main.c

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

user $ gcc -Llib -o myapp main.o -lfoo

Om man nu försöker köra myapp kommer man få följande fel:

user $ ./myapp
/libexec/ld-elf.so.1: Shared object "libfoo.so" not found, required by "myapp"

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:

user $ readelf -Wa ./myapp | grep RPATH
0x000000000000000f (RPATH) Library rpath: [/<path>/lib]

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:

user $ gcc -Llib -Wl,-rpath,<path>/lib -o myapp main.o -lfoo

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:

user $ gcc -Llib -Wl,-rpath,./lib -o myapp main.o -lfoo

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:

user $ gcc -Llib -Wl,-rpath,\$ORIGIN/lib -Wl,-z,origin -o myapp main.o -lfoo

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 $ORIGIN.

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.