Da http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 :
Recentemente ho avuto la necessità di incorporare un file in un eseguibile. Dato che sto lavorando alla riga di comando con gcc, et al e non con un sofisticato strumento RAD che fa accadere tutto magicamente, non è stato immediatamente ovvio per me come farlo accadere. Un po 'di ricerca in rete ha trovato un trucco per essenzialmente catarlo alla fine dell'eseguibile e quindi decifrare dove era basato su un mucchio di informazioni che non volevo sapere. Sembrava che ci dovesse essere un modo migliore ...
E c'è, è una copia in soccorso. objcopy converte file oggetto o eseguibili da un formato a un altro. Uno dei formati che comprende è "binario", che è fondamentalmente qualsiasi file che non sia in uno degli altri formati che comprende. Quindi probabilmente hai immaginato l'idea: convertire il file che vogliamo incorporare in un file oggetto, quindi può essere semplicemente collegato con il resto del nostro codice.
Supponiamo di avere un nome file data.txt che vogliamo incorporare nel nostro eseguibile:
# cat data.txt
Hello world
Per convertirlo in un file oggetto che possiamo collegare al nostro programma usiamo semplicemente objcopy per produrre un file ".o":
# objcopy --input binary \
--output elf32-i386 \
--binary-architecture i386 data.txt data.o
Questo dice a objcopy che il nostro file di input è nel formato "binario", che il nostro file di output dovrebbe essere nel formato "elf32-i386" (file oggetto su x86). L'opzione --binary-architecture dice a objcopy che il file di output è pensato per "essere eseguito" su un x86. Ciò è necessario affinché ld accetti il file per il collegamento con altri file per x86. Si potrebbe pensare che specificare il formato di output come "elf32-i386" implichi questo, ma non è così.
Ora che abbiamo un file oggetto dobbiamo solo includerlo quando eseguiamo il linker:
# gcc main.c data.o
Quando eseguiamo il risultato otteniamo l'output pregato:
# ./a.out
Hello world
Ovviamente, non ho ancora raccontato l'intera storia, né ti ho mostrato main.c. Quando objcopy esegue la conversione precedente, aggiunge alcuni simboli "linker" al file oggetto convertito:
_binary_data_txt_start
_binary_data_txt_end
Dopo il collegamento, questi simboli specificano l'inizio e la fine del file incorporato. I nomi dei simboli vengono formati anteponendo binary e aggiungendo _start o _end al nome del file. Se il nome del file contiene caratteri che non sarebbero validi in un nome di simbolo, vengono convertiti in trattini bassi (es. Data.txt diventa data_txt). Se si ottengono nomi irrisolti durante il collegamento utilizzando questi simboli, eseguire un hexdump -C sul file oggetto e cercare alla fine del dump i nomi scelti da objcopy.
Il codice per utilizzare effettivamente il file incorporato dovrebbe ora essere ragionevolmente ovvio:
#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++);
}
Una cosa importante e sottile da notare è che i simboli aggiunti al file oggetto non sono "variabili". Non contengono dati, anzi, il loro indirizzo è il loro valore. Li dichiaro come tipo char perché è conveniente per questo esempio: i dati incorporati sono dati carattere. Tuttavia, puoi dichiararli come qualsiasi cosa, come int se i dati sono un array di numeri interi, o come struct foo_bar_t se i dati erano un qualsiasi array di foo bar. Se i dati incorporati non sono uniformi, allora char è probabilmente il più conveniente: prendi il suo indirizzo e lancia il puntatore al tipo corretto mentre attraversi i dati.