On Sat, Nov 20, 2021 at 9:43 AM Jacob Kroon via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> On 11/20/21 09:32, Jakub Jelinek wrote:
> > On Sat, Nov 20, 2021 at 12:24:21AM -0800, Andrew Pinski via Gcc-patches 
> > wrote:
> >> On Sat, Nov 20, 2021 at 12:18 AM Jacob Kroon via Gcc-patches
> >> <gcc-patches@gcc.gnu.org> wrote:
> >>>
> >>> cc1/cc1plus both include a checksum of the object files, archives and
> >>> options used during linking. Unless the host binutils has been built
> >>> with --enable-deterministic-archives, the archives will have different
> >>> checksums each build due to changes in timestamps of the containing
> >>> object files, and thus the checksum that is embedded in cc1/cc1plus will
> >>> also change.
> >>>
> >>> Fix this by passing "D" to ar/ranlib when creating the archives.
> >>
> >> How portable is the D option? That does it work with Mac OS X's ar;
> >> what about AIX's ar; what about Solaris's ar, etc?
> >> GNU binutils is not the only ar which is supported for the host.
> >
> > It isn't portable and even if ar/ranlib do support that option, not all
> > users will want it, so forcing it upon them unconditionally is IMO not a
> > good idea.  If anything, configure needs to check if those options are
> > supported and there needs to be preferrably non-default gcc configure
> > option to request it.
> >
>
> Aha, I see. Then perhaps an easier and more portable solution for
> improving the reproducibility would be to make it optional whether or
> not to include the archives when calculating the checksums.
>
> Or perhaps by checksumming the containing object files instead of the
> archives themselves ?
>
> Would something like that be acceptable ?

At SUSE we are carrying patches to not include the checksum at all
but instead use the linker generated build-id as checksum for PCH.
I suppose when we add the configure option to disable PCH support
we could also elide checksum processing (or as in the patch simply
always use all-zeros).

Attached for reference.

Richard.

>
> Jacob
Use the binaries build-id as checksum for PCH purposes.

diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c
index 9c0bd0b631d..de762517fc3 100644
--- a/gcc/c-family/c-pch.c
+++ b/gcc/c-family/c-pch.c
@@ -65,6 +65,66 @@ 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))
+
+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;
+      ElfW(Nhdr) *nhdr
+	= (ElfW(Nhdr) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+      ptrdiff_t size = info->dlpi_phdr[i].p_filesz;
+      ptrdiff_t align = info->dlpi_phdr[i].p_align;
+      if (align != 8)
+	align = 4;
+      while (size >= (ptrdiff_t)sizeof (ElfW(Nhdr)))
+	{
+	  if (nhdr->n_type == NT_GNU_BUILD_ID
+	      && nhdr->n_namesz == 4
+	      && strncmp ((char *)nhdr
+			  + sizeof (ElfW(Nhdr)),
+			  "GNU", 4) == 0
+	      && nhdr->n_descsz >= 16)
+	    {
+	      memcpy (data, 
+		      (char *)nhdr
+		      + ALIGN (sizeof (ElfW(Nhdr))
+			       + nhdr->n_namesz, align), 16);
+	      return 1;
+	    }
+	  size_t offset = (ALIGN (sizeof (ElfW(Nhdr))
+				  + nhdr->n_namesz, align)
+			   + ALIGN(nhdr->n_descsz, align));
+	  nhdr = (ElfW(Nhdr) *)((char *)nhdr + 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
@@ -120,8 +180,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, "cannot write to %s: %m", pch_file);
@@ -232,7 +295,10 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd)
 	  cpp_warning (pfile, CPP_W_INVALID_PCH, "%s: not a PCH file", name);
       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)
     {
       cpp_warning (pfile, CPP_W_INVALID_PCH,
 		   "%s: created by a different GCC executable", name);
diff --git a/gcc/genchecksum.c b/gcc/genchecksum.c
index 09fbb63fa93..ec8b3281d53 100644
--- a/gcc/genchecksum.c
+++ b/gcc/genchecksum.c
@@ -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;
 }

Reply via email to