🎁

任意のバイナリをオブジェクトファイルで包む方法

に公開

cmakeでの実装コード

# 任意のバイナリ(BINARY_FILE_TO_WRAP)を特定セクションに格納して
# その先頭アドレスと末尾アドレス、そのサイズをシンボルとして
# 公開するオブジェクトファイルを作成するターゲット(TARGET)を作成
function(add_binary_embedded_obj TARGET BINARY_FILE_TO_WRAP)
  cmake_parse_arguments(FATBIN "" "BFDNAME;SYMBOL_PREFIX" "" ${ARGN})

  if (NOT DEFINED BFDNAME)
    set(BFDNAME "elf64-x86-64")
  endif()

  if (NOT DEFINED SYMBOL_PREFIX)
    set(SYMBOL_PREFIX "$<MAKE_C_IDENTIFIER:${TARGET}>")
  endif()

  add_custom_target(${TARGET}
      BYPRODUCTS ${BINARY_FILE_TO_WRAP}.o
      COMMAND objcopy
          --input binary
          --output ${BFDNAME}
          --rename-section .data=.ANY_SECTION,alloc,load,readonly,data,contents
          --redefine-sym _binary_$<MAKE_C_IDENTIFIER:${BINARY_FILE_TO_WRAP}>_start=${SYMBOL_PREFIX}_start
          --redefine-sym _binary_$<MAKE_C_IDENTIFIER:${BINARY_FILE_TO_WRAP}>_end=${SYMBOL_PREFIX}_end
          --redefine-sym _binary_$<MAKE_C_IDENTIFIER:${BINARY_FILE_TO_WRAP}>_size=${SYMBOL_PREFIX}_size
          ${BINARY_FILE_TO_WRAP} ${BINARY_FILE_TO_WRAP}.o
      COMMAND  objcopy
          --add-section .note.GNU-stack=/dev/null
          --set-section-flags .note.GNU-stack=contents
          ${BINARY_FILE_TO_WRAP}.o ${BINARY_FILE_TO_WRAP}.o
  )
endfunction()
$ # 以下はイメージ
$ cmake --build build --target sample_lib_with_sample_binary
$ nm build/libsample.so.o
0000000000003da8 R sample_binary_end
0000000000003da8 A sample_binary_size
0000000000000000 R sample_binary_metadata_start
# 以下のようにC/C++から参照可能
extern const char sample_binary_start[];
extern const char sample_binary_end[];
extern const unsigned long sample_binary_size;
  • 二個目のobjcopyのとこは、/usr/bin/ld: warning: libsample.so.o: missing .note.GNU-stack section implies executable stackってエラーを回避するために導入。空のセクションを導入している。使用しないスタックは明示的に設定しないと利用可能になったりするらしい。execstackコマンドでも修繕可能。
  • 変数名はTARGETからprefixを設定しているけど任意の名前でいい
  • outputのとこに入れるbfdnameは各アーキテクチャに合わせて設定すべき

背景

バイナリをホストから参照できる形で埋め込みたいシチュエーションがあった。ldにも似たような機能があるがobjcopyの方がシンボル名のrenameまで含めると単純明快。

Discussion