BSD daemon

NetBSD Dokumentation:

NetBSD ELF FAQ

ELF Issues


ELF Issues


Was ist ELF ? (zurück)

ELF ist ein Binärformat, welches mit Rücksicht auf dynamische Objekten und shared libraries entworfen wurde. Mit den älteren COFF und ECOFF Systemen war die Unterstützung für dynmische Objekte und shared libraries nicht von Anfang an vorgesehen, weswegen jene Implementationen, die sie unterstützten, oftmals komplex, verquer und langsam waren.

Ein dynamisch geladenes Modul konnte zur Laufzeit keine Symbole aus dem Programm finden. (zurück)

Sie haben wahrscheinlich die --export-dynamic Option beim Binden der Anwendung weggelassen. Diese Option wird nur benötigt, wenn gewisse Symbole aus der Anwendung von einem dynamisch geladenen Modul benutzt werden könnten, zum Beispiel wenn ein Programm zur Laufzeit versucht Module zu laden, mit denen es nicht gebunden wurde. Beachten Sie jedoch, falls sie cc(1) statt ld(1) aufrufen, dass Sie diese Option als -Wl,--export-dynamic angeben müssen.

ldconfig und ld.so.conf werden nicht benötigt! (zurück)

Theoretisch gibt es keine Notwendigkeit mehr für ldconfig oder für /etc/ld.so.conf, da ELF einen guten und portablen Mechanismus um shared libraries zu finden anbietet. Leider gibt es in der Praxis immer noch Fälle, in denen das nicht möglich ist (wie zum Beispiel wenn Sie setuid Programme benutzen wollen, zu denen sie keinen Quellcode haben, und die ihre shared libraries an Stellen erwarten, an denen sie sie nicht haben wollen). Für diese Fälle können Sie wie gehabt eine /etc/ld.so.conf Datei erstellen. In der nächsten Sektion, die die Mechanismen von ELF, um shared libraries zu finden, diskutiert, werden Sie jedoch Alternativen sehen, und warum die Benutzung von /etc/ld.so.conf keine gute Idee ist.

Mein Programm findet seine Shared library nicht! (zurück)

Ein ELF Programm muss das Verzeichnis und den Dateinamen einer shared library kennen, um sie via mmap(2) einzulesen. Im Dateinamen befindet sich gleichzeitig die Version der library. Es existieren zwei Klassen von Mechanismen zum Auffinden der libraries, einer für die Verzeichnisse, und einer für die Dateinamen.

Verzeichnisse

Obwohl sie selten benutzt wird, kann die optionale Umgebungsvariable LD_LIBRARY_PATH eine Liste von Verzeichnissen, durch Doppelpunkte getrennt, enthalten, in denen das Programm nach seinen Libraries sucht. Das kann durch wrapper-skripten benutzt werden, um fehlkonfigurierte Anwendungen zum Laufen zu bewegen. Diese Variable wird jedoch von setuid Anwendungen ignoriert.

Es gibt eine Standardliste von Verzeichnissen, die vom Laufzeitlader (ld.elf_so) durchsucht werden, wobei das bei den meisten Systemen nur /usr/lib ist. Ältere Versionen (vor 1.4) durchsuchten auch /usr/local/lib.

Der primäre Mechanismus um das Verzeichnis einer shared library zu finden, ist die ``rpath''-Liste, die in dem Programm eingebettet ist. Diese Liste wird durch die -R Option von ld(1) gesetzt. Die Posix-syntax, um ld optionen vom Compiler durchzureichen ist

    -Wl,option,option,...

Zum Beispiel: -Wl,-R/usr/something/lib. Einer Anwendung können mehrere -R-Direktiven übergeben werden, um eine Suchliste aufzubauen.

Diese Direktive ist auch als -rpath bekannt. Die Benutzung von -R hat den Vorteil, dass diese Direktive auch auf älteren Versionen von NetBSD funktioniert.

Dateinamen und Versionen

Wenn shared libraries erschaffen werden, wird die -soname Direktive verwendet um die major Versionsnummer der library im internen DT_SONAME-Feld abzuspeichern. Die library wird wie in folgendem Beispiel zu ersehen installiert:

Der Gedanke dabei ist, dass Makefiles nur mit der .so Datei binden wollen werden (Wer will sich schon durch alle Makefiles lesen und sie verändern nur weil eine neue Version einer library installiert wurde?). Sobald das Programm gebunden ist, wird es die major Version einer library kennen wollen, jedoch wird es die minor Version einer library nicht beachten wollen.

