为什么链接的二进制文件的 _size 符号不能正常工作?

Why doesn't a linked binary file's _size symbol work correctly?

我使用 'ld -r -b binary -o binary.o foo.jpeg' 在我的程序中嵌入资源。效果棒极了。我只是想知道为什么 int _binary_size 符号永远不会正确读取负数或太大的数字,但在程序运行之间保持不变。 我总是必须做 _binary_end - _binary_start,它完美地工作。似乎对任何人都没有用... like here ....这是为什么?

没有理由不使用 end-start,因为它取代了尺寸符号,但它仍然让我感到好奇。

编辑:代码示例。

extern const unsigned char _binary_scna4_jpg_start;
extern const unsigned char _binary_scna4_jpg_end;
extern const int _binary_scna4_jpg_size;

int size = &_binary_scna4_jpg_end - &_binary_scna4_jpg_start;
printf("Size is %d vs %d \n", size, _binary_scna4_jpg_size);

这会打印:

Size is 1192071 vs -385906356 

第一个数字是二进制文件的正确大小,我的所有图像都可以完美读取。

良好测量的 nm 输出:

0000000000123087 D _binary_scna4_jpg_end
0000000000123087 A _binary_scna4_jpg_size
0000000000000000 D _binary_scna4_jpg_start

问题的出现是因为 Position-Independent Executables (PIE). Earlier executables were loaded at the same memory addresses (which were determined at compile/link time) which led to possible attacks because the attacker knew at which address specific parts of programs were. Therefore Address Space Layout Randomization 已实施。这具有将大小符号定义为绝对地址的副作用(_binary_scna4_jpg_size 而不是 整数值,它是一个 "pointer" 就像 _start 和 _end)加载时也会重新定位。

如果您使用选项 -no-pie 编译您的代码,您可以禁用位置独立并且 _binary_scna4_jpg_size 将输出正确的值,因为它不会被重定位。由于 PIE 现在默认打开,指针的值基本上是垃圾。如果您知道重定位内存的开头,也可以使用它,但是由于您已经有了 _binary_scna4_jpg_start_binary_scna4_jpg_end,所以使用它们是一样的。

您的 _binary_scna4_jpg_size 符号不是整数。这是一个绝对地址符号。为了获得大小,您需要获取它的 地址 并转换为适当的整数类型:

printf("The real size is %td\n", (ptrdiff_t) &_binary_scna4_jpg_size);

但这仅在禁用 PIE (gcc -fPIC -no-pie) 或静态链接 (gcc -static) 时有效。