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; }