Konsequenterweise weiss die library dass sie selbst libgizmo.so.4 ist, weil während ihrer Erschaffung eine -soname libgizmo.so.4 benutzt wurde. Das Programm weiss, dass es libgizmo in der major Version 4 bekommen hat, weil der Binder den libgizmo.so.4 DT_SONAME string aus der library in die ausführbare Programmdatei kopiert und gespeichert hat.

Man benutzt normalerweise nicht -soname libgizmo.so, weil sonst das Programm immer die neueste major Version benutzen würde und nicht mehr funktionieren würde, sobald jene geändert würde. (Bemerkung: Die major Version einer library wird nur geändert, wenn die neue library mit der alten inkompatibel ist.) Genauso benutzt man nicht -soname libgizmo.so.4.2, weil dann bei Installation einer kompatiblen Änderung der library unnötigerweise die damit gebundenen Programme nicht mehr funktionieren würden.

Elf Shared Library Beispiele (zurück)

Um f.c zu kompilieren und eine installierbare shared library daraus zu machen:

cc -O -Werror -c -fpic -DPIC f.c -o f.so
ar cq libf_pic.a `NM=nm lorder f.so | tsort -q`
ld -x -shared -R/my/directory/lib -soname libf.so.4 -o
   libf.so.4.9 /usr/lib/crtbeginS.o --whole-archive
   libf_pic.a /usr/lib/crtendS.o

Oder:

% cat Makefile
LIB=f
SRCS=f.c
.include <bsd.lib.mk>
% cat shlib_version
major=4
minor=9
% make

Sie können einige der Makefile targets mit NOPROFILE=1 und NOSTATICLIB=1 ausblenden.

Und noch eine Möglichkeit:

libtool - Das libtool Paket ist ein umfangreiches Shellskript, das benutzt wird um plattformunabhängig shared und static libraris zu handhaben. Es gibt ein NetBSD libtool Paket, und sogar eine libtool home page.

Aber... Ich Will ldconfig!     Ich Will ld.so.conf! Ich will! Ich will! Ich will! (zurück)

Im ersten Moment erscheint das sinnvoll, warum sollten die Benutzerinnen nicht libraries umherschieben dürfen, und die entsprechenden Einträge in einer /etc Datei machen?

Tatsächich haben einige der ELF-Entwickler solch eine Datei vorgesehen, aber mit unterschiedlichen Resultaten. Der ELF-Mechanismus wurde geschaffen, um existierende Probleme zu lösen, und die Unterstützung des alten Mechanismus würde einige der alten Probleme wiedererwecken.

Im Moment unterstützen wir sogar die /etc/ld.so.conf Funktionalität in unserem ELF Binder, aber es ist alles andere als offensichtlich, dass solch ein Hybrid-mechanismus die richtige Lösung ist. Aus diesem Grund weisen wir nicht auf dessen Existenz hin, empfehlen weder dessen Benutzung, noch installieren wir eine Standard Schablone für diese Datei. Es wird nur für jene unterstützt, die meinen ohne es nicht leben zu können, oder denken es wirklich zu brauchen.

Das sind einige der Probleme:

  1. Es ist ein grober Ansatz, der fälschlicherweise davon ausgeht, dass alle ausführbaren Dateien eines Systemes die gleiche Suchliste durchgehen wollen. Ein Vorteil des -R Mechanismus ist dass unterschiedliche Anwendungen unterschiedliche Suchlisten haben können. Wir könnten Ausnahmen davon einrichten, aber das erfordert mehr Aufwand, siehe unten...
  2. Eine weitere Datei in /etc ist nur noch ein weiterer Konfigurationsregler an dem gedreht werden muss. Das spricht gegen ein leicht installier- und benutzbares System.
  3. Die Datei in /etc kann einfach beginnen vom installierten System zu divergieren, wenn Konfigurationen geändert werden, oder neue Pakete installiert werden. Die daraus resultierenden Fehler können BenutzerInnen schnell verwirren.
  4. Das System sollte 'einfach funktionieren'. Wir wollen unsere BenutzerInnen nicht dazu zwingen, Konfigurationsdateien für Pakete, X11, /usr/local etc. zu editieren.

  5. DAS GEHT SO NICHT: Würden Sie davon ausgehen, dass es Sinn macht eine lokale Konfiguration in Bezug auf unterschiedlichste private Konfigurationen zu halten ? Würde eine einzige Suchliste tatsächich für alle Anwendungen zutreffen ? Was, wenn zwei Anwendungen die gleiche Konfiguration benutzen ? Was, wenn zwei Pakete beide eine "libutil.so.1" erwarten ?

