以前は、.o
まずGNUリンカを使用してリソースファイル(画像)をファイルに変換してプログラムに含めました。たとえば、
ld -r -b binary -o file.o file.svg
FreeBSD 12以降、デフォルトのリンカがGNUからLLVMに変更されました。リンカーがコマンドラインオプションを理解しているように見えますが、これによりエラーが発生します。たとえば、
ld -r -b binary -o file.o file.svg
ld: error: target emulation unknown: -m or at least one .o file required
また、コマンドラインオプションを試してみました。ld.lld(1)マニュアルページ:
ld --relocatable --format=binary -o file.o file.svg
ld: error: target emulation unknown: -m or at least one .o file required
私は正しいツールを使用していますか?-m
このオプションに値を指定する必要がありますか?
答え1
追加する必要があるようです-z noexecstack
(ELFバイナリにも追加されます)。LLD 7.0.0)。デフォルトでは、脆弱な実行可能なスタック領域があります。スタックメモリによる活用。あなたのバイナリイメージに実行可能なスタックがないので、これが失敗する理由だと思います。このエラーは、使用するターゲットモックターゲット(使用しないターゲット)をスタックに知らせる必要があるため、混乱します。
デビッド・ハーマンすべての努力をして、以下を含むクロスプラットフォームソリューションを見つけました。
- GNU-ld
- GNU - ゴールド
- GNUライブラリツール
- クロスコンパイルの使用
- LLVMの使用
- 外部の非標準ツールは必要ありません。
魔法の呼び出しは次のとおりです。
$(LD) -r -o "src/mydata.bin.o" -z noexecstack --format=binary "src/mydata.bin"
ほとんどの場合、このバイナリセグメントを読み取り専用に設定しようとします。
$(OBJCOPY) --rename-section .data=.rodata,alloc,load,readonly,data,contents "src/mydata.bin.o"
修正する:
私のシステムは次のようなのでテストできません。
$ uname -r
11.2-STABLE
$ ld -V
GNU ld 2.17.50 [FreeBSD] 2007-07-03
Supported emulations:
elf_x86_64_fbsd
elf_i386_fbsd
これをテストするためにFreeBSD 12.0で仮想マシンを起動し、次のものを見つけました:
$ uname -r
12.0-RELEASE
$ ld -V
LLD 6.0.1 (FreeBSD 335540-1200005) (compatible with GNU linkers)
7.0.0にのみ追加され、-z noexecstack
リストには表示されません。マニュアルページ6.0.1の場合。さらに迷惑なのは、サポートされていない値を指定しても-z
エラーが発生しないことです!
これが動作するかどうかをテストするためにLLVM 7にアップグレードしませんでした。 @Richard Smithは-m
他の答えにモックを付けて正しい解決策を直接見つけました。 LLDがサポートするエミュレーションをリストすると、-V
このパスははるかに簡単になります。
file
このコマンドを使用すると、file.o
SYSV ELFによって識別されることがわかります。これで十分です。ただし、システムとまったく同じにするには、次のようにelf_amd64_fbsd
します。ニックネームのためのelf_x86_64_fbsd
。迷惑なことにld -V
、GNU ldのようにサポートされているLLDエミュレーションを出力しません。
$ file /bin/cat
/bin/cat: ELF 64-bit LSB executable, x86-64, version 1 (FreeBSD), dynamically linked, interpreter /libexec/ld-elf.so.1, for FreeBSD 12.0 (1200086), FreeBSD-style, stripped
$ ld -r -b binary -m elf_amd64 -o data.o data.bin
$ file data.o
data.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ ld -r -b binary -m elf_amd64_fbsd -o data.o data.bin
$ file data.o
data.o: ELF 64-bit LSB relocatable, x86-64, version 1 (FreeBSD), not stripped
elf_amd64_fbsd
はいelf_x86_64_fbsd
(参照D7837そしてD24356)。 LLDが-V
出力にエミュレーションを追加してください。
答え2
ソースコードを確認してみると正しい内容です。ターゲットシミュレーション私のプラットフォームはelf_amd64。したがって、バイナリファイルからオブジェクトファイルへの変換は、以下を使用して実行できます。
ld -r -b binary -m elf_amd64 -o file.o file.svg
答え3
本当に苦労する価値がありますか?これは当初移植性がありません。
.svgをC char配列の例に変換することをお勧めします。
$ cat Makefile
.SUFFIXES: .svg
.svg.c:
od -tx1 $< | sed 's/ /,0x/g;s/[^,]*//;1s/,/char $*[]={/;$$s/$$/};/' > $@
$ make file.o
od -tx1 file.svg | sed 's/ /,0x/g;s/[^,]*//;1s/,/char file[]={/;$s/$/};/' > file.c
cc -c -o file.o file.c
rm file.c
もちろん、配列名を他の/より強力な名前に設定することもできます(たとえば、GNU makeを使用するchar $(subst /,_,$*)[] = ...
代わりに)。あるいは、恐ろしいod + sedの組み合わせの代わりにchar $*[] = ...
Cで書かれた一時的なコンバーターを構築することもできます。bin2c
答え4
私は次の簡単なツールを提供したいと思います。リソースの埋め込み。範囲は似ていますが、LLVMに基づいていません。デフォルトでは、NASMまたはGasを使用してアセンブリファイルを介してバイナリを含めます。これは高度なCMakeインターフェースでラップされます。
add_executable(res_example "example.cpp")
res_embed(TARGET res_example NAME "my_cool_image" PATH ${CMAKE_CURRENT_SOURCE_DIR}/file.svg)
その後、プログラムに含まれるリソースを次のように使用できます。
#include "res_embed.h"
#include <cstdio>
int main(int argc, char* argv[])
{
printf("%s", res::embed::get("my_cool_image"));
return 0;
}
ほとんどのプラットフォームでガスが利用可能な場合、ソリューションは移植可能です。また、NASMを介してWindows上でMSVCをサポートしています。これは、次の点でLLDアプローチと似ています。 res_embed は、リソースを C 配列として含めようとした結果を防ぎます。これは、明らかな理由なしに多数のリソースが表示された場合、コンパイルが大幅に遅くなる可能性があります。