My command-line program's build process generates a binary file (over 500KB) that currently has to be referenced by path from argv. I would like to embed this file in the executable instead.
On Linux, it appears possible to use objcopy
to make an object file from a binary file:
objcopy --input binary --output elf32-i386 --binary-architecture i386 myfile.dat myfile.o
However, the OS X developer toolchain doesn't include an objcopy command. Short of installing binutils, what are the possibilities?
I build my project from Xcode and the file is generated with a custom build rule.
During the link phase, pass the arguments -sectcreate <segname> <sectname> <file>
to the linker. If you're driving the linker via an invocation of the compiler, which is pretty common, you'd pass it as -Wl,-sectcreate,<segname>,<sectname>,<file>
.
You'd make up segment and section names.
You would use the getsectdata()
function along with _dyld_get_image_vmaddr_slide()
to get a pointer to the data at runtime.
As evidenced in this other question about objcopy
, another way to include a binary file into an executable is to use the .incbin
assembler directive. This solution has two main advantages over objcopy
: the developer is in control of the symbol names (objcopy
appears to have a fixed scheme to name them), and, well, it doesn't require objcopy
.
The solution also has advantages over the linker-based -sectcreate
solution. It's cross-platform and accessing the data is much, much more straightforward.
I'm using this Xcode build rule script to generate the file to be included and an assembly file with the .incbin
directive:
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
Then, given a file "somefile.gen" that is processed with this rule, the assembly will look like:
.global _data_start_somefile
.global _data_end_somefile
_data_start_somefile:
.incbin "somefile.gen.out"
_data_end_somefile:
The data can be accessed in C using the data_start_somefile
and data_end_somefile
symbols (the macOS linker prefixes C names with a spurious _
, that's why the assembly file has them):
extern char data_start_somefile, data_end_somefile;
for (const char* c = &data_start_somefile; c != &data_end_somefile; ++c)
{
// do something with character
}
The answer on the other thread has more bells and whistles that some people may find useful (for instance, a length
symbol).
来源:https://stackoverflow.com/questions/34641373/how-do-i-embed-the-contents-of-a-binary-file-in-an-executable-on-mac-os-x