Die ELF Werkzeuge sind standardisierte Pakete, welche von Drittanbietern gewartet werden; diese Werkzeuge werden konsisten auf verschiedenen Betriebssystemen und Plattformen eingesetzt. Auf Dauer wird die Standardisierung durch die Benutzung von ELF die Qualität von Systemen und Anwendungen erhöhen.

Ein System von a.out nach ELF updaten (zurück)

Die empfohlene Methode ist, einen ELF snapshot zu installieren.
Wenn Sie versuchen ein upgrade vom Quellcode durchzuführen, und etwas schiefgeht, ist es wahrscheinlich, dass Ihr System in einen Zustand gerät, in dem es nicht einmal mehr in single-user booten kann.
Jedoch für alle, die dennoch vom Quellcode aus upgraden wollen: (was auf i386, sparc, und jeder Plattform die ld.new und gas.new benutzt funktionieren sollte)
  1. Holen Sie sich die -current Quellen.

  2. Erstellen Sie ein /emul/aout Verzeichnisbaum mit den a.out shared libraries
    mkdir -p /emul/aout/usr/lib /emul/aout/usr/X11R6/lib
    cp -p /usr/lib/*.so* /emul/aout/usr/lib
    cp -p /usr/X11R6/lib/*.so* /emul/aout/usr/X11R6/lib

  3. Erneuern Sie config(8)
    cd /usr/src/usr.sbin/config && make && make install

  4. Konfigurieren, Installieren und booten Sie einen Kernel mit den EXEC_ELF, EXEC_AOUT, und COMPAT_AOUT Optionen.

  5. Rufen Sie folgendes Shellskript auf:
    #!/bin/sh -x -e
    
    SRC=/usr/src
    
    # if the src is an update, eg: to -current, as well as config,
    # you might need to rebuild make:
    ### cp /usr/bin/make /usr/bin/make.old
    ### cd $SRC/usr.bin/make && make && make install
    # and at times in the past, /bin/sh, flex, etc
    
    # magic build variables
    export DESTDIR=/../.                    # hack from Hell
    export OBJECT_FMT=a.out
    export BOOTSTRAP_ELF=YESSIREE
    
    # update .mk files for new magic
    cd $SRC/share/mk && make install
    
    # Clean any old objects
    cd $SRC && make cleandir
    
    # You may need this:
    ### cd $SRC/gnu && make depend
    
    # update compiler tools
    cd $SRC/gnu/usr.bin/binutils && make
    cd ../gas.new && make
    cd ../ld.new && make
    cd ../egcs && make
    
    # (you may want to copy the old a.out tools here, just in case)
    cd $SRC/gnu/usr.bin/binutils && make install
    cd ../gas.new && make install
    cd ../ld.new && make install
    cd ../egcs && make install
    
    # You may need this:
    ### cd $SRC/gnu/lib/libbfd && make
    
    # now building ELF natively
    export OBJECT_FMT=ELF
    
    # update include files and base libraries
    cd $SRC && make includes
    cd $SRC/lib/csu && make && make install
    cd $SRC/lib && make && make install
    
    # build the dynamic linker (needs libc_pic.a)
    cd $SRC/libexec/ld.elf_so && make && make install
    
    # finish the build
    cd $SRC/gnu/lib && make && make install
    cd $SRC && make && make install
    

  6. Stellen Sie sicher, dass Sie neue boot blocks zusammenstellen und installieren bevor sie mit einem ELF kernel rebooten, da die alten bootblocks ELF Dateien nicht handhaben können.

Sollten Sie irgendwelche Änderungen an obigem Skript vornehmen müssen, teilen Sie uns das bitte unter <www@NetBSD.org> mit.

Wie erkenne ich ob ich ein ELF-System benutze ? (zurück)

Wenn Sie ein ELF-System benutzen, wird Ihr compiler die Konstante __ELF__ definieren. Sie können dies in Ihren C-Programmen benutzen, aber natürlich können Sie auch folgendes Shell skript benutzen um Ihr System zu klassifizieren:

if echo __ELF__ | ${CC:-cc} -E - | grep -q __ELF__
then echo "Kein ELF System"
else echo "Dies ist ein ELF System"
fi

Kommentare zur NetBSD ELF FAQ? (zurück)

Die ELF faq wird von Christos Zoulas <christor@NetBSD.org> verwaltet.

Home page
Zurück zu Dokumentation

(Ihre Meinung) $NetBSD: elf.html,v 1.14 2005/09/28 17:24:39 mishka Exp $
Copyright © 1998-2003 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.