pr0gma pr0gma - 1 month ago 5
C Question

Referencing external global variables fails miserably

I'm trying to embed binary file

B
into executable
A
at linking time, on Linux (64bit).

B
is a simple text file...


Hi, I'm a text file in plain ASCII.


...which is turned into a relocatable object with
ld -r -bbinary -oB.o B
. Its
symtab
reports three global variables, the names of which are pretty self-explanatory:


  1. _binary_B_start

  2. _binary_B_end

  3. _binary_B_size



This is
A.c
...


#include <stdio.h>

extern const size_t _binary_B_size;

int main(int argc, char * * argv)
{
printf("size: %zu\n", _binary_B_size);
return 0;
}


...which is compiled and linked with
B.o
:
gcc -oA A.c B.o
.
Unfortunately, as soon as executable
A
tries to access
_binary_B_size
, it gets abruptly terminated with a
SIGSEGV
.

What am I doing wrong?

AnT AnT
Answer

Apparently you are misunderstanding the semantics of _binary_B_size. It is not a size_t lvalue, as you seem to believe. It is a zero size absolutely positioned section (a label), whose address equals the size of your binary blob data. Try objdump -t on your file an you will see *ABS* in the corresponding column.

So the proper usage would be

extern unsigned char _binary_B_size[];

int main()
{
    printf("size: %zu\n", (size_t) _binary_B_size);
}

You can also use end - start method and get the same result

extern unsigned char _binary_B_start[];
extern unsigned char _binary_B_end[];

int main()
{
    printf("size: %zu\n", (size_t) (_binary_B_end - _binary_B_start));
}

Basically, the main consideration here is that there's no reason for _binary_B_size to be a size_t lvalue. It is effectively a constant with value pre-determined at compile time. There's no reason for it to occupy storage. And what you see above is one way to encode such constant values in object files.

Comments