1

What is the proper way of accessing the actual value of an *ABS* (absolute, not-to-be-relocated) symbol from C?

I'm using ld to embed data (... a HTML template) in an executable (... following the method described in https://csl.name/post/embedding-binary-data/). As in:

ld -r -b binary [the_file_to_be_embedded] -o [some_object.o]

Then, I'm using

const char _some_object_start;
const char _some_object_end;
const int _some_object_size;

in the actual code. The actual linked text works nicely by getting char pointers with &_some_object_start; reading the size keeps breaking in interesting, platform-dependent ways though: on ARM64, (long) &_some_object_size actually ends up being the size, but on x64 the compiler is trying to make it PC-relative and doesn't end up with the right thing.

For reference, this is how the actual symbol table looks like:

SYMBOL TABLE:
00000000 l    d  .data  00000000 .data
0000000d g       .data  00000000 _binary_hello_world_txt_end
0000000d g       *ABS*  00000000 _binary_hello_world_txt_size
00000000 g       .data  00000000 _binary_hello_world_txt_start

(obtained by objdump -x.)

I presume ld adds size data assuming that there is some reasonable way for code linked with it to read it, therefore the question.

(... which is more on the theoretical side, as &_obj_end - &obj_start does still resolve to the actual data length; I'm curious specifically about _obj_size though.)

Latanius
  • 2,553
  • 2
  • 23
  • 21

1 Answers1

1

The value of a symbol is its address, so &symbol_name should retrieve it.

example.c

#include <stdio.h>
extern char abs_sym;
int main() { printf("%p\n", (void*)&abs_sym); }

run example:

$ gcc ldabs.c  -no-pie -Wl,--defsym=abs_sym=0xab && ./a.out
  0xab
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 2
    Why cast the address to `long` instead of `void *` and use the `"%p"` format to print it? There's no guarantee that `long` is the same size as a pointer, not even on a 64-bit system. – Some programmer dude Jul 13 '19 at 11:08
  • 1
    @Someprogrammerdude %p prints in hexadecimal and I wanted decimal and when you're comparing compiler/linker behavior on x86-64 you're already in implementation-defined area anyway, but sure `"%p", (void*)x` is of course the most proper way to print a pointer. – Petr Skocik Jul 13 '19 at 11:36
  • @Someprogrammerdude Point taken, though. I'm setting and printing (%p) hex values now. – Petr Skocik Jul 13 '19 at 11:38
  • yeaaah, the gcc x86_64 issue is what I bumped into, too. Sadly, one of the target platforms is just that... it's interesting though how it's working on clang! do you think it's a gcc bug, or is it just unspecified? – Latanius Jul 14 '19 at 00:47
  • @Latanius Found the cause of the problem. The gcc was passing `-pie` to the linker, which causes the absolute symbol to be handled incorrectly. Passing `-no-pie` solves the problem. (My clang doesn't do that so clang works with absolute symbols by default.) – Petr Skocik Jul 14 '19 at 10:41
  • nice, thanks!!! Yeah, this indeed seems to be the solution. (... actually, it'd be nice if it also worked with -fPIE since technically it's a different sort of symbol... the linux linker disagrees apparently.) (... also, would you mind adding an update to the answer to point out that "position independence" is the key? it feels like it's easy to miss if it's only in the comments :) Thanks!) – Latanius Jul 15 '19 at 00:55