5

我的编译命令是
C:\work\PROJ-test\QNX_SDK\host\win32\x86/usr/bin/qcc -c -Wc,-frandom-seed="sadfsasafssadsa" -Wc,-MP,-MT,C:/work/PROJ-test/N_Manag/src/bld/N_Manag//armle-v7/release/nav_event_rcv.cpp.o,-MMD,C:/work/PROJ-test/N_Manag/src/bld/N_Manag//armle-v7/release/nav_event_rcv.cpp.d -Vgcc_ntoarmv7le -w9 -shared -O3 -ggdb3 -DBUILD_VERSION= -DPASLOGOPTIONS=0x02 -DPASLOGAPPZONES=31,23,30,9,8,3 -DNS1_5PORT -DBOARD_TYPE=PRODUCTION C:/work/PROJ-test/N_Manag/src/nav_event_rcv.cpp -o C:/work/PROJ-test/N_Manag/src/bld/N_Manag//armle-v7/release/nav_event_rcv.cpp.o

当我连续两次运行此命令时,这两个.obj文件是不同的,而不仅仅是时间戳的几个字节。

我们正在切换构建系统,因此我们希望我们的构建是二进制兼容的。我的绝大多数目标文件都是二进制相同的。一些使用__DATE____TIME__宏的部分相差几个字节,但这个完全不同!

我使用了一个 elf-dump 实用程序,发现两个编译之间完全不同的部分是这个

  [544] .debug_info
       PROGBITS        00000000 047d70 1021ed 00   0   0  1
       [00000000]: 

但我不知道PROGBITS包含什么以及为什么它包含用于连续编译的不同项目。该站点仅说明这PROGBITS是一个属性,但没有说明它所指示的内容(以及为什么连续编译会有所不同)。

问题

如何使.obj二进制确定性的生成?

想法

不知何故,正在编译的代码实际上是在.debug_info修改.obj. 这.cpp使用了一堆 boost 库;这可能是原因吗?

更新

我查看了正在生成的程序集文件,它们是不同的。.obj结果s 会有所不同是有道理的。
为什么会发生这种情况仍然没有意义。

更新上面 的qcc命令不是实际执行的编译器命令:qcc是一个编译器“重定向器”,它将调用与-V参数匹配的那个。“真正的”编译器调用是这样的:

C:/work/Proj/QNX_SDK/host/win32/x86/usr/lib/gcc/arm-unknown-nto-qnx6.5.0eabi/4.4.2/cc1plus -Wall -O3 -ggdb3 -DBUILD_VERSION= -DPASLOGOPTIONS=0x02 -DPASLOGAPPZONES=31,23,30,9,8,3 -DNS1_5PORT -DBOARD_TYPE=PRODUCTION -quiet -fno-builtin -fpic -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mlittle-endian -nostdinc -nostdinc++ -D__cplusplus -D__QNX__ -D__QNXNTO__ -D__GNUC__=4 -D__GNUC_MINOR__=4 -D__GNUC_PATCHLEVEL__=2 -D__NO_INLINE__ -D__DEPRECATED -D__EXCEPTIONS -D__unix__ -D__unix -D__ELF__ -fpic -DPIC=1 -D__ARM__ -D__arm__ -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp -D__LITTLEENDIAN__ -D__ARMEL__ -U__ARMEB__ -frandom-seed=sadfsasafssadsa -MP -MT C:/work/Proj/N_Manag/src/bld/N_Manag//armle-v7/release/nav_event_rcv.cpp.o -MMD C:/work/Proj/N_Manag/src/bld/N_Manag//armle-v7/release/nav_event_rcv.cpp.d -isystem C:/work/Proj/QNX_SDK/target/qnx6/usr/include -isystem C:/work/Proj/QNX_SDK/host/win32/x86/usr/lib/gcc/arm-unknown-nto-qnx6.5.0eabi/4.4.2/include -isystem C:/work/Proj/QNX_SDK/target/qnx6/usr/include/cpp/c -isystem C:/work/Proj/QNX_SDK/target/qnx6/usr/include/cpp C:/work/Proj/N_Manag/src/nav_event_rcv.cpp -dumpbase C:/work/Proj/N_Manag/src/nav_event_rcv.cpp -o C:\work\Proj\nav_event_rcv.s

更新

我认为看看.s汇编输出是值得的,因为那里存在重大差异。

请记住,我正在使用-frandom-seed.

.s文件是 105 万行,并且在 ~900k 行开始出现差异。

剩下:

.LASF17345:
.ascii "_ZN5boost6detail7variant21make_initializer_node5app"
.ascii "lyINS_3mpl4pairINS3_INS5_INS3_INS5_INS3_INS5_INS3_I"
.ascii "NS5_INS3_INS5_INS3_INS5_INS3_INS5_INS3_INS5_INS3_IN"
.ascii "S5_INS3_INS5_INS3_INS5_INS3_INS5_INS3_INS5_INS3_INS"
.ascii "5_INS3_INS5_INS3_INS5_INS3_INS5_INS3_INS5_INS1_16in"
.ascii "itializer_rootEN4mpl_4int_ILi0EEEEENS4_6l_iterINS4_"
...

正确的:

.LASF17764:
.ascii "_ZNKSt8numpunctIcE13decimal_pointEv\000"
.LASF10304:
.ascii "cAlpha0\000"
.LASF10222:
.ascii "usWeek\000"
.LASF14117:
.ascii "_ZN5boost10shared_ptrI27TnRespTravelEstimationEvent"
.ascii "EaSERKS2_\000"
...

它持续了几百个字节。

现在我仔细检查了我的无法比较,所有差异部分都是由于boost::detail::variant::make_initializer_node. 该增强功能是否每次都会生成不同的代码?

解析度

原来这是一个gcc错误。我用Y>=2 的.cpp所有排列编译我的,程序集文件和对象是不确定的。-O<X> -ggdb<Y>.s.obj

我发现了一个描述这个问题的 gcc 错误。


我不得不删除另一个帖子。. . 原因。

4

1 回答 1

5

非确定性的原因

通常的罪魁祸首是宏__DATE__, __TIME____TIMESTAMP__编译器将其扩展为从系统时间计算的值。

一种可能性是为二进制文件生成的调试信息是以非确定性方式编写的。例如,当编译器进程中调试信息的内存布局不确定时,就会发生这种情况。我不知道 GCC 的内部结构。但我想这样的事情可能会发生在

  • 在调试信息输出中使用随机 GUID ,
  • 在匿名命名空间中使用符号修饰,或
  • 按顺序序列化一个哈希图,其中键是指向内存的指针。

后一种不确定性来源通常被认为是编译器中的错误(例如GCC PR65015

减轻

__DATE__为了强制,__TIME____TIMESTAMP__宏的可重现扩展,必须模拟和伪造编译器的系统时间(例如,通过使用libfaketime/faketime)。GCC的-Wdate-time命令行选项可用于在使用这些预定义宏时发出警告。

要强制 GUID 和修改的可重现“随机性”,您可以尝试编译-frandom-seed=<somestring>where <somestring>is a unique string for your build(例如,您正在编译的源文件内容的哈希应该这样做)。

或者,您可以尝试在没有调试信息的情况下进行编译(例如,没有-ggdbetc 标志)或稍后使用一些剥离工具删除调试信息部分。

也可以看看

于 2017-01-30T20:29:49.290 回答