Hat jemand eine Idee, wie eine Ressourcendatei mithilfe von GCC statisch direkt in die ausführbare Datei oder die gemeinsam genutzte Bibliotheksdatei kompiliert werden kann?
Zum Beispiel möchte ich Bilddateien hinzufügen, die sich nie ändern (und wenn ja, müsste ich die Datei trotzdem ersetzen) und möchte nicht, dass sie im Dateisystem herumliegen.
Wenn dies möglich ist (und ich denke, es liegt daran, dass Visual C ++ für Windows dies auch kann), wie kann ich die Dateien laden, die in der eigenen Binärdatei gespeichert sind? Analysiert die ausführbare Datei selbst, findet die Datei und extrahiert die Daten daraus?
Vielleicht gibt es eine Option für GCC, die ich noch nicht gesehen habe. Die Verwendung von Suchmaschinen hat nicht wirklich das Richtige ausgespuckt.
Ich würde dies benötigen, um für gemeinsam genutzte Bibliotheken und normale ausführbare ELF-Dateien zu arbeiten.
Jede Hilfe wird geschätzt
Antworten:
Mit imagemagick :
Gibt etwas wie:
Aus Gründen der Kompatibilität mit anderem Code können Sie dann entweder
fmemopen
ein "normales"FILE *
Objekt abrufen oder alternativstd::stringstream
ein Objekt erstelleniostream
.std::stringstream
ist jedoch nicht besonders gut dafür und Sie können natürlich einfach einen Zeiger überall dort verwenden, wo Sie einen Iterator verwenden können.Wenn Sie dies mit automake verwenden, vergessen Sie nicht, BUILT_SOURCES entsprechend festzulegen .
Das Schöne daran ist:
quelle
xxd -i infile.bin outfile.h
objcopy
darin, die Binärdaten direkt in eine Objektdatei zu konvertieren. Dies ist jedoch selten ein Problem.Update Ich bin gewachsen, um die Steuerung zu bevorzugen, die John Ripleys Assembler-
.incbin
basierte Lösung anbietet, und verwende jetzt eine Variante dafür.Ich habe objcopy (GNU binutils) verwendet, um die Binärdaten aus einer Datei foo-data.bin mit dem Datenabschnitt der ausführbaren Datei zu verknüpfen:
Dadurch erhalten Sie eine
foo-data.o
Objektdatei, die Sie mit Ihrer ausführbaren Datei verknüpfen können. Die C-Schnittstelle sieht ungefähr so ausso können Sie Sachen wie tun
oder
Wenn Ihre Zielarchitektur besondere Einschränkungen hinsichtlich der Speicherung von konstanten und variablen Daten aufweist oder Sie diese Daten im
.text
Segment speichern möchten, damit sie in denselben Speichertyp wie Ihr Programmcode passen, können Sie mit denobjcopy
Parametern noch mehr spielen.quelle
ld
da das Ausgabeformat dort impliziert ist (siehe stackoverflow.com/a/4158997/201725) .Sie können Binärdateien mit dem
ld
Linker in die ausführbare Datei einbetten . Wenn Sie beispielsweise eine Datei habenfoo.bar
, können Sie diese in eine ausführbare Datei einbetten und die folgenden Befehle hinzufügenld
Wenn Sie den Aufruf sind
ld
bisgcc
dann müssen Sie hinzufügen-Wl
Hier
--format=binary
teilt der Linker mit, dass die folgende Datei binär ist und--format=default
zum Standardeingabeformat zurückschaltet (dies ist nützlich, wenn Sie danach andere Eingabedateien angebenfoo.bar
).Dann können Sie über den Code auf den Inhalt Ihrer Datei zugreifen:
Es gibt auch ein Symbol mit dem Namen
"_binary_foo_bar_size"
. Ich denke, es ist vom Typ,uintptr_t
aber ich habe es nicht überprüft.quelle
data_end
ein Array kein Zeiger? (Oder ist das idiomatische C?)data_end
es sich um einen Zeiger handelt, denkt der Compiler, dass nach dem Dateiinhalt ein Zeiger gespeichert ist. Ähnlich, wenn Sie den Typdata
eines Zeigers ändern, erhalten Sie einen Zeiger, der aus den ersten Bytes einer Datei besteht, anstatt auf den Anfang. Ich glaube schon.const pointer
. Mit dem Compiler können Sie den Wert von Nicht-Konstanten-Zeigern ändern. Wenn es sich um ein Array handelt, können Sie den Wert nicht ändern. Daher ist es möglicherweise weniger tippend, die Array-Syntax zu verwenden.Sie können alle Ihre Ressourcen in eine ZIP-Datei einfügen und diese an das Ende der ausführbaren Datei anhängen :
Dies funktioniert, da a) den meisten ausführbaren Bildformaten egal ist, ob sich hinter dem Bild zusätzliche Daten befinden, und b) zip die Dateisignatur am Ende der zip-Datei speichert . Dies bedeutet, dass Ihre ausführbare Datei danach eine reguläre Zip-Datei ist (mit Ausnahme Ihrer ausführbaren Upfront-Datei, die von Zip verarbeitet werden kann), die mit libzip geöffnet und gelesen werden kann.
quelle
install_name_tool
. Außerdem funktioniert die Binärdatei weiterhin als ausführbare Datei.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:
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:
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:
Wenn wir das Ergebnis ausführen, erhalten wir das Gebet für die Ausgabe:
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:
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:
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.
quelle
Wenn Sie die Kontrolle über den genauen Symbolnamen und die Platzierung von Ressourcen haben möchten, können Sie den GNU-Assembler (der nicht wirklich Teil von gcc ist) verwenden (oder skripten), um ganze Binärdateien zu importieren. Versuche dies:
Montage (x86 / Arm):
C:
Was auch immer Sie verwenden, es ist wahrscheinlich am besten, ein Skript zu erstellen, um alle Ressourcen zu generieren, und schöne / einheitliche Symbolnamen für alles zu haben.
Abhängig von Ihren Daten und den Systemspezifikationen müssen Sie möglicherweise unterschiedliche Ausrichtungswerte (vorzugsweise mit
.balign
aus Gründen der Portabilität) oder ganzzahlige Typen unterschiedlicher Größe fürthing_size
oder einen anderen Elementtyp für dasthing[]
Array verwenden.quelle
Beim Lesen aller Beiträge hier und im Internet bin ich zu dem Schluss gekommen, dass es kein Tool für Ressourcen gibt, nämlich:
1) Einfach im Code zu verwenden.
2) Automatisiert (um einfach in cmake / make enthalten zu sein).
3) Plattformübergreifend.
Ich habe beschlossen, das Tool selbst zu schreiben. Der Code ist hier verfügbar. https://github.com/orex/cpp_rsc
Die Verwendung mit cmake ist sehr einfach.
Sie sollten Ihrer CMakeLists.txt-Datei solchen Code hinzufügen.
Das eigentliche Beispiel für diesen Ansatz kann hier heruntergeladen werden: https://bitbucket.org/orex/periodic_table
quelle