« How much security is too much? | Home | openSUSE 12.3 »

August 21, 2013

Fun with linking data files

Here's a neat trick that I recently discovered, from here.  Say you have a data file which is needed by your program, and you don't want to bother with installing it in /usr/share/somewhere and having to "make install" every time you want to test a tiny change.  You would also prefer to edit it as a separate file, not weave it into your other source code somehow.  You can achieve this by creating an object out of the file itself and linking it into your binary.  The procedure is quite simple:

$ ld -r -b binary -o myfile.o myfile.txt
$ gcc myprogram.o myfile.o -o myprogram

Then, in C:

extern void *_binary_myfile_txt_start;
extern void *_binary_myfile_txt_size;

void get_data()
{
size_t len;
char *v;

len = (size_t)&_binary_myfile_txt_size;
v = malloc(len+1);
memcpy(v, &_binary_myfile_txt_start, len);
v[len] = '\0';
printf("myfile.txt contains '%s'\n", v);
}

Contrary to what's implied by the original article, I don't think you can assume that the data is zero-terminated (why would it add a terminator?  It's binary data as far as the linker is concerned, not text).  This example code includes some extra faffing around to add the terminator.

This technique works quite nicely with automake as well.  In Makefile.am, I put something like this:

src/myfile.o: src/myfile.txt
ld -r -b binary -o src/myfile.o src/myfile.txt
LDADD += src/myfile.o

I use a single Makefile.am at the top level of my project, avoiding "recursive make" where possible, so everything is prefixed with "src/".  The symbols used to find the data in the program therefore look more like this:

extern void *_binary_src_myfile_txt_start;
extern void *_binary_src_myfile_txt_end;

Disadvantages of this technique?  "ld" is not the linker on all platforms supported by autotools, e.g. Mac OS X, so it's not very portable.

Leave a comment