Von http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 :
Ich hatte vor kurzem die Notwendigkeit, eine Datei in eine ausführbare Datei einzubetten. Da ich mit gcc et al. An der Kommandozeile arbeite und nicht mit einem ausgefallenen RAD-Tool, das alles auf magische Weise ermöglicht, war mir nicht sofort klar, wie ich dies erreichen kann. Ein bisschen im Internet gesucht hat einen Hack gefunden, um ihn im Wesentlichen an das Ende der ausführbaren Datei zu kopieren und dann zu entschlüsseln, wo er auf einer Reihe von Informationen basiert, über die ich nichts wissen wollte. Es schien, als ob es einen besseren Weg geben sollte ...
Und es gibt ein Objekt zur Rettung. objcopy konvertiert Objektdateien oder ausführbare Dateien von einem Format in ein anderes. Eines der Formate, die es versteht, ist "binär". Dies ist im Grunde jede Datei, die nicht in einem der anderen Formate vorliegt, die es versteht. Sie haben sich also wahrscheinlich die Idee vorgestellt: Konvertieren Sie die Datei, die wir in eine Objektdatei einbetten möchten, und verknüpfen Sie sie einfach mit dem Rest unseres Codes.
Angenommen, wir haben einen Dateinamen data.txt, den wir in unsere ausführbare Datei einbetten möchten:
# cat data.txt
Hello world
Um dies in eine Objektdatei zu konvertieren, die wir mit unserem Programm verknüpfen können, verwenden wir einfach objcopy, um eine ".o" -Datei zu erstellen:
# objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 data.txt data.o
Dies teilt objcopy mit, dass unsere Eingabedatei im "binären" Format vorliegt, dass unsere Ausgabedatei im "elf32-i386" -Format vorliegen sollte (Objektdateien auf dem x86). Die Option --binary-Architektur teilt objcopy mit, dass die Ausgabedatei auf einem x86 "ausgeführt" werden soll. Dies ist erforderlich, damit ld die Datei zum Verknüpfen mit anderen Dateien für x86 akzeptiert. Man würde denken, dass die Angabe des Ausgabeformats als "elf32-i386" dies implizieren würde, aber dies ist nicht der Fall.
Nachdem wir eine Objektdatei haben, müssen wir sie nur noch einschließen, wenn wir den Linker ausführen:
# gcc main.c data.o
Wenn wir das Ergebnis ausführen, erhalten wir das Gebet für die Ausgabe:
# ./a.out
Hello world
Natürlich habe ich noch nicht die ganze Geschichte erzählt und dir main.c. Wenn objcopy die obige Konvertierung durchführt, werden der konvertierten Objektdatei einige "Linker" -Symbole hinzugefügt:
_binary_data_txt_start
_binary_data_txt_end
Nach dem Verknüpfen geben diese Symbole den Anfang und das Ende der eingebetteten Datei an. Die Symbolnamen werden gebildet, indem Binärdateien vorangestellt und _start oder _end an den Dateinamen angehängt werden. Wenn der Dateiname Zeichen enthält, die in einem Symbolnamen ungültig wären, werden sie in Unterstriche konvertiert (z. B. wird data.txt zu data_txt). Wenn Sie beim Verknüpfen mit diesen Symbolen ungelöste Namen erhalten, führen Sie einen Hexdump -C für die Objektdatei aus und suchen Sie am Ende des Speicherauszugs nach den Namen, die objcopy ausgewählt hat.
Der Code zur tatsächlichen Verwendung der eingebetteten Datei sollte jetzt ziemlich offensichtlich sein:
#include <stdio.h>
extern char _binary_data_txt_start;
extern char _binary_data_txt_end;
main()
{
char* p = &_binary_data_txt_start;
while ( p != &_binary_data_txt_end ) putchar(*p++);
}
Eine wichtige und subtile Sache ist, dass die der Objektdatei hinzugefügten Symbole keine "Variablen" sind. Sie enthalten keine Daten, sondern ihre Adresse ist ihr Wert. Ich deklariere sie als Typ char, weil es für dieses Beispiel praktisch ist: Die eingebetteten Daten sind Zeichendaten. Sie können sie jedoch als alles deklarieren, als int, wenn die Daten ein Array von Ganzzahlen sind, oder als struct foo_bar_t, wenn die Daten ein Array von foo-Balken sind. Wenn die eingebetteten Daten nicht einheitlich sind, ist char wahrscheinlich am bequemsten: Nehmen Sie die Adresse und setzen Sie den Zeiger auf den richtigen Typ, während Sie die Daten durchlaufen.