C 为什么';t一个链接的二进制文件';s_尺寸符号是否正常工作?

C 为什么';t一个链接的二进制文件';s_尺寸符号是否正常工作?,c,gcc,ld,C,Gcc,Ld,我使用'ld-r-b binary-o binary.o foo.jpeg'在程序中嵌入资源。工作令人敬畏。我只是想知道为什么int(二进制)大小的符号永远不会正确读取负数或太大的数字,而是在程序运行期间保持不变。 我总是要做_binary_end-_binary_start,这是完美的。似乎对任何人都不管用。。。。为什么呢 没有理由不使用“结束-开始”,因为它取代了尺寸符号,但它仍然让我感到好奇 编辑:代码示例 extern const unsigned char _binary_scna4_

我使用'ld-r-b binary-o binary.o foo.jpeg'在程序中嵌入资源。工作令人敬畏。我只是想知道为什么int(二进制)大小的符号永远不会正确读取负数或太大的数字,而是在程序运行期间保持不变。 我总是要做_binary_end-_binary_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

这个问题是因为(馅饼)而产生的。早期的可执行文件是在相同的内存地址(在编译/链接时确定)加载的,这可能导致攻击,因为攻击者知道程序的特定部分位于哪个地址。因此,该计划得以实施。这有一个副作用,即被定义为绝对地址的大小符号(二进制scna4 jpg大小不是整数值,它是一个“指针”,就像“开始和结束”)在加载时也会被重新定位


如果使用选项
-no pie
编译代码,则可以禁用位置独立性,
\u binary\u scna4\u jpg\u size
将输出正确的值,因为它不会被重新定位。由于PIE现在默认是打开的,指针的值基本上是垃圾。如果您知道重新定位的内存的开始,也可以使用它,但是因为您已经有了
\u binary\u scna4\u jpg\u start
\u binary\u scna4\u jpg\u end
使用它们也是一样的。

您的
\u binary\u scna4\u jpg\u size
符号不是整数。这是一个绝对地址符号。为了获得大小,您需要将其地址转换为适当的整数类型:

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

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

您能显示您尝试使用_binary_size的代码吗?@n.m.编辑问题以包括代码示例我不认为ASLR与此有关(尝试禁用它,看看会发生什么)。它有效,但我不明白。似乎C语义对这个特殊的外部符号的作用非常不同:
&
运算符这里不告诉内存中变量的地址,而是告诉值本身。还有,
\u binary\u size
应该有哪个声明?它可以是
size\u t
,它可以是
int
,它可以是
size\u t*
void*
…所有这些都可以工作。那么,哪种声明更合适?如果你能用更多的解释来改进答案,我会非常高兴。@ceztko
foo.jpeg
不是一个C文件,而无论
ld
如何使用它,都与C无关。
\u binary\u scna4\u jpg\u size
不是一个保持大小的变量。它是一个符号,
ld
放置在表示大小的地址处。该地址没有变量,只有符号。我只是指
\u size
符号。我的想法是假设
&
操作符只处理变量,返回的值总是一个有效的地址。在本例中,返回的值是一个大小,它根本不是有效地址。没关系,这可能只是一个奇怪的语义,适用于这些符号。如果您有建议,我应该声明哪个类型的符号,我会很高兴,因为它不是一个变量,而且大多数类型对我来说都没有多大意义(而且我不能声明它只是
void
)。@ceztko
\u size
就C而言,symbol不是一个变量。它没有在任何C源文件中定义。它仅声明为
extern
。它是由非C代码定义的。C语言没有指定在这种情况下应该发生什么。当然,对于C程序来说,这不是一个有效的地址,因为它不是任何对象的地址。您可以按照自己的意愿声明它,只要它是对象类型,类型就无关紧要(因此无
void
)。没关系,因为您没有访问您声明的(不存在的)对象,您只是获取它的地址。
&
获取对象的地址。它不接受所述对象的值。假设数据的大小为100。链接器在地址100处创建一个
\u size
符号。该地址没有对象和值,但链接器欺骗编译器,使其相信存在。因此,编译器创建一条指令,以获取地址100处不存在的对象的地址。如果您想将其视为一个链接器,它放置一个由编译器通过magic
&
访问的魔法值,您可以,但实际上这只是一个与其他符号一样的常规符号,一个常规的
&