🎁
任意のバイナリをオブジェクトファイルで包む方法
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