【问题标题】:`ar` library override timestamp`ar` 库覆盖时间戳
【发布时间】:2011-10-08 04:14:27
【问题描述】:

.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 标志

【问题讨论】:

  • 请原谅我的好奇,但是为什么您希望新的二进制文件完全匹配旧的?也许有更好的方法来实现你想要的。
  • @Frédéric Hamidi 这不是重点。是的,我可以手动返回并破解所有时间戳,但想象一下有 >10 个库和 >100 个二进制文件的情况。您无法返回手动执行此操作。
  • 我在这里看不到任何问题。没有ar 选项可以满足您的需要,并且您已经排除了编辑.a 文件和构建您自己的专用工具的可能性;这归结为一个简单的问题,即您是否可以阅读手册页,并且您显然可以。该工具不能做你需要它做的事情,你既不能使用不同的工具也不能修改现有的工具,问题出在哪里?
  • 首先,这不是金融的标准做法。在金融领域,标准做法是将源代码控制标签嵌入到每个目标文件中,这样您就可以在二进制文件上执行strings。其次,您的方法与 C++ 和匿名命名空间不同,因为编译器在每次编译时都会为匿名命名空间生成一个新名称。
  • @Maxim 在真正的自营交易柜台,确实担心业务连续性,您必须证明没有遗漏或隐藏任何地方。这要求您准确地复制二进制文件,因为即使有很小的偏差,您也会遇到问题(您如何区分“您的交易没有赚钱,因为今天与昨天不同”与“您的交易没有赚钱,因为您更改了二进制文件)? 这是一个残酷的地方,你可以避免篡改代码的问题。

标签: c linux static-libraries unix-ar .a


【解决方案1】:

在 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 会将时间戳放回去。

【讨论】:

  • 请注意,“确定性模式”是一个相对较新的添加。您需要 GNU binutils 2.20(2009-10-16 发布)或更新版本。 ar --version 会告诉你你有什么版本。非 GNU 版本的“ar”可能没有“D”选项(或--version,就此而言)。
  • 不幸的是它没有出现在 osx 版本上,但它也是来自 BSD 版本;它还刷新时间戳(这并不能完全复制库);但是,这是我为将来的项目构建脚本而添加的东西
  • 添加到@KeithThompson,ranlib 命令将时间戳添加回symbol table pseduo-entry。尽管ranlib 提供了-t 选项来“更新存档符号映射的时间戳”,但无论您是否指定它,它都会更新时间戳。这是我对ranlib 2.22 版的体验。我挖了一个e-mail from 2010 mentioning similarars 选项消除了 ranlib 并尊重确定性模式。
【解决方案2】:

使用 dd 会让你覆盖你想要的文件部分:

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

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

【讨论】:

  • 由于我意识到我没有在问题中解释的原因,这类解决方案(编写工具来手动更改时间戳)是不可接受的。不幸的是,这里有非技术因素在起作用。我更新了问题。
  • 您更新为:“可接受的解决方案包括:AR 或其他可能覆盖库中时间戳的程序的标志”那么此解决方案如何不适用?
  • 我同意此解决方案符合 OP 的规定要求。这是最好的解决方案,值得 +50。
  • 它并没有解决问题,因为它仍在篡改时间戳。此外,Frederic 一周前提出了这个建议,我已经表达了对这种方法的担忧。
  • 那么这个问题就无法回答了。你为什么不直接放弃使用库文件并明确链接你需要的目标文件集??
【解决方案3】:

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

【讨论】:

  • 我写了一个 implementation in Haskell 和一个小的可执行文件,供任何需要如何执行此操作的示例的人使用。
【解决方案4】:

默认答案是“ar工具做不到”

【讨论】:

  • 不幸的是,在这种情况下,默认答案是错误的。 ar Dranlib -D 工作正常(对于足够新的工具)。
猜你喜欢
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-27
相关资源
最近更新 更多