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

时间:2019-02-23 18:22:15

标签: c gcc ld

我使用'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

2 个答案:

答案 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)时有效。