elf_begin(3E) elf_begin(3E)
NAME
elfbegin - Dateideskriptor erzeugen
SYNTAX
cc [option ...] datei ... -lelf [bibliothek ...]
#include <libelf.h>
Elf *elfbegin(int fildes, ElfCmd cmd, Elf *ref);
BESCHREIBUNG
elfbegin(), elfnext(), elfrand() und elfend() arbeiten zusammen.
Sie bearbeiten ELF-Objektdateien entweder einzeln oder als Archivkom-
ponenten. Nachdem ein ELF-Deskriptor von elfbegin() erzeugt wurde,
kann das Programm eine existierende Datei lesen, aktualisieren oder
eine neue Datei erzeugen. fildes ist ein geöffneter Dateideskriptor,
den elfbegin() zum Lesen oder Schreiben benutzt. Der anfängliche
Datei-Offset [siehe lseek(2)] spielt keine Rolle, und der resultie-
rende Datei-Offset ist undefiniert.
Für cmd sind die folgenden Werte möglich:
ELFCNULL
elfbegin() liefert einen Nullzeiger, ohne daß ein neuer Deskrip-
tor angelegt wird. ref wird bei diesem Kommando ignoriert. Siehe
elfnext(3E) und die dazugehörigen Beispiele für weitere Informa-
tionen.
ELFCREAD
Wenn ein Programm den Inhalt einer existierenden Datei prüfen
will, sollte es cmd auf diesen Wert setzen. Abhängig vom ref-Wert
prüft dieses Kommando Archivkomponenten oder ganze Dateien. Dabei
können folgende drei Fälle auftreten:
- Wenn ref ein Nullzeiger ist, belegt elfbegin() einen neuen
ELF-Deskriptor und bereitet die Bearbeitung der ganzen Datei
vor. Wenn die zu lesende Datei ein Archiv ist, bereitet
elfbegin() den resultierenden Deskriptor darauf vor, beim
nächsten Aufruf von elfbegin() auf die erste Archivkomponente
der kompletten Datei zuzugreifen, als ob das Programm
elfnext() oder elfrand() zur Positionierung auf die erste
Komponente verwenden würde.
- Wenn ref ein mit einer Archivdatei verknüpfter Deskriptor
ungleich null ist, erlaubt elfbegin() einem Programm das
Anlegen eines separaten ELF-Deskriptors, der mit einer eigenen
Komponente verknüpft ist. Das Programm sollte elfnext() oder
elfrand() verwenden, um ref entsprechend zu positionieren
(außer für die erste Komponente, welche elfbegin() automa-
tisch einstellt; siehe folgendes Beispiel). In diesem Fall
sollte fildes derselbe Dateideskriptor sein, der auch für das
Vaterarchiv verwendet wird.
Seite 1 Reliant UNIX 5.44 Gedruckt 11/98
elf_begin(3E) elf_begin(3E)
- Wenn ref schließlich ein Deskriptor ungleich null ist und kein
Archiv darstellt, so erhöht elfbegin() die Anzahl der Akti-
vierungen für den Deskriptor und liefert ref zurück, ohne daß
ein neuer Deskriptor angelegt wird und ohne daß die Lese- und
Schreibrechte des Deskriptors verändert werden. Um den
Deskriptor für ref freizugeben, muß das Programm für jede der
Aktivierungen elfend() einmal aufrufen. Siehe elfnext(3E)
und die Beispiele für weitere Informationen.
ELFCRDWR
Dieses Kommando führt zu denselben Aktionen wie ELFCREAD,
erlaubt jedoch dem Programm außerdem das Aktualisieren der Datei-
inhalte [siehe elfupdate(3E)]. Dies bedeutet, daß ELFCREAD nur
das Lesen der Datei ermöglicht, während ELFCRDWR dem Programm
das Lesen und Schreiben der Datei erlaubt. ELFCRDWR ist für
Archivkomponenten nicht zulässig. Wenn ref ungleich null ist, so
muß die Datei zuvor mit dem Kommando ELFCRDWR erzeugt worden
sein.
ELFCWRITE
Wenn das Programm einen bereits vorhandenen Dateiinhalt ignorie-
ren möchte, um eine neue Datei zu erzeugen, sollte cmd auf diesen
Wert gesetzt werden. ref wird für dieses Kommando ignoriert.
elfbegin() "arbeitet" mit allen Dateien (einschließlich Dateien mit
Null-Bytes), vorausgesetzt, es kann genügend Speicher für interne
Strukturen belegt werden, und die notwendigen Dateiinformationen kön-
nen gelesen werden. Programme, die Objektdateien auslesen, können
daher elfkind() oder elfgetehdr() aufrufen, um den Dateityp festzu-
stellen (nur Objektdateien haben einen ELF-Kopf). Wenn die Datei ein
Archiv ist, welches keine weiteren Komponenten zum Bearbeiten enthält,
oder wenn ein Fehler auftritt, so liefert elfbegin() einen Nullzeiger
zurück. Ansonsten wird ein ELF-Deskriptor ungleich null zurückgegeben.
Vor dem ersten Aufruf von elfbegin() muß das Programm zur Koordinie-
rung der Versionen elfversion() aufrufen.
Systemdienste
Bei der Bearbeitung einer Datei entscheidet die Bibliothek in Abhän-
gigkeit von den Programmanforderungen, wann die Datei gelesen oder
geschrieben wird. Normalerweise geht die Bibliothek davon aus, daß der
Dateideskriptor bei Verfügbarkeit des ELF-Deskriptors ebenfalls ver-
fügbar ist. Muß ein Programm viele Dateien gleichzeitig bearbeiten und
beschränkt das zugrundeliegende Betriebssystem die Anzahl der geöffne-
ten Dateien, so kann das Programm elfcntl() verwenden, um die Datei-
deskriptoren wiederzuverwenden. Nachdem elfcntl() mit entsprechenden
Argumenten aufgerufen wurde, kann das Programm den Dateideskriptor
schließen, ohne mit der Bibliothek in Konflikt zu kommen.
Alle Daten, die mit einem ELF-Deskriptor verknüpft sind, bleiben allo-
kiert, bis elfend() die letzte Aktivierung des Deskriptors beendet
Seite 2 Reliant UNIX 5.44 Gedruckt 11/98
elf_begin(3E) elf_begin(3E)
hat. Nach Freigabe der Deskriptoren wird auch der Speicher freigege-
ben; der Versuch, auf freigegebene Daten zuzugreifen, führt zu einem
undefinierten Verhalten. Daher muß ein Programm, welches mit mehreren
Ein- oder Ausgabedateien operiert, die ELF-Deskriptoren aktiv halten,
bis die Bearbeitung vollständig abgeschlossen ist.
BEISPIELE
Ein Prototyp zum Lesen einer Datei ist unten angeführt. Wenn die Datei
eine einfache Objektdatei ist, führt das Programm die Schleife einmal
aus und erhält beim zweiten Schleifendurchlauf einen Nulldeskriptor.
In diesem Fall haben elf und arf denselben Wert; der Aktivierungszäh-
ler ist 2, und das Programm ruft elfend() zweimal auf, um den
Deskriptor freizugeben. Wenn die Datei ein Archiv ist, wird die
Schleife für jede Archivkomponente durchgeführt, wobei die Dateien,
die keine Objektdateien sind, ignoriert werden.
if (elfversion(EVCURRENT) == EVNONE)
{
/* Bibliothek veraltet */
/* Fehlerbehandlung */
}
cmd = ELFCREAD;
arf = elfbegin(fildes, cmd, (Elf *)0);
while ((elf = elfbegin(fildes, cmd, arf)] != 0)
{
if ((ehdr = elf32getehdr(elf)] != 0)
{
/* Datei bearbeiten ... */
}
cmd = elfnext(elf);
elfend(elf);
}
elfend(arf);
Alternativ dazu ist auch die wahlfreie Bearbeitung von Archiven mög-
lich, wie das nächste Beispiel zeigt. Nachdem die Datei als Archiv
identifiziert ist, bearbeitet das Programm die gewünschten Archivkom-
ponenten. Der Einfachheit halber sind in diesem Beispiel Fehlerabfra-
gen ausgelassen; einfache Objektdateien werden ignoriert. Außerdem
bleiben in diesen Programmzeilen die ELF-Deskriptoren für alle Archiv-
komponenten bestehen, da elfend() nicht zur Freigabe aufgerufen wird.
Seite 3 Reliant UNIX 5.44 Gedruckt 11/98
elf_begin(3E) elf_begin(3E)
elfversion(EVCURRENT);
arf = elfbegin(fildes, ELFCREAD, (Elf *)0);
if (elfkind(arf) != ELFKAR)
{
/* kein Archiv */
}
/* erste Komponente bearbeiten */
/* offset = ... für gewünschten Kopf der Komponente */
while (elfrand(arf, offset) == offset)
{
if ((elf = elfbegin(fildes, ELFCREAD, arf)] == 0)
if ((ehdr = elf32getehdr(elf)] != 0)
{
/* Archivkomponente bearbeiten ... */
}
/* offset = ... für gewünschten Kopf der Komponente */
}
Der folgende Auszug zeigt, wie eine neue ELF-Datei erzeugt werden
kann. Um den allgemeinen Ablauf zu beschreiben, ist dieses Beispiel
vereinfacht:
elfversion(EVCURRENT);
fildes = open("pfad/name", ORDWROTRUNCOCREAT, 0666);
if ((elf = elfbegin(fildes, ELFCWRITE, (Elf *)0)] == 0)
return;
ehdr = elf32newehdr(elf);
phdr = elf32newphdr(elf, count);
scn = elfnewscn(elf);
shdr = elf32getshdr(scn);
data = elfnewdata(scn);
elfupdate(elf, ELFCWRITE);
elfend(elf);
Folgender Auszug beschreibt das Aktualisieren einer bereits vorhande-
nen ELF-Datei. Dieses Beispiel ist ebenfalls vereinfacht, um den all-
gemeinen Ablauf darzustellen.
elfversion(EVCURRENT);
fildes = open("pfad/name", ORDWR);
elf = elfbegin(fildes, ELFCRDWR, (Elf *)0);
/* neue Informationen hinzufügen oder alte Informationen löschen... */
close(creat("pfad/name", 0666)];
elfupdate(elf, ELFCWRITE);
elfend(elf);
Seite 4 Reliant UNIX 5.44 Gedruckt 11/98
elf_begin(3E) elf_begin(3E)
Im obigen Beispiel kürzt der Aufruf creat() die Datei; dadurch wird
sichergestellt, daß die resultierende Datei die "richtige" Größe hat.
Ohne Kürzen könnte die aktualisierte genauso groß sein wie die Origi-
naldatei, selbst wenn Informationen gelöscht wurden. Die Bibliothek
kürzt, wenn möglich, die Datei durch ftruncate [siehe truncate(3C)].
Einige Systeme unterstützen jedoch ftruncate() nicht; der Aufruf von
creat() schützt die Datei davor.
Bitte beachten Sie, daß beide Beispiele zum Erzeugen von Dateien
jeweils mit Schreib- und Leserechten öffnen. Die Bibliothek verwendet
mmap() (sofern das System dies unterstützt), um den Durchsatz zu stei-
gern, und mmap() erfordert einen lesbaren Dateideskriptor. Die Bibli-
othek kann auch einen Dateideskriptor verwenden, der nur beschreibbar
ist; das Anwendungsprogramm erhält dann jedoch nicht die Durchsatzvor-
teile von mmap().
HINWEIS
COFF ist ein Objektdateiformat, das vor ELF verwendet wurde. Wenn ein
Programm elfbegin() mit einer COFF-Datei aufruft, übersetzt die
Bibliothek die COFF-Strukturen in die entsprechenden ELF-Äquivalente;
das Programm kann auch eine COFF-Datei lesen (aber nicht schreiben),
als ob es sich um eine ELF-Datei handeln würde. Diese Konversion fin-
det nur auf der Speicherabbildung und nicht auf der Datei selbst
statt. Nach dem Aufruf von elfbegin() behalten die Datei-Offsets, die
Adressen des ELF-Kopfes, die Programmköpfe und die Abschnittsköpfe die
originalen COFF-Werte [siehe elfgetehdr(), elfgetphdr() und
elfgetshdr()). Ein Programm kann elfupdate() aufrufen, um diese
Werte anzupassen (ohne die Datei zu schreiben). Die Bibliothek liefert
dann eine konsistente ELF-Abbildung der Datei. Daten, die über
elfgetdata() gelesen werden, werden übersetzt (die COFF-Symboltabelle
wird im ELF-Format dargestellt etc.). Daten, die über elfrawdata()
gelesen werden, unterliegen keiner Umwandlung; das Programm kann somit
den tatsächlichen Dateiinhalt lesen.
Einige Debugging-Informationen von COFF werden nicht übersetzt; dies
beeinflußt die Semantik eines laufenden Programms nicht. Obwohl die
ELF-Bibliothek COFF unterstützt, wird den Programmierern dringend
geraten, ihre Programme neu zu übersetzen, um dadurch ELF-
Objektdateien zu erhalten.
SIEHE AUCH
creat(2), lseek(2), mmap(2), open(2), truncate(3C), elf(3E),
elfcntl(3E), elfend(3E), elfgetarhdr(3E), elfgetbase(3E),
elfgetdata(3E), elfgetehdr(3E), elfgetphdr(3E), elfgetscn(3E),
elfkind(3E), elfnext(3E), elfrand(3E), elfrawfile(3E),
elfupdate(3E), elfversion(3E), ar(4).
Seite 5 Reliant UNIX 5.44 Gedruckt 11/98