`ar` 库覆盖时间戳
.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 年)工具,可以执行此操作
- GCC 的标志,可以在进行链接时覆盖来自 ar 的时间戳
the .a archive format header requires a timestamp. This has led to countless headaches when I rebuild a static library, mainly because I can't exactly reproduce the original binary.
For example (this is on my Mac, but the same thing happens in 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
To prove to myself that the only difference was time, I took a diff based on 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
which, if you backsolve using the header format, corresponds to the time field.
Manpage gives no indication of whether or not it is possible to override the timestamp from the header. Any thoughts?
Edit: yes, it is possible to go back and physically hack the file to use an arbitrary timestamp. yes, it is possible to change the program's behavior. Given the circumstances surrounding the situation, not all of which are strictly technical in nature, a tool to manually change the timestamp is not acceptable, nor is a modified version of ar
, nor is messing with the actual system time.
Edit: In this circumstance, I have to prove that, without any unacceptable deviation from the build path, the binaries can be produced from source. In some industries (e.g. finance) this is apparently a standard practice. A handrolled tool to change the timestamps is unacceptable (because a special tool, which was not in the original build path, was used). A handrolled version of ar
is unacceptable (similar problem). The problem with changing system clock is that the build would have to be perfectly coordinated (it is an hour-long build with a lot of libraries and binaries). Acceptable solutions include:
- flags to AR or other programs that could override the timestamp in the library
- an existing (age > 1 year) tool to do this
- flags to GCC that could override the timestamp coming from ar when doing the linking
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在 ar 中使用“确定性模式”。请参阅手册中 ar 的选项“D”。
如果您之后使用
ranlib
,请确保您使用ranlib -D
;否则ranlib
会将时间戳放回去。Use "deterministic mode" in ar. See option "D" for ar in manual.
If you use
ranlib
afterwards, make sure you're usingranlib -D
; otherwiseranlib
will put the timestamp back.使用 dd 可以让你覆盖你想要的文件部分:
当然,这意味着你需要在其他地方使用时间戳(你可以有一个非常基本的 C 程序,它获取当前时间并以小端或大端输出然后使用 dd 你可以覆盖库文件)。使用 dd,我可以覆盖 .a 文件并且不会得到 diff 结果
using dd will let you overwrite the part of the file you want:
of course this means that you'll need your timestamp somewhere else (you can have a very basic c program that takes the current time and outputs it in little endian or big endian and then with dd you can overwrite the library file). using dd, i can overwrite the .a file and get no diff results
如果二进制文件的其余部分始终完全相同,那么您可以在
.a
文件中找到时间戳并用固定值(如全零)覆盖它。If the rest of the binary is always exactly the same, then you could locate the timestamp in the
.a
file and override it with a fixed value (like all zeroes).我在 GitHub 中编写了一个 python 脚本,用于重置没有
-D
选项的旧版本ar
的时间戳。我已经在Python 3.8.10和Python 2.6.6中进行了测试。
https://gist.github.com/Supermanuu/ccdbe0c5d15d41dd1df75ad288e2a30a
清除时间戳的使用示例:
用法:
I wrote a python script in my GitHub to reset timestamps for older versions of
ar
that didn't have-D
option.I have tested in Python 3.8.10 and Python 2.6.6.
https://gist.github.com/Supermanuu/ccdbe0c5d15d41dd1df75ad288e2a30a
Use example for clearing timestamps:
Usage:
默认答案是“ar工具做不到”
The default answer is "It can't be done by the ar tool"