Sunday, November 11, 2012

Emedding Binary data in an executable

I have a fast little game engine that I've written called Dancing Squid. Recently I thought it would be nice to make it a little more user-friendly and print debug text to the screen of the render window. This way the user wouldn't have to keep looking at the console to see what's gone wrong. It'd also be useful for instrumentation type things like FPS and memory used.

If I 'm going to be rendering out error messages - I need a font but those error messages might include "Font file missing!", what's a programmer to do?

Well the way that immediately springs to mind for me is to embed the binary data in the .exe file directly. Can't lose the font then! (I decided to use silkscreen which has a permissive license and looks nice and minimal)

Here's how it's done using the standard gcc toolset.

ld -r -b binary -o [output_name].o [binary_file_to_embed]

This outputs an object file which can be linked into the exe at compile time. But then how do you reference the data? Well you need to get a special reference keyword and this can be done with another tool.

objdump -x [output_name].o

Which in my case outputs something like:

[  0](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 _binary_[data_id]_start
[  1](sec -1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x0000480c _binary_[data_id]_size
[  2](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x0000480c _binary_[data_id]_en

[data_id] is a name generated from the file being embedded. You can then use these names to get your data.


extern char binary_[data_id]_start[];

int main(int argc, char* argv[])
    char* p = binary_[data_id]_start;
    return 0;

Then to compile this:

gcc -o embed_test.exe embed_test.c [output_name].o

And that's fine, I managed to add that into my makefile and everything worked fine.

But I also compile to Android and I'd like this to work there too. Android make file's for C/C++ projects are some non-standard script and you can't add object data :( Somewhere hidden in a maze of different makefile and bashscripts Android uses the same tools, it uses gcc or g++ so it's possible but I didn't feel like trying to untangle all that so I looked for a different approach.

(I did get as far as making the object file for android - this is pretty simple and just requires you to use the arm version of ld that comes with android-ndk)

Second Approach to embedding data in a executable

If that fails - how about whacking the binary data into a header file as an array of bytes (unsigned chars). It's not a hard tool to write but I suspected someone had already written it - and they had; jetro

I ended up using that to generate my header file.

size_t data_len = 18444;
unsigned char data[18444]=

And there we go - embedded data that works on both windows, android and any other platform that I think to add in the future.

No comments: