LLVMツールを使用してバイナリデータを実行可能ファイルに含める

LLVMツールを使用してバイナリデータを実行可能ファイルに含める

以前は、.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.oSYSV 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 配列として含めようとした結果を防ぎます。これは、明らかな理由なしに多数のリソースが表示された場合、コンパイルが大幅に遅くなる可能性があります。

関連情報