2015/02/09(月)データファイルをバイナリに埋め込みたい

表題のとおり。
バイナリファイルをデータ配列として取り込むことが可能です。
binary utilityのobjcopyコマンドのヘルプを見ると、入出力フォーマットにbinaryやhexといった指定ができることが判ります。
実際にファイルを吐かせてfileコマンドやreadelfコマンドを使って、試行錯誤した後でビルドできる状態にできたので、
メモとして記しておきます。しっかりとマニュアルを読めば試行錯誤は不要だとは思います...(無力

結合したいファイルを作る

$ echo -ne "1234567890\0" > foo.txt
$ objcopy -Ibinary -Bi386 -Oelf64-x86-64 foo.txt foo.o
  • Iは入力フォーマット。テキストファイルを作っていますが、バイナリファイルでも同様です。
  • Bはアーキテクチャですが、入力ファイルからアーキテクチャが推定できない場合のみ有効だそうです。
  • Oは出力フォーマット。ビルドする際に結合したいオブジェクトファイルに合わせて選択します。
あとで記載するreadelfのヘッダ情報がCファイルから生成したobjectと一致するようにすると良いです。

サンプルコード

結果からの後付になりますが、変換した後のファイルをシンボルダンプするとソレらしいものがあります。
実際にオブジェクトファイルの内容と易化の出力とを照らしあわせていくとなんとなくイメージがわきます。
変数に型は与えていないので、適当な型の変数としてextern宣言しておきます。
シンボルのアドレス情報がデータ本体のアドレスになるので、&演算子でアドレスを得ます。
start/endはそれで納得しますが、sizeも&で取得する必要があります。
値を保持する変数を用意してくれているわけではなく、値はシンボルのアドレス情報として格納されているようです。
$ cat sample.c
#include <stdio.h>

main()
{
extern char _binary_foo_txt_start;
extern char _binary_foo_txt_end;
extern char _binary_foo_txt_size;

printf("%16x\n%16x\n%16x\n%s\n",
		&_binary_foo_txt_start,
		&_binary_foo_txt_end,
		&_binary_foo_txt_size,
		&_binary_foo_txt_start);
}

$ gcc -c sample.c -o sample.o
$ gcc sample.o foo.o -o sample
$ ./sample 
          601040
          60104b
               b
1234567890
$

検証

生成していたオブジェクトファイルのヘッダ情報を参照しておきましょう..
リンクに失敗する場合には 整合性がとれているか確認していきます.
シンボルが見つからない時も これで探すと良いでしょう.
$ readelf -a sample | grep _binary_
    51: 000000000000000b     0 NOTYPE  GLOBAL DEFAULT  ABS _binary_foo_txt_size
    54: 000000000060104b     0 NOTYPE  GLOBAL DEFAULT   24 _binary_foo_txt_end
    55: 0000000000601040     0 NOTYPE  GLOBAL DEFAULT   24 _binary_foo_txt_start

$ readelf -h sample.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          328 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         13
  Section header string table index: 10

$ readelf -h foo.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          112 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         5
  Section header string table index: 2


対応フォーマット

objcopyのビルド方法やバイナリパッケージの場合はディストリに依存するかもしれません。
"--info"オプションでリストアップすることができました。
これに気づくのが後になってロスが大きかったです。
Display a list showing all architectures and object formats available.
$ objcopy --info
BFD header file version (GNU Binutils for Ubuntu) 2.24
elf64-x86-64
 (header little endian, data little endian)
  i386
elf32-i386
 (header little endian, data little endian)
  i386
elf32-x86-64
 (header little endian, data little endian)
  i386
a.out-i386-linux
 (header little endian, data little endian)
  i386
pei-i386
 (header little endian, data little endian)
  i386
pei-x86-64
 (header little endian, data little endian)
  i386
elf64-l1om
 (header little endian, data little endian)
  l1om
elf64-k1om
 (header little endian, data little endian)
  k1om
elf64-little
 (header little endian, data little endian)
  i386
  l1om
  k1om
  plugin
elf64-big
 (header big endian, data big endian)
  i386
  l1om
  k1om
  plugin
elf32-little
 (header little endian, data little endian)
  i386
  l1om
  k1om
  plugin
elf32-big
 (header big endian, data big endian)
  i386
  l1om
  k1om
  plugin
pe-x86-64
 (header little endian, data little endian)
  i386
pe-i386
 (header little endian, data little endian)
  i386
plugin
 (header little endian, data little endian)
srec
 (header endianness unknown, data endianness unknown)
  i386
  l1om
  k1om
  plugin
symbolsrec
 (header endianness unknown, data endianness unknown)
  i386
  l1om
  k1om
  plugin
verilog
 (header endianness unknown, data endianness unknown)
  i386
  l1om
  k1om
  plugin
tekhex
 (header endianness unknown, data endianness unknown)
  i386
  l1om
  k1om
  plugin
binary
 (header endianness unknown, data endianness unknown)
  i386
  l1om
  k1om
  plugin
ihex
 (header endianness unknown, data endianness unknown)
  i386
  l1om
  k1om
  plugin

               elf64-x86-64 elf32-i386 elf32-x86-64 a.out-i386-linux pei-i386 
          i386 elf64-x86-64 elf32-i386 elf32-x86-64 a.out-i386-linux pei-i386 
          l1om ------------ ---------- ------------ ---------------- -------- 
          k1om ------------ ---------- ------------ ---------------- -------- 
        plugin ------------ ---------- ------------ ---------------- -------- 

               pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big 
          i386 pei-x86-64 ---------- ---------- elf64-little elf64-big 
          l1om ---------- elf64-l1om ---------- elf64-little elf64-big 
          k1om ---------- ---------- elf64-k1om elf64-little elf64-big 
        plugin ---------- ---------- ---------- elf64-little elf64-big 

               elf32-little elf32-big pe-x86-64 pe-i386 plugin srec symbolsrec 
          i386 elf32-little elf32-big pe-x86-64 pe-i386 ------ srec symbolsrec 
          l1om elf32-little elf32-big --------- ------- ------ srec symbolsrec 
          k1om elf32-little elf32-big --------- ------- ------ srec symbolsrec 
        plugin elf32-little elf32-big --------- ------- ------ srec symbolsrec 

               verilog tekhex binary ihex 
          i386 verilog tekhex binary ihex 
          l1om verilog tekhex binary ihex 
          k1om verilog tekhex binary ihex 
        plugin verilog tekhex binary ihex