如这篇关于objcopy
的问题所证明的那样,将二进制文件包含到可执行文件中的另一种方法是使用.incbin
汇编指令。相对于objcopy
,这种解决方案有两个主要优点:开发者可以控制符号名称(objcopy
似乎有一个固定的命名规则),而且不需要用到objcopy
。
相比基于链接器的-sectcreate
解决方案,此解决方案也有优势。它跨平台,并且访问数据要简单得多。
我正在使用这个Xcode构建规则脚本来生成要包含的文件和带有.incbin
指令的汇编文件:
my_generation_tool -o $DERIVED_FILE_DIR/$INPUT_FILE_NAME.out $INPUT_FILE_PATH
export AS_PATH=$DERIVED_FILE_DIR/$INPUT_FILE_NAME.out.s
echo "\t.global _data_start_$INPUT_FILE_BASE" > $AS_PATH
echo "\t.global _data_end_$INPUT_FILE_BASE" >> $AS_PATH
echo "_data_start_ $INPUT_FILE_BASE:" >> $AS_PATH
echo "\t.incbin \"$INPUT_FILE_NAME.out\"" >> $AS_PATH
echo "_data_end_$INPUT_FILE_BASE:" >> $AS_PATH
然后,给定一个被这个规则处理的文件 "somefile.gen",汇编代码将如下所示:
.global _data_start_somefile
.global _data_end_somefile
_data_start_somefile:
.incbin "somefile.gen.out"
_data_end_somefile:
数据可以使用
data_start_somefile
和
data_end_somefile
符号在C中访问(macOS链接器会在C名称前加上虚假的
_
,这就是为什么汇编文件中有它们的原因):
extern char data_start_somefile, data_end_somefile;
for (const char* c = &data_start_somefile; c != &data_end_somefile; ++c)
{
// do something with character
}
另一篇帖子中的答案包含更多功能,其中一些人可能会发现有用(比如一个 length
符号)。
getsectiondata
是否有任何真相可以避免使用下划线函数的需求? - zneakgetsectiondata()
的方式是它被记录在文档中,但似乎并没有。为什么你对“带下划线”的函数如此迷信?它们已经被记录并且完全安全可用。如果你想要可执行文件的Mach头,而不是任何动态库,并且你正在可执行文件中编写代码,你可以简单地引用&_mh_execute_header
。请参阅/usr/include/mach-o/ldsyms.h
。顺便说一句,你可以将索引0传递给dyld(3)函数(例如_dyld_get_image_vmaddr_slide()
)来引用主可执行文件。 - Ken Thomasesgetsectdata
不会调整ASLR滑动值,所以也许我应该担心苹果最终会修复它,导致我的代码出现问题。我相信我们都怀疑他们不会这样做,但我也怀疑getsectiondata
不会消失,正是因为这个原因。无论如何,从任何角度来看,这都感觉像使用dlsym
获取全局变量句柄一样hacky和奇怪(因为本质上就是这样),所以我可能会选择让它感觉最不糟糕的函数。 - zneakgetsectdata()
的 man 页面(我没有链接到它,因为它似乎不在线上)说:“Getsectdata 与 getsectdatafromheader 相同,只是其第一个参数为链接编辑器定义的符号 _mh_execute_header。” 同一 man 页面还说,您必须将getsectdatafromheader()
的结果添加滑动值。虽然我猜它只适用于动态库,但可执行文件也会被 ASLR 滑动,除非它们没有构建为位置无关。 - Ken Thomases