gcc binary output differs whether it is built from *.o or *.a

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi all,

To fully understand the purpose of my e-mail, you shall know what my
goal is: "produce reproducibly identical binaries and libraries on all
my development computers" (ie.: produce binaries and libraries which
MD5 checksum will be the same on all my development computers).

Here is a light description of my environment:

Computer 1:
  - hostname: dev1
  - user: userX
  - home: /home/userX
  - OS: RHEL4-U4

Computer 2:
  - hostname: dev2
  - user: userY
  - home: /home/userY
  - OS: RHEL4-U4

On both computers, packages set installed are equivalent
(cloned). Only user names used for login differs from one computer to
the other (will be important, considering static libraries checksum).

Now the full version of my e-mail object: "Why does gcc output (MD5
checksum) differs when I build a binary using the project object files
(*.o) or the project convenience libraries (*.a)?".

In my peregrinations, first of all, I realized that the first source
of variable checksum was the non-systematic use of "-fPIC -DPIC" in
gcc options for object files generation. Therefore, I configured my
project with "--with-pic" too force the use of PIC on each object
generated. The result was as expected: all object files produced,
whether on dev1 or on dev2 are identical (same md5sum). Nevertheless,
the generated binary is finally still different on dev1 and dev2.

I looked at the convenience libraries I produced and discovered that
none of them was identical between dev1 and dev2 one. A quick edit of
the produced ar archives and a little reading on
http://en.wikipedia.org/wiki/Ar_%28Unix%29 gave me the explanation of
all that. Ar, as tar also do, stores various info on objects archived:
such as its modification timestamp, its uid, its gid, etc. Therefore,
AFAK, in any case, convenience libraries could be produced two times
successively with the same MD5 checksum (i.e.: if object files are
also re-generated, timestamps will change MD5 checksum). Therefore, to
understand what was going on in there, I extracted all ar archive
contents in one directory and I checked all my object files. All
object files extracted from convenience libraries were the same as the
one spread over my project directory. Good point, but it was also what
I expected.

Therefore I tried a little workaround to reach my goal: extract all
object files contained in my convenience libraries and build my binary
from these extracted object files. And here are the results obtained
on both computers:

dev1:
  - Checksum of binary built from *.a: fda85686a499d273596d33b661a01913
  - Checksum of binary built from *.o: 9e1525d404db45bf920e54a8728313eb

dev2:
  - Checksum of binary built from *.a: 5f8c6a658343741f1a251f00ab60a9c3
  - Checksum of binary built from *.o: 9e1525d404db45bf920e54a8728313eb

Then, when building my binary with object files, both generated
binaries are identical on dev1 and dev2. But if I use convenience
libraries as input, generated binaries are different.

So, to put it in a nutshell, all my generated objects file are
identical on dev1 and dev2 and object files contained in my
convenience libraries are all identical. The only difference
remaining, before I generate my binary, resides in the generated
convenience libraries which are not identical, but their contents
are. So AFAK, this slight difference shall not make the difference. So
"why does gcc output (MD5 checksum) differs when I build a binary
using the project object files (*.o) or the project convenience
libraries (*.a)?" and "what can I do to fix that?".

Here are the commands I executed on dev1 and dev2 to generate my
binaries, respectively, with object files (*.o) or convenience
libraries (*.a) as inputs:

gcc -Wall -Wextra -Ulinux -Dlinux=linux -D_GNU_SOURCE -DNDEBUG \
-o my_binary *.o -L/opt/snmp/lib /opt/snmp/lib/libnetsnmpmibs.so \
/usr/lib/librpm.so -L/usr/src/build/757196-i386/install/usr/lib \
-L/usr/lib /usr/lib/librpmdb.so -L/usr/local/lib -lelf -lselinux \
/usr/lib/librpmio.so /usr/lib/libbeecrypt.so -lbz2 /usr/lib/libpopt.so \
/opt/snmp/lib/libnetsnmphelpers.so /opt/snmp/lib/libnetsnmpagent.so \
/opt/snmp/lib/libnetsnmp.so -lcrypto /usr/lib/libccgnu2.so \
/usr/lib/libccext2.so -lrt -lxerces-c -ldl /usr/lib/libxml2.so -lpthread \
-lz -lm -lcib -lplumb -lcrmcommon -lhbclient -lc -Wl,--rpath \
-Wl,/opt/snmp/lib -Wl,--rpath -Wl,/opt/snmp/lib

gcc -Wall -Wextra -Ulinux -Dlinux=linux -D_GNU_SOURCE -DNDEBUG \
-o my_binary -L/opt/snmp/lib /opt/snmp/lib/libnetsnmpmibs.so \
/usr/lib/librpm.so -L/usr/src/build/757196-i386/install/usr/lib \
-L/usr/lib /usr/lib/librpmdb.so -L/usr/local/lib -lelf -lselinux \
/usr/lib/librpmio.so /usr/lib/libbeecrypt.so -lbz2 /usr/lib/libpopt.so \
/opt/snmp/lib/libnetsnmphelpers.so /opt/snmp/lib/libnetsnmpagent.so \
/opt/snmp/lib/libnetsnmp.so -lcrypto /usr/lib/libccgnu2.so \
/usr/lib/libccext2.so -lrt -lxerces-c -ldl /usr/lib/libxml2.so -lpthread \
-lz -lm -lcib -lplumb -lcrmcommon -lhbclient *.a -lc -Wl,--rpath \
-Wl,/opt/snmp/lib -Wl,--rpath -Wl,/opt/snmp/lib

Rem: These commandlines originally comes from my autotools Makefile.

Thank you, in advance, for your help.

Kind Regards,

--
Alexandre BEAUGY
Product Engineer at Egis Avia
(Toulouse, France)

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux