我使用'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
答案 0 :(得分:1)
由于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
,所以使用它们是同一回事。
答案 1 :(得分:0)
您的_binary_scna4_jpg_size
符号不是整数。这是一个绝对地址符号。为了获得大小,您需要使用其地址并将其转换为适当的整数类型:
printf("The real size is %td\n", (ptrdiff_t) &_binary_scna4_jpg_size);
但这仅在禁用PIE(gcc -fPIC -no-pie)或静态链接(gcc -static
)时有效。