我使用'ld -r -b binary -o binary.o foo.jpeg'将资源嵌入到我的程序中。工作得很棒。我只是想知道为什么int _binary_size符号永远不会正确读取,负数或太大的数字,但在程序运行之间保持不变。我总是要做_binary_end - _binary_start,它完美无瑕。它似乎对任何人都没有... like here ....为什么会这样?
没有理由不使用end-start,因为它取代了size符号,但它仍然让我很好奇。
编辑:代码示例。
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)。早期的可执行文件被加载到相同的内存地址(在编译/链接时确定),这导致可能的攻击,因为攻击者知道程序的特定部分在哪个地址。因此Address Space Layout Randomization得以实施。这有副作用,即大小符号被定义为绝对地址(_binary_scna4_jpg_size
不是整数值,它是一个“指针”,就像_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
)时有效。