[RFC] Change PCH "checksum"

Richard Biener rguenther@suse.de
Fri Feb 22 11:29:00 GMT 2019


GCC builds are currently not reproducible because for one the checksum
we compute for PCH purposes (by genchecksum) nowaways includes checksums
of archives (since we switched from checksumming a dummy executable
to checksumming object files).  That includes dates (unless built with
-D which we don't do).

Then later we switched to do thin archives so for example libbackend.a
we checksum doesn't contain the actual code anymore...

A pragmatic approach to "fix" things would be to just checksum
gtype-desc.o which should have enough state to cover PCH dependences
if I understand the workings correctly (patch below - a single
checksum would suffice so more simplifications are possible).

Another solution working on ELF systems with build-id support is
simply forgo checksumming anything and rely on the executable
build-id instead (pat^whack below as well).

Does anybody think that just checksumming gtype-desc.o is a
degradation over the current state (which checksums thin archives)?

Thanks,
Richard.

2019-02-22  Richard Biener  <rguenther@suse.de>

	c/
	* Make-lang.in (cc1-checksum.c): Checksum only gtype-desc.o.

	cp/
	* Make-lang.in (cc1plus-checksum.c): Checksum only gtype-desc.o.

	objc/
	* Make-lang.in (cc1obj-checksum.c): Checksum only gtype-desc.o.

	objcp/
	* Make-lang.in (cc1objplus-checksum.c): Checksum only gtype-desc.o.

Index: gcc/c/Make-lang.in
===================================================================
--- gcc/c/Make-lang.in	(revision 269111)
+++ gcc/c/Make-lang.in	(working copy)
@@ -70,14 +70,13 @@ endif
 # compute checksum over all object files and the options
 # re-use the checksum from the prev-final stage so it passes
 # the bootstrap comparison and allows comparing of the cc1 binary
-cc1-checksum.c : build/genchecksum$(build_exeext) checksum-options \
-	$(C_OBJS) $(BACKEND) $(LIBDEPS) 
+cc1-checksum.c : build/genchecksum$(build_exeext) gtype-desc.o 
 	if [ -f ../stage_final ] \
 	   && cmp -s ../stage_current ../stage_final; then \
 	  cp ../prev-gcc/cc1-checksum.c cc1-checksum.c; \
 	else \
-	  build/genchecksum$(build_exeext) $(C_OBJS) $(BACKEND) $(LIBDEPS) \
-                     checksum-options > cc1-checksum.c.tmp && 		 \
+	  build/genchecksum$(build_exeext) gtype-desc.o \
+                     > cc1-checksum.c.tmp && 		 \
 	  $(srcdir)/../move-if-change cc1-checksum.c.tmp cc1-checksum.c; \
 	fi
 
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in	(revision 269111)
+++ gcc/cp/Make-lang.in	(working copy)
@@ -105,14 +105,13 @@ cp-warn = $(STRICT_WARN)
 # compute checksum over all object files and the options
 # re-use the checksum from the prev-final stage so it passes
 # the bootstrap comparison and allows comparing of the cc1 binary
-cc1plus-checksum.c : build/genchecksum$(build_exeext) checksum-options \
-	$(CXX_OBJS) $(BACKEND) $(LIBDEPS) 
+cc1plus-checksum.c : build/genchecksum$(build_exeext) gtype-desc.o 
 	if [ -f ../stage_final ] \
 	   && cmp -s ../stage_current ../stage_final; then \
 	   cp ../prev-gcc/cc1plus-checksum.c cc1plus-checksum.c; \
 	else \
-	  build/genchecksum$(build_exeext) $(CXX_OBJS) $(BACKEND) $(LIBDEPS) \
-                     checksum-options > cc1plus-checksum.c.tmp &&	   \
+	  build/genchecksum$(build_exeext) gtype-desc.o \
+                     > cc1plus-checksum.c.tmp &&	   \
 	  $(srcdir)/../move-if-change cc1plus-checksum.c.tmp cc1plus-checksum.c; \
 	fi
 
Index: gcc/objc/Make-lang.in
===================================================================
--- gcc/objc/Make-lang.in	(revision 269111)
+++ gcc/objc/Make-lang.in	(working copy)
@@ -56,10 +56,9 @@ OBJC_OBJS = objc/objc-lang.o objc/objc-a
 
 objc_OBJS = $(OBJC_OBJS) cc1obj-checksum.o
 
-cc1obj-checksum.c : build/genchecksum$(build_exeext) checksum-options \
-        $(OBJC_OBJS) $(C_AND_OBJC_OBJS) $(BACKEND) $(LIBDEPS)
-	build/genchecksum$(build_exeext) $(OBJC_OBJS) $(C_AND_OBJC_OBJS) \
-        $(BACKEND) $(LIBDEPS) checksum-options > cc1obj-checksum.c.tmp && \
+cc1obj-checksum.c : build/genchecksum$(build_exeext) gtype-desc.o
+	build/genchecksum$(build_exeext) gtype-desc.o
+		> cc1obj-checksum.c.tmp && \
 	$(srcdir)/../move-if-change cc1obj-checksum.c.tmp cc1obj-checksum.c
 
 cc1obj$(exeext): $(OBJC_OBJS) $(C_AND_OBJC_OBJS) cc1obj-checksum.o $(BACKEND) $(LIBDEPS)
Index: gcc/objcp/Make-lang.in
===================================================================
--- gcc/objcp/Make-lang.in	(revision 269111)
+++ gcc/objcp/Make-lang.in	(working copy)
@@ -59,10 +59,9 @@ OBJCXX_OBJS = objcp/objcp-act.o objcp/ob
 
 obj-c++_OBJS = $(OBJCXX_OBJS) cc1objplus-checksum.o
 
-cc1objplus-checksum.c : build/genchecksum$(build_exeext) checksum-options \
-	$(OBJCXX_OBJS) $(BACKEND) $(LIBDEPS)
-	build/genchecksum$(build_exeext) $(OBJCXX_OBJS) $(BACKEND) \
-		$(LIBDEPS) checksum-options > cc1objplus-checksum.c.tmp && \
+cc1objplus-checksum.c : build/genchecksum$(build_exeext) gtype-desc.o 
+	build/genchecksum$(build_exeext) gtype-desc.o
+		> cc1objplus-checksum.c.tmp && \
 	$(srcdir)/../move-if-change cc1objplus-checksum.c.tmp \
 	cc1objplus-checksum.c
 


2019-02-22  Richard Biener  <rguenther@suse.de>

	* ...

Index: gcc/c-family/c-pch.c
===================================================================
--- gcc/c-family/c-pch.c	(revision 269111)
+++ gcc/c-family/c-pch.c	(working copy)
@@ -45,10 +45,6 @@ enum {
   MATCH_SIZE = ARRAY_SIZE (pch_matching)
 };
 
-/* The value of the checksum in the dummy compiler that is actually
-   checksummed.  That compiler should never be run.  */
-static const char no_checksum[16] = { 0 };
-
 /* Information about flags and suchlike that affect PCH validity.
 
    Before this structure is read, both an initial 8-character identification
@@ -69,6 +65,67 @@ static FILE *pch_outfile;
 
 static const char *get_ident (void);
 
+#if _GNU_SOURCE
+#include <link.h>
+
+#define ALIGN(val, align)      (((val) + (align) - 1) & ~((align) - 1))
+
+struct build_id_note {
+    /* The NHdr.  */
+    uint32_t namesz;
+    uint32_t descsz;
+    uint32_t type;
+
+    char name[4]; /* Note name for build-id is "GNU\0" */
+    unsigned char build_id[16];
+};
+
+static int
+get_build_id_1 (struct dl_phdr_info *info, size_t, void *data)
+{
+  for (unsigned i = 0; i < info->dlpi_phnum; ++i)
+    {
+      if (info->dlpi_phdr[i].p_type != PT_NOTE)
+	continue;
+      build_id_note *note
+	= (build_id_note *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+      ptrdiff_t size = info->dlpi_phdr[i].p_filesz;
+      while (size >= (ptrdiff_t)sizeof (build_id_note))
+	{
+	  if (note->type == NT_GNU_BUILD_ID
+	      && note->namesz == 4
+	      && note->descsz >= 16)
+	    {
+	      memcpy (data, note->build_id, 16);
+	      return 1;
+	    }
+	  size_t offset = (sizeof (uint32_t) * 3
+			   + ALIGN(note->namesz, 4)
+			   + ALIGN(note->descsz, 4));
+	  note = (build_id_note *)((char *)note + offset);
+	  size -= offset;
+	}
+    }
+
+  return 0;
+}
+
+static const unsigned char *
+get_build_id ()
+{
+  static unsigned char build_id[16];
+  if (!dl_iterate_phdr (get_build_id_1, build_id))
+    return NULL;
+  return build_id;
+}
+#else
+static const unsigned char *
+get_build_id ()
+{
+  return NULL;
+}
+#endif
+
 /* Compute an appropriate 8-byte magic number for the PCH file, so that
    utilities like file(1) can identify it, and so that GCC can quickly
    ignore non-PCH files and PCH files that are of a completely different
@@ -111,8 +168,6 @@ pch_init (void)
 		 pch_file);
   pch_outfile = f;
 
-  gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0);
-
   memset (&v, '\0', sizeof (v));
   v.debug_info_type = write_symbols;
   {
@@ -126,8 +181,11 @@ pch_init (void)
   v.pch_init = &pch_init;
   target_validity = targetm.get_pch_validity (&v.target_data_length);
 
+  const unsigned char *chksum = get_build_id ();
+  if (!chksum)
+    chksum = executable_checksum;
   if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
-      || fwrite (executable_checksum, 16, 1, f) != 1
+      || fwrite (chksum, 16, 1, f) != 1
       || fwrite (&v, sizeof (v), 1, f) != 1
       || fwrite (target_validity, v.target_data_length, 1, f) != 1)
     fatal_error (input_location, "can%'t write to %s: %m", pch_file);
@@ -212,8 +270,6 @@ c_common_valid_pch (cpp_reader *pfile, c
   /* Perform a quick test of whether this is a valid
      precompiled header for the current language.  */
 
-  gcc_assert (memcmp (executable_checksum, no_checksum, 16) != 0);
-
   sizeread = read (fd, ident, IDENT_LENGTH + 16);
   if (sizeread == -1)
     fatal_error (input_location, "can%'t read %s: %m", name);
@@ -245,7 +301,10 @@ c_common_valid_pch (cpp_reader *pfile, c
 	}
       return 2;
     }
-  if (memcmp (ident + IDENT_LENGTH, executable_checksum, 16) != 0)
+  const unsigned char *chksum = get_build_id ();
+  if (!chksum)
+    chksum = executable_checksum;
+  if (memcmp (ident + IDENT_LENGTH, chksum, 16) != 0)
     {
       if (cpp_get_options (pfile)->warn_invalid_pch)
 	cpp_error (pfile, CPP_DL_WARNING,
Index: gcc/genchecksum.c
===================================================================
--- gcc/genchecksum.c	(revision 269111)
+++ gcc/genchecksum.c	(working copy)
@@ -113,8 +113,13 @@ main (int argc, char ** argv)
   puts ("#include \"config.h\"");
   puts ("#include \"system.h\"");
   fputs ("EXPORTED_CONST unsigned char executable_checksum[16] = { ", stdout);
+#if _GNU_SOURCE
+  for (i = 0; i < 16; i++)
+    printf ("0x%02x%s", 0, i == 15 ? " };\n" : ", ");
+#else
   for (i = 0; i < 16; i++)
     printf ("0x%02x%s", result[i], i == 15 ? " };\n" : ", ");
+#endif
 
   return 0;
 }



More information about the Gcc mailing list