11

.a 存档格式标头需要时间戳。这在我重建静态库时导致了无数的头痛,主要是因为我无法准确地重现原始二进制文件。

例如(这是在我的 Mac 上,但同样的事情发生在 x64 linux 上):

$ cat foo.h
int foo();
$ cat foo.c
#include "foo.h"
int foo() { return 3; }
$ gcc -fno-pic -m64 -arch x86_64 -I/usr/local/include -O3 -c foo.c -o foo.o -fpic
$ ar rcs libfoo.a foo.o
$ md5 libfoo.a
MD5 (libfoo.a) = 0d0e6606185de4e994c47f4a0e54c1c4
$ mv libfoo.a libfoo.a1
$ ar rcs libfoo.a foo.o
$ md5 libfoo.a
MD5 (libfoo.a) = 22a69d42e1325ae8f978c2a18a4886da    

为了向自己证明唯一的区别是时间,我使用了基于 hexdump 的差异:

$ diff <(hexdump libfoo.a) <(hexdump libfoo.a1)
2,3c2,3
< 0000010 20 20 20 20 20 20 20 20 31 33 31 31 30 34 33 30
< 0000020 38 36 20 20 35 30 31 20 20 20 32 30 20 20 20 20
---
> 0000010 20 20 20 20 20 20 20 20 31 33 31 31 30 34 32 38
> 0000020 37 31 20 20 35 30 31 20 20 20 32 30 20 20 20 20

如果您使用标题格式进行反解,则它对应于时间字段。

手册页没有说明是否可以覆盖标头中的时间戳。有什么想法吗?

编辑:是的,可以返回并物理破解文件以使用任意时间戳。是的,可以改变程序的行为。考虑到这种情况的情况,并非所有这些都是严格的技术性质,手动更改时间戳的工具是不可接受的,修改版本也不可接受,也ar不会弄乱实际系统时间。

编辑:在这种情况下,我必须证明,在构建路径没有任何不可接受的偏差的情况下,可以从源代码生成二进制文件。在某些行业(例如金融),这显然是一种标准做法。更改时间戳的手动工具是不可接受的(因为使用了不在原始构建路径中的特殊工具)。的手卷版本ar是不可接受的(类似问题)。更改系统时钟的问题在于构建必须完美协调(这是一个长达一小时的构建,包含大量库和二进制文件)。可接受的解决方案包括:

  • 标记到 AR 或其他可能覆盖库中时间戳的程序
  • 现有的(年龄 > 1 岁)工具来执行此操作
  • 在进行链接时可能会覆盖来自 ar 的时间戳的 GCC 标志
4

4 回答 4

20

在 ar 中使用“确定性模式”。参见手册中关于 ar 的选项“D”。

me@mybox:~$ rm libfoo.a; touch foo.o; ar rcsD libfoo.a foo.o; md5sum libfoo.a
3ecae045133ff919d1e42f6050ef56be  libfoo.a
me@mybox:~$ rm libfoo.a; touch foo.o; ar rcsD libfoo.a foo.o; md5sum libfoo.a
3ecae045133ff919d1e42f6050ef56be  libfoo.a

如果您ranlib之后使用,请确保您使用的是ranlib -D; 否则ranlib会将时间戳放回去。

于 2011-07-25T23:40:43.600 回答
5

使用 dd 将让您覆盖所需的文件部分:

dd if=libfoo.a1 of=libfoo.a skip=30 seek=30 count=4 bs=1 conv=notrunc

当然,这意味着您将在其他地方需要您的时间戳(您可以有一个非常基本的 c 程序,它获取当前时间并以 little endian 或 big endian 输出,然后使用 dd 您可以覆盖库文件)。使用 dd,我可以覆盖 .a 文件并且没有差异结果

于 2011-07-25T00:56:51.480 回答
0

如果二进制文件的其余部分始终完全相同,那么您可以在.a文件中找到时间戳并用固定值(如全零)覆盖它。

于 2011-07-31T02:50:19.973 回答
-3

默认答案是“它不能由 ar 工具完成”

于 2011-07-24T15:28:09.227 回答