Apakah ada yang punya ide bagaimana mengkompilasi file sumber daya secara statis ke file executable atau shared library menggunakan GCC?
Misalnya, saya ingin menambahkan file gambar yang tidak pernah berubah (dan jika berubah, saya harus tetap mengganti file tersebut) dan tidak ingin file tersebut berada di sekitar sistem file.
Jika ini memungkinkan (dan saya pikir itu karena Visual C ++ untuk Windows juga dapat melakukan ini), bagaimana cara memuat file yang disimpan dalam biner sendiri? Apakah file yang dapat dieksekusi mengurai sendiri, menemukan file, dan mengekstrak datanya?
Mungkin ada opsi untuk GCC yang belum saya lihat. Menggunakan mesin pencari tidak benar-benar menghasilkan hal yang benar.
Saya akan membutuhkan ini untuk bekerja untuk perpustakaan bersama dan ELF-executable normal.
Bantuan apa pun dihargai
Jawaban:
Dengan imagemagick :
Memberikan sesuatu seperti:
Untuk kompatibilitas dengan kode lain, Anda kemudian dapat menggunakan baik
fmemopen
untuk mendapatkan objek "biasa"FILE *
, atau sebagai alternatifstd::stringstream
untuk membuatiostream
.std::stringstream
tidak bagus untuk ini meskipun dan Anda tentu saja dapat menggunakan penunjuk di mana pun Anda dapat menggunakan iterator.Jika Anda menggunakan ini dengan automake, jangan lupa untuk menyetel BUILT_SOURCES dengan tepat.
Hal yang menyenangkan tentang melakukannya dengan cara ini adalah:
sumber
xxd -i infile.bin outfile.h
objcopy
untuk mengonversi data biner secara langsung ke file objek; namun hal ini jarang menjadi perhatian.Perbarui Saya telah tumbuh untuk lebih memilih kontrol penawaran solusi berbasis perakitan John Ripley
.incbin
dan sekarang menggunakan varian untuk itu.Saya telah menggunakan objcopy (GNU binutils) untuk menautkan data biner dari file foo-data.bin ke bagian data yang dapat dieksekusi:
Ini memberi Anda
foo-data.o
file objek yang dapat Anda tautkan ke file yang dapat dieksekusi. Antarmuka C terlihat seperti inisehingga Anda dapat melakukan hal-hal seperti
atau
Jika arsitektur target Anda memiliki batasan khusus tentang tempat penyimpanan data konstan dan variabel, atau Anda ingin menyimpan data tersebut di
.text
segmen agar sesuai dengan jenis memori yang sama dengan kode program Anda, Anda dapat bermain-main denganobjcopy
parameter lagi.sumber
ld
karena format output tersirat di sana, lihat stackoverflow.com/a/4158997/201725 .Anda dapat menyematkan file biner dalam file yang dapat dieksekusi menggunakan
ld
linker. Misalnya, jika Anda memiliki filefoo.bar
maka Anda dapat menyematkannya di executable menambahkan perintah berikut keld
Jika Anda memohon
ld
melaluigcc
maka Anda perlu menambahkan-Wl
Di sini
--format=binary
memberi tahu linker bahwa file berikut adalah biner dan--format=default
beralih kembali ke format input default (ini berguna jika Anda akan menentukan file input lain setelahnyafoo.bar
).Kemudian Anda dapat mengakses konten file Anda dari kode:
Ada juga simbol bernama
"_binary_foo_bar_size"
. Saya pikir itu adalah tipeuintptr_t
tetapi saya tidak memeriksanya.sumber
data_end
array, bukan pointer? (Atau apakah ini C idiomatik?)data_end
akan menjadi pointer maka compiler akan berpikir bahwa ada pointer yang disimpan setelah konten file. Sama halnya, jika Anda akan mengubah tipedata
menjadi pointer maka Anda akan mendapatkan pointer yang terdiri dari byte pertama dari sebuah file, bukan pointer ke awalnya. Aku pikir begitu.const pointer
. Kompiler memungkinkan Anda mengubah nilai non-const pointer, tidak memungkinkan Anda mengubah nilai jika itu adalah array. Jadi mungkin kurang mengetik untuk menggunakan sintaks array.Anda dapat memasukkan semua sumber daya Anda ke dalam file ZIP dan menambahkannya ke akhir file yang dapat dieksekusi :
Ini berfungsi, karena a) Sebagian besar format gambar yang dapat dieksekusi tidak peduli jika ada data tambahan di belakang gambar dan b) zip menyimpan tanda tangan file di akhir file zip . Artinya, file yang dapat dieksekusi adalah file zip biasa setelah ini (kecuali untuk file yang dapat dieksekusi dimuka, yang dapat ditangani oleh zip), yang dapat dibuka dan dibaca dengan libzip.
sumber
install_name_tool
. Selain itu, biner masih berfungsi sebagai executable.Dari http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 :
Saya baru-baru ini perlu menyematkan file dalam file yang dapat dieksekusi. Karena saya bekerja pada baris perintah dengan gcc, dkk dan bukan dengan alat RAD mewah yang membuat semuanya terjadi secara ajaib, tidak langsung jelas bagi saya bagaimana membuat ini terjadi. Sedikit pencarian di internet menemukan peretasan yang pada dasarnya memasukkannya ke akhir eksekusi dan kemudian menguraikan di mana itu didasarkan pada banyak informasi yang tidak ingin saya ketahui. Sepertinya harus ada cara yang lebih baik ...
Dan ada, itu tujuan penyelamatan. objcopy mengubah file objek atau executable dari satu format ke format lainnya. Salah satu format yang dipahami adalah "biner", yang pada dasarnya adalah file apa pun yang tidak ada dalam salah satu format lain yang dipahami. Jadi, Anda mungkin membayangkan idenya: ubah file yang ingin kita sematkan menjadi file objek, lalu dengan mudah dapat ditautkan dengan kode kita yang lain.
Katakanlah kita memiliki nama file data.txt yang ingin kita sematkan di file yang dapat dieksekusi:
Untuk mengubahnya menjadi file objek yang dapat kita tautkan dengan program kita, kita hanya menggunakan objcopy untuk menghasilkan file ".o":
Ini memberitahu objcopy bahwa file masukan kita dalam format "biner", bahwa file keluaran kita harus dalam format "elf32-i386" (file objek pada x86). Opsi --binary-architecture memberi tahu objcopy bahwa file output dimaksudkan untuk "dijalankan" pada x86. Ini diperlukan agar ld menerima file untuk ditautkan dengan file lain untuk x86. Orang akan berpikir bahwa menentukan format keluaran sebagai "elf32-i386" akan menyiratkan hal ini, tetapi sebenarnya tidak.
Sekarang kita memiliki file objek, kita hanya perlu memasukkannya saat kita menjalankan linker:
Ketika kami menjalankan hasilnya, kami mendapatkan output yang didoakan:
Tentu saja, saya belum menceritakan keseluruhan cerita, atau menunjukkan main.c. Ketika objcopy melakukan konversi di atas, ia menambahkan beberapa simbol "linker" ke file objek yang dikonversi:
Setelah menautkan, simbol-simbol ini menentukan awal dan akhir file yang disematkan. Nama simbol dibentuk dengan memasukkan biner dan menambahkan _start atau _end ke nama file. Jika nama file berisi karakter apa pun yang tidak valid dalam nama simbol, maka akan diubah menjadi garis bawah (misalnya data.txt menjadi data_txt). Jika Anda mendapatkan nama yang belum terselesaikan saat menautkan menggunakan simbol ini, lakukan hexdump -C pada file objek dan lihat di akhir dump untuk nama yang dipilih objcopy.
Kode untuk benar-benar menggunakan file yang disematkan sekarang seharusnya sudah cukup jelas:
Satu hal penting dan halus untuk diperhatikan adalah bahwa simbol yang ditambahkan ke file objek bukanlah "variabel". Mereka tidak berisi data apa pun, melainkan alamat mereka adalah nilainya. Saya mendeklarasikannya sebagai tipe char karena nyaman untuk contoh ini: data yang disematkan adalah data karakter. Namun, Anda bisa mendeklarasikannya sebagai apa saja, seperti int jika datanya adalah larik bilangan bulat, atau sebagai struct foo_bar_t jika datanya adalah larik dari bilah foo. Jika data yang disematkan tidak seragam, maka char mungkin yang paling nyaman: ambil alamatnya dan berikan penunjuk ke jenis yang tepat saat Anda melintasi data.
sumber
Jika Anda ingin mengontrol nama simbol yang tepat dan penempatan sumber daya, Anda dapat menggunakan (atau skrip) GNU assembler (bukan bagian dari gcc) untuk mengimpor seluruh file biner. Coba ini:
Perakitan (x86 / lengan):
C:
Apa pun yang Anda gunakan, mungkin yang terbaik adalah membuat skrip untuk menghasilkan semua sumber daya, dan memiliki nama simbol yang bagus / seragam untuk semuanya.
Bergantung pada data Anda dan spesifikasi sistem, Anda mungkin perlu menggunakan nilai penyelarasan yang berbeda (sebaiknya dengan
.balign
untuk portabilitas), atau tipe bilangan bulat dengan ukuran yang berbedathing_size
, atau tipe elemen yang berbeda untukthing[]
larik.sumber
Membaca semua posting di sini dan di Internet saya telah membuat kesimpulan bahwa tidak ada alat untuk sumber daya, yaitu:
1) Mudah digunakan dalam kode.
2) Otomatis (agar mudah dimasukkan dalam cmake / make).
3) Lintas platform.
Saya telah memutuskan untuk menulis alat itu sendiri. Kode tersedia di sini. https://github.com/orex/cpp_rsc
Untuk menggunakannya dengan cmake sangatlah mudah.
Anda harus menambahkan kode tersebut ke file CMakeLists.txt.
Contoh nyata, menggunakan pendekatan tersebut dapat diunduh di sini, https://bitbucket.org/orex/periodic_table
sumber