public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/4] config: Allow a host to opt out of PCH.
@ 2021-11-04 20:02 Iain Sandoe
  2021-11-04 20:02 ` [PATCH 1/4] config: Add top-level flag to disable host PCH Iain Sandoe
  2021-11-05  9:42 ` [PATCH 0/4] config: Allow a host to opt out of PCH Richard Biener
  0 siblings, 2 replies; 39+ messages in thread
From: Iain Sandoe @ 2021-11-04 20:02 UTC (permalink / raw)
  To: gcc-patches

GCC (currently) has an implementation of pre-compiled-headers, that relies
on being able to launch the compiler executable at the same address each
time.  This constraint is not permitted by some system security models.

The facility is an optimisation; saving the output of parsing a covering
header file (that may include many others) so that the parsing need not be
repeated when the same set of headers is needed in many places in a project.

The patch series disables the operation of the PCH-related command lines,
but does not cause an error to be emitted.  The intent is that build
recipes that expect PCH to work will continue to operate, but the compiler
no longer acts on them and therefore is no longer bound to the requirement
to launch at a fixed address.

 * When invoked to "generate PCH" the compiler will carry out the parsing
   as before - producing any diagnostics if relevant and then saving a
   stub file (to satisfy build recipe targets).  The stub file is marked as
   invalid PCH.

 * When an include directive is encountered, the compiler no longer checks
   to see if a PCH header is available.

 * The top-level configure option (--disable-host-pch-support) is also
   propagated to libstdc++ where it causes the automatic invocation of the
   existing --disable-libstdxx-pch.

tested on x86_64-darwin, aarch64-darwin, and on x86_64, powerpc64le-linux,
OK for master?
thanks
Iain

Iain Sandoe (4):
  config: Add top-level flag to disable host PCH.
  libstdc++: Adjust build of PCH files accounting configured host
    support.
  libcpp: Honour a configuration without host support for PCH.
  c-family, gcc: Allow configuring without support for PCH.

 Makefile.def              |  9 ++--
 Makefile.in               | 87 +++++++++++++++++++++++++--------------
 configure                 | 42 +++++++++++++++++++
 configure.ac              | 35 ++++++++++++++++
 gcc/c-family/c-pch.c      | 23 ++++++++++-
 gcc/config.in             |  6 +++
 gcc/config/host-darwin.c  | 18 ++++++++
 gcc/configure             | 29 ++++++++++++-
 gcc/configure.ac          | 17 ++++++++
 gcc/doc/install.texi      |  6 +++
 libcpp/config.in          |  3 ++
 libcpp/configure          | 24 +++++++++++
 libcpp/configure.ac       | 16 +++++++
 libcpp/files.c            | 14 +++++++
 libcpp/pch.c              | 12 ++++++
 libstdc++-v3/acinclude.m4 | 49 +++++++++++++---------
 libstdc++-v3/configure    | 71 +++++++++++++++++++++-----------
 libstdc++-v3/configure.ac | 11 ++++-
 18 files changed, 391 insertions(+), 81 deletions(-)

-- 
2.24.3 (Apple Git-128)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 1/4] config: Add top-level flag to disable host PCH.
  2021-11-04 20:02 [PATCH 0/4] config: Allow a host to opt out of PCH Iain Sandoe
@ 2021-11-04 20:02 ` Iain Sandoe
  2021-11-04 20:02   ` [PATCH 2/4] libstdc++: Adjust build of PCH files accounting configured host support Iain Sandoe
  2021-11-05  9:42 ` [PATCH 0/4] config: Allow a host to opt out of PCH Richard Biener
  1 sibling, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-04 20:02 UTC (permalink / raw)
  To: gcc-patches

This provides a --disable-host-pch-support configure flag
that is passed down to libcpp, gcc and libstdc++ where the
support for PCH is enacted.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

ChangeLog:

	* Makefile.def: Pass host PCH support configuration
	to libcpp, gcc and libstdc++.
	* Makefile.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Add --disable-host-pch-support flag.
	* doc/install.texi: Document the option.
---
 Makefile.def         |  9 +++--
 Makefile.in          | 87 +++++++++++++++++++++++++++++---------------
 configure            | 42 +++++++++++++++++++++
 configure.ac         | 35 ++++++++++++++++++
 gcc/doc/install.texi |  6 +++
 5 files changed, 146 insertions(+), 33 deletions(-)

diff --git a/Makefile.def b/Makefile.def
index 0abc42b1a1b..671d1c7ccc6 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -47,7 +47,8 @@ host_modules= { module= fixincludes; bootstrap=true;
 host_modules= { module= flex; no_check_cross= true; };
 host_modules= { module= gas; bootstrap=true; };
 host_modules= { module= gcc; bootstrap=true; 
-		extra_make_flags="$(EXTRA_GCC_FLAGS)"; };
+		extra_make_flags="$(EXTRA_GCC_FLAGS)";
+		extra_configure_flags="@configure_host_pch_support@"; };
 host_modules= { module= gmp; lib_path=.libs; bootstrap=true;
 		// Work around in-tree gmp configure bug with missing flex.
 		extra_configure_flags='--disable-shared LEX="touch lex.yy.c"';
@@ -81,7 +82,8 @@ host_modules= { module= tcl;
 host_modules= { module= itcl; };
 host_modules= { module= ld; bootstrap=true; };
 host_modules= { module= libbacktrace; bootstrap=true; };
-host_modules= { module= libcpp; bootstrap=true; };
+host_modules= { module= libcpp; bootstrap=true;
+                extra_configure_flags="@configure_host_pch_support@"; };
 // As with libiconv, don't install any of libcody
 host_modules= { module= libcody; bootstrap=true;
 		no_install= true;
@@ -152,7 +154,8 @@ host_modules= { module= libctf; bootstrap=true; };
 target_modules = { module= libstdc++-v3;
 		   bootstrap=true;
 		   lib_path=src/.libs;
-		   raw_cxx=true; };
+		   raw_cxx=true;
+		   extra_configure_flags="@configure_host_pch_support@"; };
 target_modules = { module= libsanitizer;
 		   bootstrap=true;
 		   lib_path=.libs;

diff --git a/configure.ac b/configure.ac
index 550e6993b59..0d9c36bf6d6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -408,6 +408,41 @@ AC_ARG_ENABLE(compressed_debug_sections,
   fi
 ], [enable_compressed_debug_sections=])
 
+# Add a configure option to control whether the host will support pre-compiled
+# headers (PCH) for the c-family compilers.  At present, the default is 'yes'
+# for most platforms but this can be adjusted below for any that are unable to
+# support it.  'configure_host_pch_support' is passed as an additional config
+# arg to the configures for host and target modules that depend on the support
+# where this is not specified explicitly.
+configure_host_pch_support=
+AC_ARG_ENABLE(host_pch_support,
+[AS_HELP_STRING([--disable-host-pch-support],
+                [Disable support for C-family precompiled headers])],
+[
+  ENABLE_HOST_PCH=$enableval
+  case "${host}" in
+    aarch64-*-darwin* | arm64*-*-darwin*)
+      if test "x${ENABLE_HOST_PCH}" = xyes; then
+        AC_MSG_ERROR([PCH is not supported on aarch64/arm64 Darwin hosts])
+      fi
+      ;;
+    *)
+      ;;
+  esac
+],[
+  # The configure line does not specify, so set appropriate values to pass to
+  # module configures that depend on this.
+  case "${host}" in
+    aarch64-*-darwin* | arm64*-*-darwin*)
+      configure_host_pch_support='--enable-host-pch-support=no'
+      ;;
+    *) 
+      configure_host_pch_support='--enable-host-pch-support=yes'
+      ;;
+  esac
+])
+AC_SUBST(configure_host_pch_support)
+
 # Configure extra directories which are host specific
 
 case "${host}" in
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 094469b9a4e..5581e4cb063 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -1015,6 +1015,12 @@ This option is required when building the libgccjit.so library.
 Contrast with @option{--enable-shared}, which affects @emph{target}
 libraries.
 
+@item --disable-host-pch-support
+Specify that the c-family compilers should be built without support for
+Pre-Compiled-Headers (PCH).  The compilers will generate stub pch files
+(to avoid breaking build scripts), but ignore these (or any existing PCH
+files) when searching for headers.
+
 @item @anchor{with-gnu-as}--with-gnu-as
 Specify that the compiler should assume that the
 assembler it finds is the GNU assembler.  However, this does not modify
-- 
2.24.3 (Apple Git-128)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 2/4] libstdc++: Adjust build of PCH files accounting configured host support.
  2021-11-04 20:02 ` [PATCH 1/4] config: Add top-level flag to disable host PCH Iain Sandoe
@ 2021-11-04 20:02   ` Iain Sandoe
  2021-11-04 20:02     ` [PATCH 3/4] libcpp: Honour a configuration without host support for PCH Iain Sandoe
       [not found]     ` <EB9AC754-904B-4877-AD17-94886712C10E@gmail.com>
  0 siblings, 2 replies; 39+ messages in thread
From: Iain Sandoe @ 2021-11-04 20:02 UTC (permalink / raw)
  To: gcc-patches

This takes account of the overall configuration for host PCH support
when deciding if we should build the libstdc++ PCH files.

We now require both the support is configured and that we are hosted.
A non-fatal configure warning is given if the user attempts to
--disable-host-pch-support --enable-libstdcxx-pch since the latter
conflicts with the former (but does not prevent a useable libstdc++
library build).

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

libstdc++-v3/ChangeLog:

	* acinclude.m4: Account for configured host PCH support.
	* configure: Regenerate.
	* configure.ac: Act on --enable-host-pch-support.
---
 libstdc++-v3/acinclude.m4 | 49 ++++++++++++++++-----------
 libstdc++-v3/configure    | 71 ++++++++++++++++++++++++++-------------
 libstdc++-v3/configure.ac | 11 ++++--
 3 files changed, 86 insertions(+), 45 deletions(-)

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 90ecc4a87a2..87652306691 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -3225,7 +3225,7 @@ AC_DEFUN([GLIBCXX_ENABLE_WCHAR_T], [
 ])
 
 
-dnl
+≈
 dnl Check to see if building and using a C++ precompiled header can be done.
 dnl
 dnl --enable-libstdcxx-pch=yes
@@ -3240,29 +3240,40 @@ dnl Substs:
 dnl  glibcxx_PCHFLAGS
 dnl
 AC_DEFUN([GLIBCXX_ENABLE_PCH], [
-  GLIBCXX_ENABLE(libstdcxx-pch,$1,,[build pre-compiled libstdc++ headers])
+  dnl This is only allowed if host support is enabled, and we are hosted.
+  if test "$1" = "yes" && test "$2" = "yes"; then
+    can_pch=yes
+  else
+    can_pch=no
+  fi
+  GLIBCXX_ENABLE(libstdcxx-pch,$can_pch,,[build pre-compiled libstdc++ headers])
   if test $enable_libstdcxx_pch = yes; then
-    AC_CACHE_CHECK([for compiler with PCH support],
-      [glibcxx_cv_prog_CXX_pch],
-      [ac_save_CXXFLAGS="$CXXFLAGS"
-       CXXFLAGS="$CXXFLAGS -Werror -Winvalid-pch -Wno-deprecated"
-       AC_LANG_SAVE
-       AC_LANG_CPLUSPLUS
-       echo '#include <math.h>' > conftest.h
-       if $CXX $CXXFLAGS $CPPFLAGS -x c++-header conftest.h \
+    if test "$2" != "yes"; then
+      glibcxx_cv_prog_CXX_pch=no
+      AC_MSG_WARN([PCH headers cannot be built since host PCH is disabled])
+    else
+      AC_CACHE_CHECK([for compiler with PCH support],
+        [glibcxx_cv_prog_CXX_pch],
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS -Werror -Winvalid-pch -Wno-deprecated"
+         AC_LANG_SAVE
+         AC_LANG_CPLUSPLUS
+         echo '#include <math.h>' > conftest.h
+         if $CXX $CXXFLAGS $CPPFLAGS -x c++-header conftest.h \
 			  -o conftest.h.gch 1>&5 2>&1 &&
 		echo '#error "pch failed"' > conftest.h &&
 	  echo '#include "conftest.h"' > conftest.cc &&
 	       $CXX -c $CXXFLAGS $CPPFLAGS conftest.cc 1>&5 2>&1 ;
-       then
-	 glibcxx_cv_prog_CXX_pch=yes
-       else
-	 glibcxx_cv_prog_CXX_pch=no
-       fi
-       rm -f conftest*
-       CXXFLAGS=$ac_save_CXXFLAGS
-       AC_LANG_RESTORE
-      ])
+         then
+	   glibcxx_cv_prog_CXX_pch=yes
+         else
+	   glibcxx_cv_prog_CXX_pch=no
+         fi
+         rm -f conftest*
+         CXXFLAGS=$ac_save_CXXFLAGS
+         AC_LANG_RESTORE
+        ])
+    fi
     enable_libstdcxx_pch=$glibcxx_cv_prog_CXX_pch
   fi
 

diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 2d68b3672b9..ce82f16c859 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -103,7 +103,6 @@ if test "$enable_vtable_verify" = yes; then
   postdep_objects_CXX="${postdep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_end.o"
 fi
 
-
 # libtool variables for C++ shared and position-independent compiles.
 #
 # Use glibcxx_lt_pic_flag to designate the automake variable
@@ -147,8 +146,16 @@ GLIBCXX_ENABLE_HOSTED
 # Enable descriptive messages to standard output on termination.
 GLIBCXX_ENABLE_VERBOSE
 
+# The current default is that PCH is supported by the host unless otherwise
+# stated.
+AC_ARG_ENABLE(host_pch_support,
+AS_HELP_STRING([--disable-host-pch-support],
+	       [Disable host support for precompiled headers]),
+host_pch_support=$enableval,
+host_pch_support=yes)
+
 # Enable compiler support that doesn't require linking.
-GLIBCXX_ENABLE_PCH($is_hosted)
+GLIBCXX_ENABLE_PCH($is_hosted, $host_pch_support)
 GLIBCXX_ENABLE_THREADS
 GLIBCXX_ENABLE_ATOMIC_BUILTINS
 GLIBCXX_ENABLE_LOCK_POLICY
-- 
2.24.3 (Apple Git-128)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 3/4] libcpp: Honour a configuration without host support for PCH.
  2021-11-04 20:02   ` [PATCH 2/4] libstdc++: Adjust build of PCH files accounting configured host support Iain Sandoe
@ 2021-11-04 20:02     ` Iain Sandoe
  2021-11-04 20:02       ` [PATCH 4/4] c-family, gcc: Allow configuring without " Iain Sandoe
       [not found]     ` <EB9AC754-904B-4877-AD17-94886712C10E@gmail.com>
  1 sibling, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-04 20:02 UTC (permalink / raw)
  To: gcc-patches

This accepts --disable-host-pch-support (or equivalent) and
disables the step that finds PCH files in the pre-processor.
It also stubs-out the PCH code (since it's never called).

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

libcpp/ChangeLog:

	* config.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Handle --enable-host-support.
	* files.c (pch_open_file, validate_pch): Do not build
	if PCH support is disabled.
	(find_file_in_dir): Do not search for PCH files if the
	host support is disabled.
	* pch.c (cpp_save_state, cpp_write_pch_deps,
	cpp_write_pch_state, cpp_valid_state, cpp_prepare_state,
	cpp_read_state): Build dummy versions when PCH support
	is disabled.
---
 libcpp/config.in    |  3 +++
 libcpp/configure    | 24 ++++++++++++++++++++++++
 libcpp/configure.ac | 16 ++++++++++++++++
 libcpp/files.c      | 14 ++++++++++++++
 libcpp/pch.c        | 12 ++++++++++++
 5 files changed, 69 insertions(+)


diff --git a/libcpp/configure.ac b/libcpp/configure.ac
index 1efa96f7ca3..0533655e15a 100644
--- a/libcpp/configure.ac
+++ b/libcpp/configure.ac
@@ -183,6 +183,22 @@ if test x$ac_valgrind_checking != x ; then
  possible memory leaks because of libcpp use of interior pointers.])
 fi
 
+# The current default is that PCH is supported by the host unless otherwise
+# stated.
+AC_ARG_ENABLE(host_pch_support,
+AS_HELP_STRING([--disable-host-pch-support],
+	       [Disable host support for precompiled headers]),
+host_pch_support=$enableval,
+host_pch_support=yes)
+AC_SUBST(host_pch_support)
+HOST_PCH_SUPPORT=0
+if test x"$host_pch_support" != xno; then
+  AC_DEFINE(ENABLE_HOST_PCH_SUPPORT, 1,
+	    [Define this to 1 to enable support for precompiled headers.])
+else
+  AC_DEFINE(ENABLE_HOST_PCH_SUPPORT, 0)
+fi
+
 AC_ARG_ENABLE(canonical-system-headers,
 [  --enable-canonical-system-headers
                           enable or disable system headers canonicalization],
diff --git a/libcpp/files.c b/libcpp/files.c
index c93a03c69ef..800744b6a48 100644
--- a/libcpp/files.c
+++ b/libcpp/files.c
@@ -168,8 +168,10 @@ struct file_hash_entry_pool
 };
 
 static bool open_file (_cpp_file *file);
+#if ENABLE_HOST_PCH_SUPPORT
 static bool pch_open_file (cpp_reader *pfile, _cpp_file *file,
 			   bool *invalid_pch);
+#endif
 static bool find_file_in_dir (cpp_reader *pfile, _cpp_file *file,
 			      bool *invalid_pch, location_t loc);
 static bool read_file_guts (cpp_reader *pfile, _cpp_file *file,
@@ -195,7 +197,9 @@ static char *read_filename_string (int ch, FILE *f);
 static void read_name_map (cpp_dir *dir);
 static char *remap_filename (cpp_reader *pfile, _cpp_file *file);
 static char *append_file_to_dir (const char *fname, cpp_dir *dir);
+#if ENABLE_HOST_PCH_SUPPORT
 static bool validate_pch (cpp_reader *, _cpp_file *file, const char *pchname);
+#endif
 static int pchf_save_compare (const void *e1, const void *e2);
 static int pchf_compare (const void *d_p, const void *e_p);
 static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool);
@@ -272,6 +276,7 @@ open_file (_cpp_file *file)
   return false;
 }
 
+#if ENABLE_HOST_PCH_SUPPORT
 /* Temporary PCH intercept of opening a file.  Try to find a PCH file
    based on FILE->name and FILE->dir, and test those found for
    validity using PFILE->cb.valid_pch.  Return true iff a valid file is
@@ -347,6 +352,7 @@ pch_open_file (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch)
 
   return valid;
 }
+#endif
 
 /* Canonicalize the path to FILE.  Return the canonical form if it is
    shorter, otherwise return NULL.  This function does NOT free the
@@ -420,8 +426,14 @@ find_file_in_dir (cpp_reader *pfile, _cpp_file *file, bool *invalid_pch,
 	}
 
       file->path = path;
+#if ENABLE_HOST_PCH_SUPPORT
+      /* If there is no PCH this does not set the validity flag, so it keeps
+	 whatever value it had on entry.  */
       if (pch_open_file (pfile, file, invalid_pch))
 	return true;
+#else
+      *invalid_pch = false;
+#endif
 
       if (open_file (file))
 	return true;
@@ -1858,6 +1870,7 @@ remap_filename (cpp_reader *pfile, _cpp_file *file)
     }
 }
 
+#if ENABLE_HOST_PCH_SUPPORT
 /* Returns true if PCHNAME is a valid PCH file for FILE.  */
 static bool
 validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)
@@ -1889,6 +1902,7 @@ validate_pch (cpp_reader *pfile, _cpp_file *file, const char *pchname)
   file->path = saved_path;
   return valid;
 }
+#endif
 
 /* Get the path associated with the _cpp_file F.  The path includes
    the base name from the include directive and the directory it was
diff --git a/libcpp/pch.c b/libcpp/pch.c
index bb809641457..1dafcae6c4b 100644
--- a/libcpp/pch.c
+++ b/libcpp/pch.c
@@ -22,6 +22,7 @@ along with this program; see the file COPYING3.  If not see
 #include "hashtab.h"
 #include "mkdeps.h"
 
+#if ENABLE_HOST_PCH_SUPPORT
 static int write_macdef (cpp_reader *, cpp_hashnode *, void *);
 static int save_idents (cpp_reader *, cpp_hashnode *, void *);
 static hashval_t hashmem (const void *, size_t);
@@ -876,3 +877,14 @@ cpp_read_state (cpp_reader *r, const char *name, FILE *f,
   cpp_errno (r, CPP_DL_ERROR, "while reading precompiled header");
   return -1;
 }
+#else
+
+int cpp_save_state (cpp_reader *, FILE *) { return 0; }
+int cpp_write_pch_deps (cpp_reader *, FILE *) { return 0; }
+int cpp_write_pch_state (cpp_reader *, FILE *) { return 0; }
+int cpp_valid_state (cpp_reader *, const char *, int) { return 0; }
+void cpp_prepare_state (cpp_reader *, struct save_macro_data **) {}
+int cpp_read_state (cpp_reader *, const char *, FILE *,
+			   struct save_macro_data *) { return 0; }
+
+#endif
-- 
2.24.3 (Apple Git-128)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH 4/4] c-family, gcc: Allow configuring without support for PCH.
  2021-11-04 20:02     ` [PATCH 3/4] libcpp: Honour a configuration without host support for PCH Iain Sandoe
@ 2021-11-04 20:02       ` Iain Sandoe
  0 siblings, 0 replies; 39+ messages in thread
From: Iain Sandoe @ 2021-11-04 20:02 UTC (permalink / raw)
  To: gcc-patches

Some hosts cannot (or do not wish to) support PCH with the
current constraint that the executables must disable ASLR.

This allows the configuration to disable support for PCH
while still accepting the command lines (to avoid existing
build recipes failing).

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

gcc/c-family/ChangeLog:

	* c-pch.c (pch_cpp_save_state): Skip output if PCH
	is disabled.
	(c_common_write_pch): Likewise.
	(c_common_pch_pragma): Replace with a dummy routine
	that emits a diagnostic if we encounter a PCH pragma.

gcc/ChangeLog:

	* config.in: Regenerate.
	* config/host-darwin.c (darwin_gt_pch_get_address,
	darwin_gt_pch_use_address): Dummy routines for the case
	that PCH is disabled (this avoids allocating and freeing
	the memory that would be used).
	* configure: Regenerate.
	* configure.ac: Act on the host PCH configure option.
---
 gcc/c-family/c-pch.c     | 23 ++++++++++++++++++++++-
 gcc/config.in            |  6 ++++++
 gcc/config/host-darwin.c | 18 ++++++++++++++++++
 gcc/configure            | 29 +++++++++++++++++++++++++++--
 gcc/configure.ac         | 17 +++++++++++++++++
 5 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c
index 5da60423354..84bd8b8e0fc 100644
--- a/gcc/c-family/c-pch.c
+++ b/gcc/c-family/c-pch.c
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-pragma.h"
 #include "langhooks.h"
 #include "hosthooks.h"
+#include "diagnostic.h"
 
 /* This is a list of flag variables that must match exactly, and their
    names for the error message.  The possible values for *flag_var must
@@ -148,12 +149,14 @@ pch_cpp_save_state (void)
 {
   if (!pch_cpp_state_saved)
     {
+#if ENABLE_HOST_PCH_SUPPORT
       if (pch_outfile)
 	{
 	  cpp_save_state (parse_in, pch_outfile);
 	  pch_cpp_state_saved = true;
 	}
       else
+#endif
 	pch_ready_to_save_cpp_state = true;
     }
 }
@@ -172,6 +175,7 @@ c_common_write_pch (void)
 
   prepare_target_option_nodes_for_pch ();
 
+#if ENABLE_HOST_PCH_SUPPORT
   cpp_write_pch_deps (parse_in, pch_outfile);
 
   gt_pch_save (pch_outfile);
@@ -183,6 +187,10 @@ c_common_write_pch (void)
   if (fseek (pch_outfile, 0, SEEK_SET) != 0
       || fwrite (get_ident (), IDENT_LENGTH, 1, pch_outfile) != 1)
     fatal_error (input_location, "cannot write %s: %m", pch_file);
+#else
+   warning_at (input_location, 0,
+	       "precompiled headers are not supported by this compiler");
+#endif
 
   fclose (pch_outfile);
 
@@ -394,6 +402,7 @@ c_common_no_more_pch (void)
     }
 }
 
+#if ENABLE_HOST_PCH_SUPPORT
 /* Handle #pragma GCC pch_preprocess, to load in the PCH file.  */
 
 void
@@ -424,4 +433,16 @@ c_common_pch_pragma (cpp_reader *pfile, const char *name)
 
   close (fd);
 }
-
+#else
+void
+c_common_pch_pragma (cpp_reader *, const char *)
+{
+  /* We have encountered a PCH pragma, which presumably means that the user
+     has managed to emit a preprocessed file with a compiler supporting PCH
+     and is now trying to compile that on one without such support.  It is
+     not going to work and not clear how we could recover sensibly - so best
+     not to allow it.  */
+  fatal_error (input_location,
+	       "precompiled headers are not supported by this compiler");
+}
+#endif
diff --git a/gcc/config.in b/gcc/config.in
index b5bec3971dc..0a3baab882e 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -193,6 +193,12 @@
 #endif
 
 
+/* Define this to enable support for precompiled header (c-family). */
+#ifndef USED_FOR_TARGET
+#undef ENABLE_HOST_PCH_SUPPORT
+#endif
+
+
 /* Define if gcc should always pass --build-id to linker. */
 #ifndef USED_FOR_TARGET
 #undef ENABLE_LD_BUILDID
diff --git a/gcc/config/host-darwin.c b/gcc/config/host-darwin.c
index 14a01fe71f2..828d5763d8c 100644
--- a/gcc/config/host-darwin.c
+++ b/gcc/config/host-darwin.c
@@ -23,6 +23,7 @@
 #include "diagnostic-core.h"
 #include "config/host-darwin.h"
 
+#if ENABLE_HOST_PCH_SUPPORT
 /* Yes, this is really supposed to work.  */
 /* This allows for a pagesize of 16384, which we have on Darwin20, but should
    continue to work OK for pagesize 4096 which we have on earlier versions.
@@ -79,3 +80,20 @@ darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off)
 
   return ret;
 }
+
+#else
+
+/* Dummy versions of the hooks that do nothing on Darwin versions without
+   PCH support, we also omit the allocation of the memory.  */
+void *
+darwin_gt_pch_get_address (size_t, int)
+{
+  return NULL;
+}
+
+int
+darwin_gt_pch_use_address (void *, size_t, int, size_t)
+{
+  return 0;
+}
+#endif
diff --git a/gcc/configure b/gcc/configure
index 920868bcd33..3a87dc8a687 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -818,6 +818,7 @@ LN
 LN_S
 AWK
 SET_MAKE
+host_pch_support
 omp_device_property_deps
 omp_device_properties
 accel_dir_suffix
@@ -976,6 +977,7 @@ with_changes_root_url
 enable_languages
 with_multilib_list
 with_multilib_generator
+enable_host_pch_support
 with_zstd
 with_zstd_include
 with_zstd_lib
@@ -1704,6 +1706,8 @@ Optional Features:
   --disable-shared        don't provide a shared libgcc
   --disable-gcov          don't provide libgcov and related host tools
   --enable-languages=LIST specify which front-ends to build
+  --disable-host-pch-support
+                          Disable host support for precompiled headers
   --disable-rpath         do not hardcode runtime library paths
   --enable-sjlj-exceptions
                           arrange to use setjmp/longjmp exception handling
@@ -8112,6 +8116,27 @@ else
 fi
 
 
+# The current default is that PCH is supported by the host unless otherwise
+# stated.
+# Check whether --enable-host_pch_support was given.
+if test "${enable_host_pch_support+set}" = set; then :
+  enableval=$enable_host_pch_support; host_pch_support=$enableval
+else
+  host_pch_support=yes
+fi
+
+
+
+if test x"$host_pch_support" != xno; then
+
+$as_echo "#define ENABLE_HOST_PCH_SUPPORT 1" >>confdefs.h
+
+else
+  $as_echo "#define ENABLE_HOST_PCH_SUPPORT 0" >>confdefs.h
+
+fi
+
+
 # -------------------------
 # Checks for other programs
 # -------------------------
@@ -19455,7 +19480,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19458 "configure"
+#line 19483 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -19561,7 +19586,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 19564 "configure"
+#line 19589 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 065080a4b39..689abf03389 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1178,6 +1178,23 @@ AC_ARG_WITH(multilib-generator,
 :,
 with_multilib_generator=default)
 
+# The current default is that PCH is supported by the host unless otherwise
+# stated.
+AC_ARG_ENABLE(host_pch_support,
+AS_HELP_STRING([--disable-host-pch-support],
+	       [Disable host support for precompiled headers]),
+host_pch_support=$enableval,
+host_pch_support=yes)
+AC_SUBST(host_pch_support)
+
+if test x"$host_pch_support" != xno; then
+  AC_DEFINE(ENABLE_HOST_PCH_SUPPORT, 1,
+    [Define this to enable support for precompiled header (c-family).])
+else
+  AC_DEFINE(ENABLE_HOST_PCH_SUPPORT, 0)
+fi
+
+
 # -------------------------
 # Checks for other programs
 # -------------------------
-- 
2.24.3 (Apple Git-128)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-04 20:02 [PATCH 0/4] config: Allow a host to opt out of PCH Iain Sandoe
  2021-11-04 20:02 ` [PATCH 1/4] config: Add top-level flag to disable host PCH Iain Sandoe
@ 2021-11-05  9:42 ` Richard Biener
  2021-11-05  9:54   ` Jakub Jelinek
  1 sibling, 1 reply; 39+ messages in thread
From: Richard Biener @ 2021-11-05  9:42 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: GCC Patches, Iain Sandoe

On Thu, Nov 4, 2021 at 9:03 PM Iain Sandoe via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
> GCC (currently) has an implementation of pre-compiled-headers, that relies
> on being able to launch the compiler executable at the same address each
> time.  This constraint is not permitted by some system security models.
>
> The facility is an optimisation; saving the output of parsing a covering
> header file (that may include many others) so that the parsing need not be
> repeated when the same set of headers is needed in many places in a project.
>
> The patch series disables the operation of the PCH-related command lines,
> but does not cause an error to be emitted.  The intent is that build
> recipes that expect PCH to work will continue to operate, but the compiler
> no longer acts on them and therefore is no longer bound to the requirement
> to launch at a fixed address.
>
>  * When invoked to "generate PCH" the compiler will carry out the parsing
>    as before - producing any diagnostics if relevant and then saving a
>    stub file (to satisfy build recipe targets).  The stub file is marked as
>    invalid PCH.
>
>  * When an include directive is encountered, the compiler no longer checks
>    to see if a PCH header is available.
>
>  * The top-level configure option (--disable-host-pch-support) is also
>    propagated to libstdc++ where it causes the automatic invocation of the
>    existing --disable-libstdxx-pch.
>
> tested on x86_64-darwin, aarch64-darwin, and on x86_64, powerpc64le-linux,
> OK for master?

I had the impression we have support for PCH file relocation to deal with ASLR
at least on some platforms.  But it's IMHO nice to have a way to disable PCH
and that paves the way to have it disabled by default for a release before we
eventually nuke support completely (and then provide a backward-compatible
stub implementation).

So - OK if there are no complaints from reviewers of their respective area the
series touches.

Thanks,
Richard.

> thanks
> Iain
>
> Iain Sandoe (4):
>   config: Add top-level flag to disable host PCH.
>   libstdc++: Adjust build of PCH files accounting configured host
>     support.
>   libcpp: Honour a configuration without host support for PCH.
>   c-family, gcc: Allow configuring without support for PCH.
>
>  Makefile.def              |  9 ++--
>  Makefile.in               | 87 +++++++++++++++++++++++++--------------
>  configure                 | 42 +++++++++++++++++++
>  configure.ac              | 35 ++++++++++++++++
>  gcc/c-family/c-pch.c      | 23 ++++++++++-
>  gcc/config.in             |  6 +++
>  gcc/config/host-darwin.c  | 18 ++++++++
>  gcc/configure             | 29 ++++++++++++-
>  gcc/configure.ac          | 17 ++++++++
>  gcc/doc/install.texi      |  6 +++
>  libcpp/config.in          |  3 ++
>  libcpp/configure          | 24 +++++++++++
>  libcpp/configure.ac       | 16 +++++++
>  libcpp/files.c            | 14 +++++++
>  libcpp/pch.c              | 12 ++++++
>  libstdc++-v3/acinclude.m4 | 49 +++++++++++++---------
>  libstdc++-v3/configure    | 71 +++++++++++++++++++++-----------
>  libstdc++-v3/configure.ac | 11 ++++-
>  18 files changed, 391 insertions(+), 81 deletions(-)
>
> --
> 2.24.3 (Apple Git-128)
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-05  9:42 ` [PATCH 0/4] config: Allow a host to opt out of PCH Richard Biener
@ 2021-11-05  9:54   ` Jakub Jelinek
  2021-11-05 10:31     ` Richard Biener
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-05  9:54 UTC (permalink / raw)
  To: Richard Biener; +Cc: Iain Sandoe, Iain Sandoe, GCC Patches

On Fri, Nov 05, 2021 at 10:42:05AM +0100, Richard Biener via Gcc-patches wrote:
> I had the impression we have support for PCH file relocation to deal with ASLR
> at least on some platforms.

Unfortunately we do not, e.g. if you build cc1/cc1plus as PIE on
x86_64-linux, PCH will stop working unless one always invokes it with
disabled ASLR through personality.

I think this is related to function pointers and pointers to .rodata/.data
etc. variables in GC memory, we currently do not relocate that.

What we perhaps could do is (at least assuming all the ELF PT_LOAD segments
are adjacent with a single load base for them - I think at least ia64
non-PIE binaries were violating this by having .text and .data PT_LOAD
segments many terrabytes appart with a whole in between not protected in any
way, but dunno if that is for PIEs too), perhaps try in a host
specific way remember the address range in which the function pointers and
.rodata/.data can exist, remember the extent start and end from PCH generation
and on PCH load query those addresses for the current compiler and relocate
everything in that extent by the load bias from the last run.
But, the assumption for this is that those function and data/rodata pointers
in GC memory are actually marked at least as pointers...
Do we e.g. have objects with virtual classes in GC memory and if so, do we
catch their virtual table pointers?

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-05  9:54   ` Jakub Jelinek
@ 2021-11-05 10:31     ` Richard Biener
  2021-11-05 15:25       ` Jakub Jelinek
  0 siblings, 1 reply; 39+ messages in thread
From: Richard Biener @ 2021-11-05 10:31 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Iain Sandoe, Iain Sandoe, GCC Patches

On Fri, Nov 5, 2021 at 10:54 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Fri, Nov 05, 2021 at 10:42:05AM +0100, Richard Biener via Gcc-patches wrote:
> > I had the impression we have support for PCH file relocation to deal with ASLR
> > at least on some platforms.
>
> Unfortunately we do not, e.g. if you build cc1/cc1plus as PIE on
> x86_64-linux, PCH will stop working unless one always invokes it with
> disabled ASLR through personality.
>
> I think this is related to function pointers and pointers to .rodata/.data
> etc. variables in GC memory, we currently do not relocate that.
>
> What we perhaps could do is (at least assuming all the ELF PT_LOAD segments
> are adjacent with a single load base for them - I think at least ia64
> non-PIE binaries were violating this by having .text and .data PT_LOAD
> segments many terrabytes appart with a whole in between not protected in any
> way, but dunno if that is for PIEs too), perhaps try in a host
> specific way remember the address range in which the function pointers and
> .rodata/.data can exist, remember the extent start and end from PCH generation
> and on PCH load query those addresses for the current compiler and relocate
> everything in that extent by the load bias from the last run.
> But, the assumption for this is that those function and data/rodata pointers
> in GC memory are actually marked at least as pointers...

If any such pointers exist they must be marked GTY((skip)) since they do not
point to GC memory...  So we'd need to invent special-handling for those.

> Do we e.g. have objects with virtual classes in GC memory and if so, do we
> catch their virtual table pointers?

Who knows, but then I don't remember adding stuff that should end in a PCH.

Honestly I don't think it's worth spending too much time in making this work.
Iff then disallow pointers to outside GC in PCH (maybe code abort() or
mark_invalid_pch calls into the pch walkers when they reach a GTY((skip)))

Richard.

>         Jakub
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-05 10:31     ` Richard Biener
@ 2021-11-05 15:25       ` Jakub Jelinek
  2021-11-05 16:37         ` Iain Sandoe
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-05 15:25 UTC (permalink / raw)
  To: Richard Biener; +Cc: Iain Sandoe, Iain Sandoe, GCC Patches

On Fri, Nov 05, 2021 at 11:31:58AM +0100, Richard Biener wrote:
> On Fri, Nov 5, 2021 at 10:54 AM Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > On Fri, Nov 05, 2021 at 10:42:05AM +0100, Richard Biener via Gcc-patches wrote:
> > > I had the impression we have support for PCH file relocation to deal with ASLR
> > > at least on some platforms.
> >
> > Unfortunately we do not, e.g. if you build cc1/cc1plus as PIE on
> > x86_64-linux, PCH will stop working unless one always invokes it with
> > disabled ASLR through personality.
> >
> > I think this is related to function pointers and pointers to .rodata/.data
> > etc. variables in GC memory, we currently do not relocate that.
> >
> > What we perhaps could do is (at least assuming all the ELF PT_LOAD segments
> > are adjacent with a single load base for them - I think at least ia64
> > non-PIE binaries were violating this by having .text and .data PT_LOAD
> > segments many terrabytes appart with a whole in between not protected in any
> > way, but dunno if that is for PIEs too), perhaps try in a host
> > specific way remember the address range in which the function pointers and
> > .rodata/.data can exist, remember the extent start and end from PCH generation
> > and on PCH load query those addresses for the current compiler and relocate
> > everything in that extent by the load bias from the last run.
> > But, the assumption for this is that those function and data/rodata pointers
> > in GC memory are actually marked at least as pointers...
> 
> If any such pointers exist they must be marked GTY((skip)) since they do not
> point to GC memory...  So we'd need to invent special-handling for those.
> 
> > Do we e.g. have objects with virtual classes in GC memory and if so, do we
> > catch their virtual table pointers?
> 
> Who knows, but then I don't remember adding stuff that should end in a PCH.

So, I've investigated a little bit.
Apparently all the relocation we currently do for PCH is done at PCH write
time, we choose some address range in the address space we think will be likely
mmappable each time successfully, relocate all pointers pointing to GC
memory to point in there and then write that to file, together with the
scalar GTY global vars values and GTY pointers in global vars.
On PCH load, we just try to mmap memory in the right range, fail PCH load if
unsuccessful, and read the GC memory into that range and update scalar and
pointer GTY global vars from what we've recorded.
Patch that made PCH load to fail for PIEs etc. was
https://gcc.gnu.org/legacy-ml/gcc-patches/2003-10/msg01994.html
If we wanted to relocate pointers to functions and .data/.rodata etc.,
ideally we'd create a relocation list of addresses that should be
incremented by the bias and quickly relocate those.

I wrote following ugly hack:

--- ggc-common.c.jj	2021-08-19 11:42:27.365422400 +0200
+++ ggc-common.c	2021-11-05 15:37:51.447222544 +0100
@@ -404,6 +404,9 @@ struct mmap_info
 
 /* Write out the state of the compiler to F.  */
 
+char *exestart = (char *) 2;
+char *exeend = (char *) 2;
+
 void
 gt_pch_save (FILE *f)
 {
@@ -458,6 +461,14 @@ gt_pch_save (FILE *f)
     for (rti = *rt; rti->base != NULL; rti++)
       if (fwrite (rti->base, rti->stride, 1, f) != 1)
 	fatal_error (input_location, "cannot write PCH file: %m");
+      else if ((((uintptr_t) rti->base) & (sizeof (void *) - 1)) == 0)
+        {
+          char *const *p = (char *const *) rti->base;
+          char *const *q = (char *const *) ((uintptr_t) rti->base + (rti->stride & ~(sizeof (void *) - 1)));
+          for (; p < q; p++)
+	    if (*p >= exestart && *p < exeend)
+	      fprintf (stderr, "scalar at %p points to executable %p\n", (void *) p, (void *) *p);
+        }
 
   /* Write out all the global pointers, after translation.  */
   write_pch_globals (gt_ggc_rtab, &state);
@@ -546,6 +557,15 @@ gt_pch_save (FILE *f)
       state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
 				  state.ptrs[i]->note_ptr_cookie,
 				  relocate_ptrs, &state);
+      if ((((uintptr_t) state.ptrs[i]->obj) & (sizeof (void *) - 1)) == 0)
+        {
+          char *const *p = (char *const *) (state.ptrs[i]->obj);
+          char *const *q = (char *const *) ((uintptr_t) (state.ptrs[i]->obj) + (state.ptrs[i]->size & ~(sizeof (void *) - 1)));
+          for (; p < q; p++)
+	    if (*p >= exestart && *p < exeend)
+	      fprintf (stderr, "object %p at %p points to executable %p\n", (void *) (state.ptrs[i]->obj), (void *) p, (void *) *p);
+        }
+
       ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
 			    state.ptrs[i]->new_addr, state.ptrs[i]->size,
 			    state.ptrs[i]->note_ptr_fn == gt_pch_p_S);

and under debugger set exestart and exeend from /proc/*/maps of the cc1plus
process being debugged (the extent of cc1plus mappings).
This resulted in something like:
scalar at 0x3d869a8 points to executable 0x2dd85e0
scalar at 0x3d869b0 points to executable 0x2dd85e4
scalar at 0x3d869c8 points to executable 0x2dd85e7
...
object 0x7fffea007e70 at 0x7fffea007e70 points to executable 0x11e48c2
object 0x7fffe953dcc0 at 0x7fffe953dcc0 points to executable 0x201e222
object 0x7fffe401d260 at 0x7fffe401d260 points to executable 0x4b0a27
object 0x7fffea02fce0 at 0x7fffea02fce0 points to executable 0x18bb2b0
object 0x7fffe7034ca0 at 0x7fffe7034ca0 points to executable 0x2f81537
object 0x7fffe700f8a0 at 0x7fffe700f8a0 points to executable 0x2c36a32
on stderr.  Unfortunately, I didn't try to rebuild the compiler as PIE, so
unfortunately the range was 0x400000 .. 0x3d9b000 so I'm not really sure
if all it dumped were actually addresses or some nice numbers like 0x1000000
etc.  Much better would be to have the compiler as PIE, run it twice and
only look at values that actually changed, or link the compiler at some very
unlikely virtual address offset so that addresses into it would be easy to
spot.
All the "scalar at " messages are for offsets in the ovl_op_info
array.
struct GTY(()) ovl_op_info_t {
  /* The IDENTIFIER_NODE for the operator.  */
  tree identifier;
  /* The name of the operator.  */
  const char *name;
  /* The mangled name of the operator.  */
  const char *mangled_name;
  /* The (regular) tree code.  */
  enum tree_code tree_code : 16;
  /* The (compressed) operator code.  */
  enum ovl_op_code ovl_op_code : 8;
  /* The ovl_op_flags of the operator */
  unsigned flags : 8;
};
For that particular case gengtype emits:
  {
    &ovl_op_info[0][0].identifier,
    1 * (2) * (OVL_OP_MAX),
    sizeof (ovl_op_info[0][0]),
    &gt_ggc_mx_tree_node,
    &gt_pch_nx_tree_node
  },
  {
    &ovl_op_info[0][0].name,
    1 * (2) * (OVL_OP_MAX),
    sizeof (ovl_op_info[0][0]),
    (gt_pointer_walker) &gt_ggc_m_S,
    (gt_pointer_walker) &gt_pch_n_S
  },
  {
    &ovl_op_info[0][0].mangled_name,
    1 * (2) * (OVL_OP_MAX),
    sizeof (ovl_op_info[0][0]),
    (gt_pointer_walker) &gt_ggc_m_S,
    (gt_pointer_walker) &gt_pch_n_S
  },
so I believe we treat the identifier as always a GC memory object pointer,
and name and mangled_name are const char * pointers which I vaguely remember
we allow to be either NULL, or 1 or GC memory pointers or string literals
(but can't find how it deals with that last category in the source).
From the source:
ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] = 
  {
    {
      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
      {NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
#define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
      {NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
#define OPERATOR_TRANSITION }, {                        \
      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
#include "operators.def"
    }
  };
where operators.def has e.g.:
DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC)
in this particular array the strings are always string literals.
I guess to get ovl_op_info out of the picture we could mark
name and mangled_name as GTY((skip)).
But that is just 178 records, the remaining 52520 are in GC memory
objects.  Figuring out what exactly it is in will be harder...
From the addresses it printed in the last column, the following point
to the start of some cc1plus symbol:
  3310: 0000000000c121d2   831 FUNC    LOCAL  DEFAULT   14 _ZL9min_vis_rPP9tree_nodePiPv
134773: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
  6151: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
188594: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
 37908: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
 50655: 0000000001707c85    37 FUNC    LOCAL  DEFAULT   14 _ZL20realloc_for_line_mapPvm
131570: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
  1653: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
129108: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
 51650: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
 77141: 0000000001b6cb5a   159 FUNC    LOCAL  DEFAULT   14 _ZL10emit_localP9tree_nodePKcmm
 77142: 0000000001b6cbf9    75 FUNC    LOCAL  DEFAULT   14 _ZL8emit_bssP9tree_nodePKcmm
 77143: 0000000001b6cc44    75 FUNC    LOCAL  DEFAULT   14 _ZL11emit_commonP9tree_nodePKcmm
 77144: 0000000001b6cc8f   231 FUNC    LOCAL  DEFAULT   14 _ZL15emit_tls_commonP9tree_nodePKcmm
181390: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
 25347: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
160243: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
163230: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
 26343: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
 40584: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
 12547: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
165150: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
181147: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
 26558: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
  8400: 0000000002e13f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_1
  8448: 0000000002e14260    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
 10166: 0000000002e444a0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL11ALL_GPR_ARGE
 11568: 0000000002e51420    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512FP16
 11735: 0000000002e52f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_VPCLMULQDQ
 12575: 0000000002e5f560    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_ROCKETLAKE
165019: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
  9991: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
 12749: 0000000002e60f60   160 OBJECT  LOCAL  DEFAULT   16 _ZL22extra_order_size_table
 14715: 0000000002e7e340    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
 15895: 0000000002e84480    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_UINTR
 17084: 0000000002e8c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SAPPHIRERAPIDS
 18397: 0000000002e946a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_2
 18986: 0000000002e97580    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
 18990: 0000000002e975c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL17PTA_GOLDMONT_PLUS
 22195: 0000000002eb1640    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_FMA
 30065: 0000000002eed6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512BF16
 31474: 0000000002ef3560     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
 34906: 0000000002f02580    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512BW
 37696: 0000000002f0e420     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
 37701: 0000000002f0e484     4 OBJECT  LOCAL  DEFAULT   16 _ZL40LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES
 38868: 0000000002f13420    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
 39129: 0000000002f143c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_XSAVES
 40610: 0000000002f1e7c0     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
 42157: 0000000002f293c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
 42201: 0000000002f29680    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
 42207: 0000000002f296e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_ICELAKE_SERVER
 49618: 0000000002f556e0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL8USED_ARGE
 50904: 0000000002f5d4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_AVX
 51188: 0000000002f5e6e0    48 OBJECT  LOCAL  DEFAULT   16 _ZN12_GLOBAL__N_1L17pass_data_tm_initE
 56440: 0000000002f7d440    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
 57404: 0000000002f81640     4 OBJECT  LOCAL  DEFAULT   16 _ZL14MAX_LOCATION_T
 57424: 0000000002f816a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_64BIT
 60100: 0000000002f903a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_TILE
 67672: 0000000002fae460    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_COOPERLAKE
 68780: 0000000002fb37c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512CD
 70316: 0000000002fbb4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_LWP
 70637: 0000000002fbc7a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
 70837: 0000000002fbd4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
 73878: 0000000002fcb960    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
 79867: 00000000030435c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
 81991: 0000000003053520    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_F16C
 82244: 0000000003054500    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
 86070: 00000000033ec560    99 OBJECT  LOCAL  DEFAULT   16 _ZL26znver1_agu_min_issue_delay
 86071: 00000000033ec5e0  1334 OBJECT  LOCAL  DEFAULT   16 _ZL15geode_translate
 86228: 00000000034419c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_NO_80387
 94224: 0000000003849420    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
 94230: 0000000003849480    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_XOP
 94647: 000000000384aa40    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SGX
 95488: 000000000384e4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNM
 95820: 000000000384f6a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
 95822: 000000000384f6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
 95824: 000000000384f6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_WAITPKG
 96072: 0000000003850640    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_LZCNT
 96074: 0000000003850660    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_MOVBE
 96080: 00000000038506c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SSE
 98344: 000000000385a4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_ENQCMD
 99309: 000000000385da40    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_POPCNT
103332: 000000000386f2c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CLFLUSHOPT
103344: 000000000386f380    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_PKU
103352: 000000000386f400    16 OBJECT  LOCAL  DEFAULT   16 _ZL15PTA_AVX512VBMI2
103709: 0000000003870a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
104337: 0000000003873660    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
106315: 000000000387d260    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_NO_TUNE
109183: 000000000388c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
111159: 0000000003894a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CANNONLAKE
112043: 00000000038994c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
112049: 0000000003899520    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
113040: 000000000389d6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_BF16
 21876: 0000000003d8d5c0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
 31109: 0000000003d8e100    40 OBJECT  LOCAL  DEFAULT   28 _ZL30unspecified_modref_access_node
 78193: 0000000003d932e0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
 78366: 0000000003d93320    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-05 15:25       ` Jakub Jelinek
@ 2021-11-05 16:37         ` Iain Sandoe
  2021-11-08  7:16           ` Richard Biener
  2021-11-08 11:46           ` Jakub Jelinek
  0 siblings, 2 replies; 39+ messages in thread
From: Iain Sandoe @ 2021-11-05 16:37 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, GCC Patches



> On 5 Nov 2021, at 15:25, Jakub Jelinek <jakub@redhat.com> wrote:
> 
> On Fri, Nov 05, 2021 at 11:31:58AM +0100, Richard Biener wrote:
>> On Fri, Nov 5, 2021 at 10:54 AM Jakub Jelinek <jakub@redhat.com> wrote:
>>> 
>>> On Fri, Nov 05, 2021 at 10:42:05AM +0100, Richard Biener via Gcc-patches wrote:
>>>> I had the impression we have support for PCH file relocation to deal with ASLR
>>>> at least on some platforms.
>>> 
>>> Unfortunately we do not, e.g. if you build cc1/cc1plus as PIE on
>>> x86_64-linux, PCH will stop working unless one always invokes it with
>>> disabled ASLR through personality.
>>> 
>>> I think this is related to function pointers and pointers to .rodata/.data
>>> etc. variables in GC memory, we currently do not relocate that.
>>> 
>>> What we perhaps could do is (at least assuming all the ELF PT_LOAD segments
>>> are adjacent with a single load base for them - I think at least ia64
>>> non-PIE binaries were violating this by having .text and .data PT_LOAD
>>> segments many terrabytes appart with a whole in between not protected in any
>>> way, but dunno if that is for PIEs too), perhaps try in a host
>>> specific way remember the address range in which the function pointers and
>>> .rodata/.data can exist, remember the extent start and end from PCH generation
>>> and on PCH load query those addresses for the current compiler and relocate
>>> everything in that extent by the load bias from the last run.
>>> But, the assumption for this is that those function and data/rodata pointers
>>> in GC memory are actually marked at least as pointers...
>> 
>> If any such pointers exist they must be marked GTY((skip)) since they do not
>> point to GC memory...  So we'd need to invent special-handling for those.
>> 
>>> Do we e.g. have objects with virtual classes in GC memory and if so, do we
>>> catch their virtual table pointers?
>> 
>> Who knows, but then I don't remember adding stuff that should end in a PCH.
> 
> So, I've investigated a little bit.
> Apparently all the relocation we currently do for PCH is done at PCH write
> time, we choose some address range in the address space we think will be likely
> mmappable each time successfully, relocate all pointers pointing to GC
> memory to point in there and then write that to file, together with the
> scalar GTY global vars values and GTY pointers in global vars.
> On PCH load, we just try to mmap memory in the right range, fail PCH load if
> unsuccessful, and read the GC memory into that range and update scalar and
> pointer GTY global vars from what we've recorded.
> Patch that made PCH load to fail for PIEs etc. was
> https://gcc.gnu.org/legacy-ml/gcc-patches/2003-10/msg01994.html
> If we wanted to relocate pointers to functions and .data/.rodata etc.,
> ideally we'd create a relocation list of addresses that should be
> incremented by the bias and quickly relocate those.

It is hard to judge the relative effort in the two immediately visible solutions:

1. relocatable PCH
2. taking the tree streamer from the modules implementation, moving its home
    to c-family and adding hooks so that each FE can stream its own special trees.

ISTM, that part of the reason people dislike PCH is because the implementation is
mixed up with the GC solution - the rendering is non-transparent etc.

So, in some ways, (2) above would be a better investment - the process of PCH is:
generate:
“get to the end of parsing a TU” .. stream the AST
consume:
.. see a header .. stream the PCH AST in if there is one available for the header.

There is no reason for this to be mixed into the GC solution - the read in (currently)
happens to an empty TU and there should be nothing in the AST that carries any
reference to the compiler’s executable.

just 0.02 GBP.
Iain


> 
> I wrote following ugly hack:
> 
> --- ggc-common.c.jj	2021-08-19 11:42:27.365422400 +0200
> +++ ggc-common.c	2021-11-05 15:37:51.447222544 +0100
> @@ -404,6 +404,9 @@ struct mmap_info
> 
> /* Write out the state of the compiler to F.  */
> 
> +char *exestart = (char *) 2;
> +char *exeend = (char *) 2;
> +
> void
> gt_pch_save (FILE *f)
> {
> @@ -458,6 +461,14 @@ gt_pch_save (FILE *f)
>     for (rti = *rt; rti->base != NULL; rti++)
>       if (fwrite (rti->base, rti->stride, 1, f) != 1)
> 	fatal_error (input_location, "cannot write PCH file: %m");
> +      else if ((((uintptr_t) rti->base) & (sizeof (void *) - 1)) == 0)
> +        {
> +          char *const *p = (char *const *) rti->base;
> +          char *const *q = (char *const *) ((uintptr_t) rti->base + (rti->stride & ~(sizeof (void *) - 1)));
> +          for (; p < q; p++)
> +	    if (*p >= exestart && *p < exeend)
> +	      fprintf (stderr, "scalar at %p points to executable %p\n", (void *) p, (void *) *p);
> +        }
> 
>   /* Write out all the global pointers, after translation.  */
>   write_pch_globals (gt_ggc_rtab, &state);
> @@ -546,6 +557,15 @@ gt_pch_save (FILE *f)
>       state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
> 				  state.ptrs[i]->note_ptr_cookie,
> 				  relocate_ptrs, &state);
> +      if ((((uintptr_t) state.ptrs[i]->obj) & (sizeof (void *) - 1)) == 0)
> +        {
> +          char *const *p = (char *const *) (state.ptrs[i]->obj);
> +          char *const *q = (char *const *) ((uintptr_t) (state.ptrs[i]->obj) + (state.ptrs[i]->size & ~(sizeof (void *) - 1)));
> +          for (; p < q; p++)
> +	    if (*p >= exestart && *p < exeend)
> +	      fprintf (stderr, "object %p at %p points to executable %p\n", (void *) (state.ptrs[i]->obj), (void *) p, (void *) *p);
> +        }
> +
>       ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
> 			    state.ptrs[i]->new_addr, state.ptrs[i]->size,
> 			    state.ptrs[i]->note_ptr_fn == gt_pch_p_S);
> 
> and under debugger set exestart and exeend from /proc/*/maps of the cc1plus
> process being debugged (the extent of cc1plus mappings).
> This resulted in something like:
> scalar at 0x3d869a8 points to executable 0x2dd85e0
> scalar at 0x3d869b0 points to executable 0x2dd85e4
> scalar at 0x3d869c8 points to executable 0x2dd85e7
> ...
> object 0x7fffea007e70 at 0x7fffea007e70 points to executable 0x11e48c2
> object 0x7fffe953dcc0 at 0x7fffe953dcc0 points to executable 0x201e222
> object 0x7fffe401d260 at 0x7fffe401d260 points to executable 0x4b0a27
> object 0x7fffea02fce0 at 0x7fffea02fce0 points to executable 0x18bb2b0
> object 0x7fffe7034ca0 at 0x7fffe7034ca0 points to executable 0x2f81537
> object 0x7fffe700f8a0 at 0x7fffe700f8a0 points to executable 0x2c36a32
> on stderr.  Unfortunately, I didn't try to rebuild the compiler as PIE, so
> unfortunately the range was 0x400000 .. 0x3d9b000 so I'm not really sure
> if all it dumped were actually addresses or some nice numbers like 0x1000000
> etc.  Much better would be to have the compiler as PIE, run it twice and
> only look at values that actually changed, or link the compiler at some very
> unlikely virtual address offset so that addresses into it would be easy to
> spot.
> All the "scalar at " messages are for offsets in the ovl_op_info
> array.
> struct GTY(()) ovl_op_info_t {
>  /* The IDENTIFIER_NODE for the operator.  */
>  tree identifier;
>  /* The name of the operator.  */
>  const char *name;
>  /* The mangled name of the operator.  */
>  const char *mangled_name;
>  /* The (regular) tree code.  */
>  enum tree_code tree_code : 16;
>  /* The (compressed) operator code.  */
>  enum ovl_op_code ovl_op_code : 8;
>  /* The ovl_op_flags of the operator */
>  unsigned flags : 8;
> };
> For that particular case gengtype emits:
>  {
>    &ovl_op_info[0][0].identifier,
>    1 * (2) * (OVL_OP_MAX),
>    sizeof (ovl_op_info[0][0]),
>    &gt_ggc_mx_tree_node,
>    &gt_pch_nx_tree_node
>  },
>  {
>    &ovl_op_info[0][0].name,
>    1 * (2) * (OVL_OP_MAX),
>    sizeof (ovl_op_info[0][0]),
>    (gt_pointer_walker) &gt_ggc_m_S,
>    (gt_pointer_walker) &gt_pch_n_S
>  },
>  {
>    &ovl_op_info[0][0].mangled_name,
>    1 * (2) * (OVL_OP_MAX),
>    sizeof (ovl_op_info[0][0]),
>    (gt_pointer_walker) &gt_ggc_m_S,
>    (gt_pointer_walker) &gt_pch_n_S
>  },
> so I believe we treat the identifier as always a GC memory object pointer,
> and name and mangled_name are const char * pointers which I vaguely remember
> we allow to be either NULL, or 1 or GC memory pointers or string literals
> (but can't find how it deals with that last category in the source).
> From the source:
> ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] = 
>  {
>    {
>      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
>      {NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
> #define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
>      {NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
> #define OPERATOR_TRANSITION }, {                        \
>      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
> #include "operators.def"
>    }
>  };
> where operators.def has e.g.:
> DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC)
> in this particular array the strings are always string literals.
> I guess to get ovl_op_info out of the picture we could mark
> name and mangled_name as GTY((skip)).
> But that is just 178 records, the remaining 52520 are in GC memory
> objects.  Figuring out what exactly it is in will be harder...
> From the addresses it printed in the last column, the following point
> to the start of some cc1plus symbol:
>  3310: 0000000000c121d2   831 FUNC    LOCAL  DEFAULT   14 _ZL9min_vis_rPP9tree_nodePiPv
> 134773: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
>  6151: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
> 188594: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
> 37908: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
> 50655: 0000000001707c85    37 FUNC    LOCAL  DEFAULT   14 _ZL20realloc_for_line_mapPvm
> 131570: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
>  1653: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
> 129108: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
> 51650: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
> 77141: 0000000001b6cb5a   159 FUNC    LOCAL  DEFAULT   14 _ZL10emit_localP9tree_nodePKcmm
> 77142: 0000000001b6cbf9    75 FUNC    LOCAL  DEFAULT   14 _ZL8emit_bssP9tree_nodePKcmm
> 77143: 0000000001b6cc44    75 FUNC    LOCAL  DEFAULT   14 _ZL11emit_commonP9tree_nodePKcmm
> 77144: 0000000001b6cc8f   231 FUNC    LOCAL  DEFAULT   14 _ZL15emit_tls_commonP9tree_nodePKcmm
> 181390: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
> 25347: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
> 160243: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
> 163230: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
> 26343: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
> 40584: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
> 12547: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> 165150: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> 181147: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> 26558: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
>  8400: 0000000002e13f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_1
>  8448: 0000000002e14260    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
> 10166: 0000000002e444a0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL11ALL_GPR_ARGE
> 11568: 0000000002e51420    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512FP16
> 11735: 0000000002e52f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_VPCLMULQDQ
> 12575: 0000000002e5f560    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_ROCKETLAKE
> 165019: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
>  9991: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
> 12749: 0000000002e60f60   160 OBJECT  LOCAL  DEFAULT   16 _ZL22extra_order_size_table
> 14715: 0000000002e7e340    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
> 15895: 0000000002e84480    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_UINTR
> 17084: 0000000002e8c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SAPPHIRERAPIDS
> 18397: 0000000002e946a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_2
> 18986: 0000000002e97580    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
> 18990: 0000000002e975c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL17PTA_GOLDMONT_PLUS
> 22195: 0000000002eb1640    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_FMA
> 30065: 0000000002eed6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512BF16
> 31474: 0000000002ef3560     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
> 34906: 0000000002f02580    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512BW
> 37696: 0000000002f0e420     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
> 37701: 0000000002f0e484     4 OBJECT  LOCAL  DEFAULT   16 _ZL40LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES
> 38868: 0000000002f13420    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
> 39129: 0000000002f143c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_XSAVES
> 40610: 0000000002f1e7c0     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
> 42157: 0000000002f293c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
> 42201: 0000000002f29680    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
> 42207: 0000000002f296e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_ICELAKE_SERVER
> 49618: 0000000002f556e0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL8USED_ARGE
> 50904: 0000000002f5d4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_AVX
> 51188: 0000000002f5e6e0    48 OBJECT  LOCAL  DEFAULT   16 _ZN12_GLOBAL__N_1L17pass_data_tm_initE
> 56440: 0000000002f7d440    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
> 57404: 0000000002f81640     4 OBJECT  LOCAL  DEFAULT   16 _ZL14MAX_LOCATION_T
> 57424: 0000000002f816a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_64BIT
> 60100: 0000000002f903a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_TILE
> 67672: 0000000002fae460    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_COOPERLAKE
> 68780: 0000000002fb37c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512CD
> 70316: 0000000002fbb4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_LWP
> 70637: 0000000002fbc7a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
> 70837: 0000000002fbd4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
> 73878: 0000000002fcb960    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
> 79867: 00000000030435c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
> 81991: 0000000003053520    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_F16C
> 82244: 0000000003054500    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
> 86070: 00000000033ec560    99 OBJECT  LOCAL  DEFAULT   16 _ZL26znver1_agu_min_issue_delay
> 86071: 00000000033ec5e0  1334 OBJECT  LOCAL  DEFAULT   16 _ZL15geode_translate
> 86228: 00000000034419c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_NO_80387
> 94224: 0000000003849420    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
> 94230: 0000000003849480    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_XOP
> 94647: 000000000384aa40    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SGX
> 95488: 000000000384e4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNM
> 95820: 000000000384f6a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
> 95822: 000000000384f6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
> 95824: 000000000384f6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_WAITPKG
> 96072: 0000000003850640    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_LZCNT
> 96074: 0000000003850660    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_MOVBE
> 96080: 00000000038506c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SSE
> 98344: 000000000385a4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_ENQCMD
> 99309: 000000000385da40    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_POPCNT
> 103332: 000000000386f2c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CLFLUSHOPT
> 103344: 000000000386f380    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_PKU
> 103352: 000000000386f400    16 OBJECT  LOCAL  DEFAULT   16 _ZL15PTA_AVX512VBMI2
> 103709: 0000000003870a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
> 104337: 0000000003873660    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
> 106315: 000000000387d260    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_NO_TUNE
> 109183: 000000000388c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
> 111159: 0000000003894a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CANNONLAKE
> 112043: 00000000038994c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
> 112049: 0000000003899520    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
> 113040: 000000000389d6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_BF16
> 21876: 0000000003d8d5c0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
> 31109: 0000000003d8e100    40 OBJECT  LOCAL  DEFAULT   28 _ZL30unspecified_modref_access_node
> 78193: 0000000003d932e0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
> 78366: 0000000003d93320    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
> 
> 	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 2/4] libstdc++: Adjust build of PCH files accounting configured host support.
       [not found]     ` <EB9AC754-904B-4877-AD17-94886712C10E@gmail.com>
@ 2021-11-05 23:23       ` Jonathan Wakely
  0 siblings, 0 replies; 39+ messages in thread
From: Jonathan Wakely @ 2021-11-05 23:23 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: libstdc++, gcc Patches

On Thu, 4 Nov 2021 at 21:04, Iain Sandoe wrote:

> Well, I did try to CC it to this list ..
>
> > Begin forwarded message:
> >
> > From: Iain Sandoe via Gcc-patches <gcc-patches@gcc.gnu.org>
> > Subject: [PATCH 2/4] libstdc++: Adjust build of PCH files accounting
> configured host support.
> > Date: 4 November 2021 at 20:02:16 GMT
> > To: gcc-patches@gcc.gnu.org
> > Cc: Iain Sandoe <iains.gcc@gmail.com>
> > Reply-To: iain@sandoe.co.uk
> >
> > This takes account of the overall configuration for host PCH support
> > when deciding if we should build the libstdc++ PCH files.
> >
> > We now require both the support is configured and that we are hosted.
> > A non-fatal configure warning is given if the user attempts to
> > --disable-host-pch-support --enable-libstdcxx-pch since the latter
> > conflicts with the former (but does not prevent a useable libstdc++
> > library build).
>

This looks OK for trunk.



> >
> > Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>
> >
> > libstdc++-v3/ChangeLog:
> >
> >       * acinclude.m4: Account for configured host PCH support.
> >       * configure: Regenerate.
> >       * configure.ac: Act on --enable-host-pch-support.
> > ---
> > libstdc++-v3/acinclude.m4 | 49 ++++++++++++++++-----------
> > libstdc++-v3/configure    | 71 ++++++++++++++++++++++++++-------------
> > libstdc++-v3/configure.ac | 11 ++++--
> > 3 files changed, 86 insertions(+), 45 deletions(-)
> >
> > diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
> > index 90ecc4a87a2..87652306691 100644
> > --- a/libstdc++-v3/acinclude.m4
> > +++ b/libstdc++-v3/acinclude.m4
> > @@ -3225,7 +3225,7 @@ AC_DEFUN([GLIBCXX_ENABLE_WCHAR_T], [
> > ])
> >
> >
> > -dnl
> > +≈
> > dnl Check to see if building and using a C++ precompiled header can be
> done.
> > dnl
> > dnl --enable-libstdcxx-pch=yes
> > @@ -3240,29 +3240,40 @@ dnl Substs:
> > dnl  glibcxx_PCHFLAGS
> > dnl
> > AC_DEFUN([GLIBCXX_ENABLE_PCH], [
> > -  GLIBCXX_ENABLE(libstdcxx-pch,$1,,[build pre-compiled libstdc++
> headers])
> > +  dnl This is only allowed if host support is enabled, and we are
> hosted.
> > +  if test "$1" = "yes" && test "$2" = "yes"; then
> > +    can_pch=yes
> > +  else
> > +    can_pch=no
> > +  fi
> > +  GLIBCXX_ENABLE(libstdcxx-pch,$can_pch,,[build pre-compiled libstdc++
> headers])
> >   if test $enable_libstdcxx_pch = yes; then
> > -    AC_CACHE_CHECK([for compiler with PCH support],
> > -      [glibcxx_cv_prog_CXX_pch],
> > -      [ac_save_CXXFLAGS="$CXXFLAGS"
> > -       CXXFLAGS="$CXXFLAGS -Werror -Winvalid-pch -Wno-deprecated"
> > -       AC_LANG_SAVE
> > -       AC_LANG_CPLUSPLUS
> > -       echo '#include <math.h>' > conftest.h
> > -       if $CXX $CXXFLAGS $CPPFLAGS -x c++-header conftest.h \
> > +    if test "$2" != "yes"; then
> > +      glibcxx_cv_prog_CXX_pch=no
> > +      AC_MSG_WARN([PCH headers cannot be built since host PCH is
> disabled])
> > +    else
> > +      AC_CACHE_CHECK([for compiler with PCH support],
> > +        [glibcxx_cv_prog_CXX_pch],
> > +        [ac_save_CXXFLAGS="$CXXFLAGS"
> > +         CXXFLAGS="$CXXFLAGS -Werror -Winvalid-pch -Wno-deprecated"
> > +         AC_LANG_SAVE
> > +         AC_LANG_CPLUSPLUS
> > +         echo '#include <math.h>' > conftest.h
> > +         if $CXX $CXXFLAGS $CPPFLAGS -x c++-header conftest.h \
> >                         -o conftest.h.gch 1>&5 2>&1 &&
> >               echo '#error "pch failed"' > conftest.h &&
> >         echo '#include "conftest.h"' > conftest.cc &&
> >              $CXX -c $CXXFLAGS $CPPFLAGS conftest.cc 1>&5 2>&1 ;
> > -       then
> > -      glibcxx_cv_prog_CXX_pch=yes
> > -       else
> > -      glibcxx_cv_prog_CXX_pch=no
> > -       fi
> > -       rm -f conftest*
> > -       CXXFLAGS=$ac_save_CXXFLAGS
> > -       AC_LANG_RESTORE
> > -      ])
> > +         then
> > +        glibcxx_cv_prog_CXX_pch=yes
> > +         else
> > +        glibcxx_cv_prog_CXX_pch=no
> > +         fi
> > +         rm -f conftest*
> > +         CXXFLAGS=$ac_save_CXXFLAGS
> > +         AC_LANG_RESTORE
> > +        ])
> > +    fi
> >     enable_libstdcxx_pch=$glibcxx_cv_prog_CXX_pch
> >   fi
> >
> >
> > diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
> > index 2d68b3672b9..ce82f16c859 100644
> > --- a/libstdc++-v3/configure.ac
> > +++ b/libstdc++-v3/configure.ac
> > @@ -103,7 +103,6 @@ if test "$enable_vtable_verify" = yes; then
> >   postdep_objects_CXX="${postdep_objects_CXX}
> ${glibcxx_builddir}/../libgcc/vtv_end.o"
> > fi
> >
> > -
> > # libtool variables for C++ shared and position-independent compiles.
> > #
> > # Use glibcxx_lt_pic_flag to designate the automake variable
> > @@ -147,8 +146,16 @@ GLIBCXX_ENABLE_HOSTED
> > # Enable descriptive messages to standard output on termination.
> > GLIBCXX_ENABLE_VERBOSE
> >
> > +# The current default is that PCH is supported by the host unless
> otherwise
> > +# stated.
> > +AC_ARG_ENABLE(host_pch_support,
> > +AS_HELP_STRING([--disable-host-pch-support],
> > +            [Disable host support for precompiled headers]),
> > +host_pch_support=$enableval,
> > +host_pch_support=yes)
> > +
> > # Enable compiler support that doesn't require linking.
> > -GLIBCXX_ENABLE_PCH($is_hosted)
> > +GLIBCXX_ENABLE_PCH($is_hosted, $host_pch_support)
> > GLIBCXX_ENABLE_THREADS
> > GLIBCXX_ENABLE_ATOMIC_BUILTINS
> > GLIBCXX_ENABLE_LOCK_POLICY
> > --
> > 2.24.3 (Apple Git-128)
> >
>
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-05 16:37         ` Iain Sandoe
@ 2021-11-08  7:16           ` Richard Biener
  2021-11-08  7:43             ` Iain Sandoe
  2021-11-08 11:46           ` Jakub Jelinek
  1 sibling, 1 reply; 39+ messages in thread
From: Richard Biener @ 2021-11-08  7:16 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: Jakub Jelinek, GCC Patches

On Fri, Nov 5, 2021 at 5:37 PM Iain Sandoe <iain@sandoe.co.uk> wrote:
>
>
>
> > On 5 Nov 2021, at 15:25, Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > On Fri, Nov 05, 2021 at 11:31:58AM +0100, Richard Biener wrote:
> >> On Fri, Nov 5, 2021 at 10:54 AM Jakub Jelinek <jakub@redhat.com> wrote:
> >>>
> >>> On Fri, Nov 05, 2021 at 10:42:05AM +0100, Richard Biener via Gcc-patches wrote:
> >>>> I had the impression we have support for PCH file relocation to deal with ASLR
> >>>> at least on some platforms.
> >>>
> >>> Unfortunately we do not, e.g. if you build cc1/cc1plus as PIE on
> >>> x86_64-linux, PCH will stop working unless one always invokes it with
> >>> disabled ASLR through personality.
> >>>
> >>> I think this is related to function pointers and pointers to .rodata/.data
> >>> etc. variables in GC memory, we currently do not relocate that.
> >>>
> >>> What we perhaps could do is (at least assuming all the ELF PT_LOAD segments
> >>> are adjacent with a single load base for them - I think at least ia64
> >>> non-PIE binaries were violating this by having .text and .data PT_LOAD
> >>> segments many terrabytes appart with a whole in between not protected in any
> >>> way, but dunno if that is for PIEs too), perhaps try in a host
> >>> specific way remember the address range in which the function pointers and
> >>> .rodata/.data can exist, remember the extent start and end from PCH generation
> >>> and on PCH load query those addresses for the current compiler and relocate
> >>> everything in that extent by the load bias from the last run.
> >>> But, the assumption for this is that those function and data/rodata pointers
> >>> in GC memory are actually marked at least as pointers...
> >>
> >> If any such pointers exist they must be marked GTY((skip)) since they do not
> >> point to GC memory...  So we'd need to invent special-handling for those.
> >>
> >>> Do we e.g. have objects with virtual classes in GC memory and if so, do we
> >>> catch their virtual table pointers?
> >>
> >> Who knows, but then I don't remember adding stuff that should end in a PCH.
> >
> > So, I've investigated a little bit.
> > Apparently all the relocation we currently do for PCH is done at PCH write
> > time, we choose some address range in the address space we think will be likely
> > mmappable each time successfully, relocate all pointers pointing to GC
> > memory to point in there and then write that to file, together with the
> > scalar GTY global vars values and GTY pointers in global vars.
> > On PCH load, we just try to mmap memory in the right range, fail PCH load if
> > unsuccessful, and read the GC memory into that range and update scalar and
> > pointer GTY global vars from what we've recorded.
> > Patch that made PCH load to fail for PIEs etc. was
> > https://gcc.gnu.org/legacy-ml/gcc-patches/2003-10/msg01994.html
> > If we wanted to relocate pointers to functions and .data/.rodata etc.,
> > ideally we'd create a relocation list of addresses that should be
> > incremented by the bias and quickly relocate those.
>
> It is hard to judge the relative effort in the two immediately visible solutions:
>
> 1. relocatable PCH
> 2. taking the tree streamer from the modules implementation, moving its home
>     to c-family and adding hooks so that each FE can stream its own special trees.
>
> ISTM, that part of the reason people dislike PCH is because the implementation is
> mixed up with the GC solution - the rendering is non-transparent etc.

Yes.  In particular it stands in the way of even thinking of doing sth
different than
GC for trees.

> So, in some ways, (2) above would be a better investment - the process of PCH is:
> generate:
> “get to the end of parsing a TU” .. stream the AST
> consume:
> .. see a header .. stream the PCH AST in if there is one available for the header.
>
> There is no reason for this to be mixed into the GC solution - the read in (currently)
> happens to an empty TU and there should be nothing in the AST that carries any
> reference to the compiler’s executable.

It makes the PCH read-in "cheap" - IIRC Google invested quite some work in
evaluating different PC* approaches but none in the end made a big enough
difference.  Given we now have a standards backed PCH-like thing for C++
with modules and given that for C (besides on Darwin...) PCH never made much
sense I doubt investing into generalizing the C++ module support or making
PCH relocatable is worth the trouble.

Richard.

>
> just 0.02 GBP.
> Iain
>
>
> >
> > I wrote following ugly hack:
> >
> > --- ggc-common.c.jj   2021-08-19 11:42:27.365422400 +0200
> > +++ ggc-common.c      2021-11-05 15:37:51.447222544 +0100
> > @@ -404,6 +404,9 @@ struct mmap_info
> >
> > /* Write out the state of the compiler to F.  */
> >
> > +char *exestart = (char *) 2;
> > +char *exeend = (char *) 2;
> > +
> > void
> > gt_pch_save (FILE *f)
> > {
> > @@ -458,6 +461,14 @@ gt_pch_save (FILE *f)
> >     for (rti = *rt; rti->base != NULL; rti++)
> >       if (fwrite (rti->base, rti->stride, 1, f) != 1)
> >       fatal_error (input_location, "cannot write PCH file: %m");
> > +      else if ((((uintptr_t) rti->base) & (sizeof (void *) - 1)) == 0)
> > +        {
> > +          char *const *p = (char *const *) rti->base;
> > +          char *const *q = (char *const *) ((uintptr_t) rti->base + (rti->stride & ~(sizeof (void *) - 1)));
> > +          for (; p < q; p++)
> > +         if (*p >= exestart && *p < exeend)
> > +           fprintf (stderr, "scalar at %p points to executable %p\n", (void *) p, (void *) *p);
> > +        }
> >
> >   /* Write out all the global pointers, after translation.  */
> >   write_pch_globals (gt_ggc_rtab, &state);
> > @@ -546,6 +557,15 @@ gt_pch_save (FILE *f)
> >       state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
> >                                 state.ptrs[i]->note_ptr_cookie,
> >                                 relocate_ptrs, &state);
> > +      if ((((uintptr_t) state.ptrs[i]->obj) & (sizeof (void *) - 1)) == 0)
> > +        {
> > +          char *const *p = (char *const *) (state.ptrs[i]->obj);
> > +          char *const *q = (char *const *) ((uintptr_t) (state.ptrs[i]->obj) + (state.ptrs[i]->size & ~(sizeof (void *) - 1)));
> > +          for (; p < q; p++)
> > +         if (*p >= exestart && *p < exeend)
> > +           fprintf (stderr, "object %p at %p points to executable %p\n", (void *) (state.ptrs[i]->obj), (void *) p, (void *) *p);
> > +        }
> > +
> >       ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
> >                           state.ptrs[i]->new_addr, state.ptrs[i]->size,
> >                           state.ptrs[i]->note_ptr_fn == gt_pch_p_S);
> >
> > and under debugger set exestart and exeend from /proc/*/maps of the cc1plus
> > process being debugged (the extent of cc1plus mappings).
> > This resulted in something like:
> > scalar at 0x3d869a8 points to executable 0x2dd85e0
> > scalar at 0x3d869b0 points to executable 0x2dd85e4
> > scalar at 0x3d869c8 points to executable 0x2dd85e7
> > ...
> > object 0x7fffea007e70 at 0x7fffea007e70 points to executable 0x11e48c2
> > object 0x7fffe953dcc0 at 0x7fffe953dcc0 points to executable 0x201e222
> > object 0x7fffe401d260 at 0x7fffe401d260 points to executable 0x4b0a27
> > object 0x7fffea02fce0 at 0x7fffea02fce0 points to executable 0x18bb2b0
> > object 0x7fffe7034ca0 at 0x7fffe7034ca0 points to executable 0x2f81537
> > object 0x7fffe700f8a0 at 0x7fffe700f8a0 points to executable 0x2c36a32
> > on stderr.  Unfortunately, I didn't try to rebuild the compiler as PIE, so
> > unfortunately the range was 0x400000 .. 0x3d9b000 so I'm not really sure
> > if all it dumped were actually addresses or some nice numbers like 0x1000000
> > etc.  Much better would be to have the compiler as PIE, run it twice and
> > only look at values that actually changed, or link the compiler at some very
> > unlikely virtual address offset so that addresses into it would be easy to
> > spot.
> > All the "scalar at " messages are for offsets in the ovl_op_info
> > array.
> > struct GTY(()) ovl_op_info_t {
> >  /* The IDENTIFIER_NODE for the operator.  */
> >  tree identifier;
> >  /* The name of the operator.  */
> >  const char *name;
> >  /* The mangled name of the operator.  */
> >  const char *mangled_name;
> >  /* The (regular) tree code.  */
> >  enum tree_code tree_code : 16;
> >  /* The (compressed) operator code.  */
> >  enum ovl_op_code ovl_op_code : 8;
> >  /* The ovl_op_flags of the operator */
> >  unsigned flags : 8;
> > };
> > For that particular case gengtype emits:
> >  {
> >    &ovl_op_info[0][0].identifier,
> >    1 * (2) * (OVL_OP_MAX),
> >    sizeof (ovl_op_info[0][0]),
> >    &gt_ggc_mx_tree_node,
> >    &gt_pch_nx_tree_node
> >  },
> >  {
> >    &ovl_op_info[0][0].name,
> >    1 * (2) * (OVL_OP_MAX),
> >    sizeof (ovl_op_info[0][0]),
> >    (gt_pointer_walker) &gt_ggc_m_S,
> >    (gt_pointer_walker) &gt_pch_n_S
> >  },
> >  {
> >    &ovl_op_info[0][0].mangled_name,
> >    1 * (2) * (OVL_OP_MAX),
> >    sizeof (ovl_op_info[0][0]),
> >    (gt_pointer_walker) &gt_ggc_m_S,
> >    (gt_pointer_walker) &gt_pch_n_S
> >  },
> > so I believe we treat the identifier as always a GC memory object pointer,
> > and name and mangled_name are const char * pointers which I vaguely remember
> > we allow to be either NULL, or 1 or GC memory pointers or string literals
> > (but can't find how it deals with that last category in the source).
> > From the source:
> > ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
> >  {
> >    {
> >      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
> >      {NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
> > #define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
> >      {NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
> > #define OPERATOR_TRANSITION }, {                        \
> >      {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
> > #include "operators.def"
> >    }
> >  };
> > where operators.def has e.g.:
> > DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC)
> > in this particular array the strings are always string literals.
> > I guess to get ovl_op_info out of the picture we could mark
> > name and mangled_name as GTY((skip)).
> > But that is just 178 records, the remaining 52520 are in GC memory
> > objects.  Figuring out what exactly it is in will be harder...
> > From the addresses it printed in the last column, the following point
> > to the start of some cc1plus symbol:
> >  3310: 0000000000c121d2   831 FUNC    LOCAL  DEFAULT   14 _ZL9min_vis_rPP9tree_nodePiPv
> > 134773: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
> >  6151: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
> > 188594: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
> > 37908: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
> > 50655: 0000000001707c85    37 FUNC    LOCAL  DEFAULT   14 _ZL20realloc_for_line_mapPvm
> > 131570: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
> >  1653: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
> > 129108: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
> > 51650: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
> > 77141: 0000000001b6cb5a   159 FUNC    LOCAL  DEFAULT   14 _ZL10emit_localP9tree_nodePKcmm
> > 77142: 0000000001b6cbf9    75 FUNC    LOCAL  DEFAULT   14 _ZL8emit_bssP9tree_nodePKcmm
> > 77143: 0000000001b6cc44    75 FUNC    LOCAL  DEFAULT   14 _ZL11emit_commonP9tree_nodePKcmm
> > 77144: 0000000001b6cc8f   231 FUNC    LOCAL  DEFAULT   14 _ZL15emit_tls_commonP9tree_nodePKcmm
> > 181390: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
> > 25347: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
> > 160243: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
> > 163230: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
> > 26343: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
> > 40584: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
> > 12547: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> > 165150: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> > 181147: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> > 26558: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
> >  8400: 0000000002e13f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_1
> >  8448: 0000000002e14260    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
> > 10166: 0000000002e444a0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL11ALL_GPR_ARGE
> > 11568: 0000000002e51420    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512FP16
> > 11735: 0000000002e52f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_VPCLMULQDQ
> > 12575: 0000000002e5f560    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_ROCKETLAKE
> > 165019: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
> >  9991: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
> > 12749: 0000000002e60f60   160 OBJECT  LOCAL  DEFAULT   16 _ZL22extra_order_size_table
> > 14715: 0000000002e7e340    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
> > 15895: 0000000002e84480    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_UINTR
> > 17084: 0000000002e8c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SAPPHIRERAPIDS
> > 18397: 0000000002e946a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_2
> > 18986: 0000000002e97580    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
> > 18990: 0000000002e975c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL17PTA_GOLDMONT_PLUS
> > 22195: 0000000002eb1640    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_FMA
> > 30065: 0000000002eed6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512BF16
> > 31474: 0000000002ef3560     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
> > 34906: 0000000002f02580    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512BW
> > 37696: 0000000002f0e420     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
> > 37701: 0000000002f0e484     4 OBJECT  LOCAL  DEFAULT   16 _ZL40LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES
> > 38868: 0000000002f13420    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
> > 39129: 0000000002f143c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_XSAVES
> > 40610: 0000000002f1e7c0     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
> > 42157: 0000000002f293c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
> > 42201: 0000000002f29680    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
> > 42207: 0000000002f296e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_ICELAKE_SERVER
> > 49618: 0000000002f556e0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL8USED_ARGE
> > 50904: 0000000002f5d4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_AVX
> > 51188: 0000000002f5e6e0    48 OBJECT  LOCAL  DEFAULT   16 _ZN12_GLOBAL__N_1L17pass_data_tm_initE
> > 56440: 0000000002f7d440    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
> > 57404: 0000000002f81640     4 OBJECT  LOCAL  DEFAULT   16 _ZL14MAX_LOCATION_T
> > 57424: 0000000002f816a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_64BIT
> > 60100: 0000000002f903a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_TILE
> > 67672: 0000000002fae460    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_COOPERLAKE
> > 68780: 0000000002fb37c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512CD
> > 70316: 0000000002fbb4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_LWP
> > 70637: 0000000002fbc7a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
> > 70837: 0000000002fbd4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
> > 73878: 0000000002fcb960    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
> > 79867: 00000000030435c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
> > 81991: 0000000003053520    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_F16C
> > 82244: 0000000003054500    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
> > 86070: 00000000033ec560    99 OBJECT  LOCAL  DEFAULT   16 _ZL26znver1_agu_min_issue_delay
> > 86071: 00000000033ec5e0  1334 OBJECT  LOCAL  DEFAULT   16 _ZL15geode_translate
> > 86228: 00000000034419c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_NO_80387
> > 94224: 0000000003849420    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
> > 94230: 0000000003849480    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_XOP
> > 94647: 000000000384aa40    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SGX
> > 95488: 000000000384e4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNM
> > 95820: 000000000384f6a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
> > 95822: 000000000384f6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
> > 95824: 000000000384f6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_WAITPKG
> > 96072: 0000000003850640    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_LZCNT
> > 96074: 0000000003850660    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_MOVBE
> > 96080: 00000000038506c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SSE
> > 98344: 000000000385a4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_ENQCMD
> > 99309: 000000000385da40    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_POPCNT
> > 103332: 000000000386f2c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CLFLUSHOPT
> > 103344: 000000000386f380    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_PKU
> > 103352: 000000000386f400    16 OBJECT  LOCAL  DEFAULT   16 _ZL15PTA_AVX512VBMI2
> > 103709: 0000000003870a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
> > 104337: 0000000003873660    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
> > 106315: 000000000387d260    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_NO_TUNE
> > 109183: 000000000388c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
> > 111159: 0000000003894a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CANNONLAKE
> > 112043: 00000000038994c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
> > 112049: 0000000003899520    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
> > 113040: 000000000389d6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_BF16
> > 21876: 0000000003d8d5c0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
> > 31109: 0000000003d8e100    40 OBJECT  LOCAL  DEFAULT   28 _ZL30unspecified_modref_access_node
> > 78193: 0000000003d932e0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
> > 78366: 0000000003d93320    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
> >
> >       Jakub
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-08  7:16           ` Richard Biener
@ 2021-11-08  7:43             ` Iain Sandoe
  0 siblings, 0 replies; 39+ messages in thread
From: Iain Sandoe @ 2021-11-08  7:43 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jakub Jelinek, GCC Patches



> On 8 Nov 2021, at 07:16, Richard Biener <richard.guenther@gmail.com> wrote:
> 
> On Fri, Nov 5, 2021 at 5:37 PM Iain Sandoe <iain@sandoe.co.uk> wrote:
>> 
>> 
>> 
>>> On 5 Nov 2021, at 15:25, Jakub Jelinek <jakub@redhat.com> wrote:
>>> 
>>> On Fri, Nov 05, 2021 at 11:31:58AM +0100, Richard Biener wrote:
>>>> On Fri, Nov 5, 2021 at 10:54 AM Jakub Jelinek <jakub@redhat.com> wrote:
>>>>> 
>>>>> On Fri, Nov 05, 2021 at 10:42:05AM +0100, Richard Biener via Gcc-patches wrote:
>>>>>> I had the impression we have support for PCH file relocation to deal with ASLR
>>>>>> at least on some platforms.
>>>>> 
>>>>> Unfortunately we do not, e.g. if you build cc1/cc1plus as PIE on
>>>>> x86_64-linux, PCH will stop working unless one always invokes it with
>>>>> disabled ASLR through personality.
>>>>> 
>>>>> I think this is related to function pointers and pointers to .rodata/.data
>>>>> etc. variables in GC memory, we currently do not relocate that.
>>>>> 
>>>>> What we perhaps could do is (at least assuming all the ELF PT_LOAD segments
>>>>> are adjacent with a single load base for them - I think at least ia64
>>>>> non-PIE binaries were violating this by having .text and .data PT_LOAD
>>>>> segments many terrabytes appart with a whole in between not protected in any
>>>>> way, but dunno if that is for PIEs too), perhaps try in a host
>>>>> specific way remember the address range in which the function pointers and
>>>>> .rodata/.data can exist, remember the extent start and end from PCH generation
>>>>> and on PCH load query those addresses for the current compiler and relocate
>>>>> everything in that extent by the load bias from the last run.
>>>>> But, the assumption for this is that those function and data/rodata pointers
>>>>> in GC memory are actually marked at least as pointers...
>>>> 
>>>> If any such pointers exist they must be marked GTY((skip)) since they do not
>>>> point to GC memory...  So we'd need to invent special-handling for those.
>>>> 
>>>>> Do we e.g. have objects with virtual classes in GC memory and if so, do we
>>>>> catch their virtual table pointers?
>>>> 
>>>> Who knows, but then I don't remember adding stuff that should end in a PCH.
>>> 
>>> So, I've investigated a little bit.
>>> Apparently all the relocation we currently do for PCH is done at PCH write
>>> time, we choose some address range in the address space we think will be likely
>>> mmappable each time successfully, relocate all pointers pointing to GC
>>> memory to point in there and then write that to file, together with the
>>> scalar GTY global vars values and GTY pointers in global vars.
>>> On PCH load, we just try to mmap memory in the right range, fail PCH load if
>>> unsuccessful, and read the GC memory into that range and update scalar and
>>> pointer GTY global vars from what we've recorded.
>>> Patch that made PCH load to fail for PIEs etc. was
>>> https://gcc.gnu.org/legacy-ml/gcc-patches/2003-10/msg01994.html
>>> If we wanted to relocate pointers to functions and .data/.rodata etc.,
>>> ideally we'd create a relocation list of addresses that should be
>>> incremented by the bias and quickly relocate those.
>> 
>> It is hard to judge the relative effort in the two immediately visible solutions:
>> 
>> 1. relocatable PCH
>> 2. taking the tree streamer from the modules implementation, moving its home
>>    to c-family and adding hooks so that each FE can stream its own special trees.
>> 
>> ISTM, that part of the reason people dislike PCH is because the implementation is
>> mixed up with the GC solution - the rendering is non-transparent etc.
> 
> Yes.  In particular it stands in the way of even thinking of doing sth
> different than
> GC for trees.
> 
>> So, in some ways, (2) above would be a better investment - the process of PCH is:
>> generate:
>> “get to the end of parsing a TU” .. stream the AST
>> consume:
>> .. see a header .. stream the PCH AST in if there is one available for the header.
>> 
>> There is no reason for this to be mixed into the GC solution - the read in (currently)
>> happens to an empty TU and there should be nothing in the AST that carries any
>> reference to the compiler’s executable.
> 
> It makes the PCH read-in "cheap" - IIRC Google invested quite some work in
> evaluating different PC* approaches but none in the end made a big enough
> difference.

that was presumably looking for a more efficient streamer - where we care more now
about a less invasive streamer.

>  Given we now have a standards backed PCH-like thing for C++
> with modules and given that for C (besides on Darwin…)

For the record, it’s not actually Darwin that is calling for it - it’s Objective-C (which has
large header uses in much the same way as C++) - so it would/will affect GNUStep
in the same way.

> PCH never made much
> sense I doubt investing into generalizing the C++ module support or making
> PCH relocatable is worth the trouble.

There are certainly things higher on my TODO …
Iain

> 
> 
> Richard.
> 
>> 
>> just 0.02 GBP.
>> Iain
>> 
>> 
>>> 
>>> I wrote following ugly hack:
>>> 
>>> --- ggc-common.c.jj   2021-08-19 11:42:27.365422400 +0200
>>> +++ ggc-common.c      2021-11-05 15:37:51.447222544 +0100
>>> @@ -404,6 +404,9 @@ struct mmap_info
>>> 
>>> /* Write out the state of the compiler to F.  */
>>> 
>>> +char *exestart = (char *) 2;
>>> +char *exeend = (char *) 2;
>>> +
>>> void
>>> gt_pch_save (FILE *f)
>>> {
>>> @@ -458,6 +461,14 @@ gt_pch_save (FILE *f)
>>>    for (rti = *rt; rti->base != NULL; rti++)
>>>      if (fwrite (rti->base, rti->stride, 1, f) != 1)
>>>      fatal_error (input_location, "cannot write PCH file: %m");
>>> +      else if ((((uintptr_t) rti->base) & (sizeof (void *) - 1)) == 0)
>>> +        {
>>> +          char *const *p = (char *const *) rti->base;
>>> +          char *const *q = (char *const *) ((uintptr_t) rti->base + (rti->stride & ~(sizeof (void *) - 1)));
>>> +          for (; p < q; p++)
>>> +         if (*p >= exestart && *p < exeend)
>>> +           fprintf (stderr, "scalar at %p points to executable %p\n", (void *) p, (void *) *p);
>>> +        }
>>> 
>>>  /* Write out all the global pointers, after translation.  */
>>>  write_pch_globals (gt_ggc_rtab, &state);
>>> @@ -546,6 +557,15 @@ gt_pch_save (FILE *f)
>>>      state.ptrs[i]->note_ptr_fn (state.ptrs[i]->obj,
>>>                                state.ptrs[i]->note_ptr_cookie,
>>>                                relocate_ptrs, &state);
>>> +      if ((((uintptr_t) state.ptrs[i]->obj) & (sizeof (void *) - 1)) == 0)
>>> +        {
>>> +          char *const *p = (char *const *) (state.ptrs[i]->obj);
>>> +          char *const *q = (char *const *) ((uintptr_t) (state.ptrs[i]->obj) + (state.ptrs[i]->size & ~(sizeof (void *) - 1)));
>>> +          for (; p < q; p++)
>>> +         if (*p >= exestart && *p < exeend)
>>> +           fprintf (stderr, "object %p at %p points to executable %p\n", (void *) (state.ptrs[i]->obj), (void *) p, (void *) *p);
>>> +        }
>>> +
>>>      ggc_pch_write_object (state.d, state.f, state.ptrs[i]->obj,
>>>                          state.ptrs[i]->new_addr, state.ptrs[i]->size,
>>>                          state.ptrs[i]->note_ptr_fn == gt_pch_p_S);
>>> 
>>> and under debugger set exestart and exeend from /proc/*/maps of the cc1plus
>>> process being debugged (the extent of cc1plus mappings).
>>> This resulted in something like:
>>> scalar at 0x3d869a8 points to executable 0x2dd85e0
>>> scalar at 0x3d869b0 points to executable 0x2dd85e4
>>> scalar at 0x3d869c8 points to executable 0x2dd85e7
>>> ...
>>> object 0x7fffea007e70 at 0x7fffea007e70 points to executable 0x11e48c2
>>> object 0x7fffe953dcc0 at 0x7fffe953dcc0 points to executable 0x201e222
>>> object 0x7fffe401d260 at 0x7fffe401d260 points to executable 0x4b0a27
>>> object 0x7fffea02fce0 at 0x7fffea02fce0 points to executable 0x18bb2b0
>>> object 0x7fffe7034ca0 at 0x7fffe7034ca0 points to executable 0x2f81537
>>> object 0x7fffe700f8a0 at 0x7fffe700f8a0 points to executable 0x2c36a32
>>> on stderr.  Unfortunately, I didn't try to rebuild the compiler as PIE, so
>>> unfortunately the range was 0x400000 .. 0x3d9b000 so I'm not really sure
>>> if all it dumped were actually addresses or some nice numbers like 0x1000000
>>> etc.  Much better would be to have the compiler as PIE, run it twice and
>>> only look at values that actually changed, or link the compiler at some very
>>> unlikely virtual address offset so that addresses into it would be easy to
>>> spot.
>>> All the "scalar at " messages are for offsets in the ovl_op_info
>>> array.
>>> struct GTY(()) ovl_op_info_t {
>>> /* The IDENTIFIER_NODE for the operator.  */
>>> tree identifier;
>>> /* The name of the operator.  */
>>> const char *name;
>>> /* The mangled name of the operator.  */
>>> const char *mangled_name;
>>> /* The (regular) tree code.  */
>>> enum tree_code tree_code : 16;
>>> /* The (compressed) operator code.  */
>>> enum ovl_op_code ovl_op_code : 8;
>>> /* The ovl_op_flags of the operator */
>>> unsigned flags : 8;
>>> };
>>> For that particular case gengtype emits:
>>> {
>>>   &ovl_op_info[0][0].identifier,
>>>   1 * (2) * (OVL_OP_MAX),
>>>   sizeof (ovl_op_info[0][0]),
>>>   &gt_ggc_mx_tree_node,
>>>   &gt_pch_nx_tree_node
>>> },
>>> {
>>>   &ovl_op_info[0][0].name,
>>>   1 * (2) * (OVL_OP_MAX),
>>>   sizeof (ovl_op_info[0][0]),
>>>   (gt_pointer_walker) &gt_ggc_m_S,
>>>   (gt_pointer_walker) &gt_pch_n_S
>>> },
>>> {
>>>   &ovl_op_info[0][0].mangled_name,
>>>   1 * (2) * (OVL_OP_MAX),
>>>   sizeof (ovl_op_info[0][0]),
>>>   (gt_pointer_walker) &gt_ggc_m_S,
>>>   (gt_pointer_walker) &gt_pch_n_S
>>> },
>>> so I believe we treat the identifier as always a GC memory object pointer,
>>> and name and mangled_name are const char * pointers which I vaguely remember
>>> we allow to be either NULL, or 1 or GC memory pointers or string literals
>>> (but can't find how it deals with that last category in the source).
>>> From the source:
>>> ovl_op_info_t ovl_op_info[2][OVL_OP_MAX] =
>>> {
>>>   {
>>>     {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
>>>     {NULL_TREE, NULL, NULL, NOP_EXPR, OVL_OP_NOP_EXPR, 0},
>>> #define DEF_OPERATOR(NAME, CODE, MANGLING, FLAGS) \
>>>     {NULL_TREE, NAME, MANGLING, CODE, OVL_OP_##CODE, FLAGS},
>>> #define OPERATOR_TRANSITION }, {                        \
>>>     {NULL_TREE, NULL, NULL, ERROR_MARK, OVL_OP_ERROR_MARK, 0},
>>> #include "operators.def"
>>>   }
>>> };
>>> where operators.def has e.g.:
>>> DEF_OPERATOR ("new", NEW_EXPR, "nw", OVL_OP_FLAG_ALLOC)
>>> in this particular array the strings are always string literals.
>>> I guess to get ovl_op_info out of the picture we could mark
>>> name and mangled_name as GTY((skip)).
>>> But that is just 178 records, the remaining 52520 are in GC memory
>>> objects.  Figuring out what exactly it is in will be harder...
>>> From the addresses it printed in the last column, the following point
>>> to the start of some cc1plus symbol:
>>> 3310: 0000000000c121d2   831 FUNC    LOCAL  DEFAULT   14 _ZL9min_vis_rPP9tree_nodePiPv
>>> 134773: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
>>> 6151: 0000000000fa67a9    47 FUNC    GLOBAL DEFAULT   14 _Z20ggc_round_alloc_sizem
>>> 188594: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
>>> 37908: 000000000102d0a0    26 FUNC    WEAK   DEFAULT   14 _Z4is_aIP7gswitch6gimpleEbPT0_
>>> 50655: 0000000001707c85    37 FUNC    LOCAL  DEFAULT   14 _ZL20realloc_for_line_mapPvm
>>> 131570: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
>>> 1653: 000000000178d3e0    66 FUNC    WEAK   DEFAULT   14 _ZNK3vecI13numbered_tree7va_heap6vl_ptrE5spaceEi
>>> 129108: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
>>> 51650: 000000000178e520    43 FUNC    WEAK   DEFAULT   14 _ZNK3vecI12loc_map_pair7va_heap8vl_embedE5spaceEj
>>> 77141: 0000000001b6cb5a   159 FUNC    LOCAL  DEFAULT   14 _ZL10emit_localP9tree_nodePKcmm
>>> 77142: 0000000001b6cbf9    75 FUNC    LOCAL  DEFAULT   14 _ZL8emit_bssP9tree_nodePKcmm
>>> 77143: 0000000001b6cc44    75 FUNC    LOCAL  DEFAULT   14 _ZL11emit_commonP9tree_nodePKcmm
>>> 77144: 0000000001b6cc8f   231 FUNC    LOCAL  DEFAULT   14 _ZL15emit_tls_commonP9tree_nodePKcmm
>>> 181390: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
>>> 25347: 0000000001b7e3d0    44 FUNC    GLOBAL DEFAULT   14 _Z21output_section_asm_opPKv
>>> 160243: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
>>> 163230: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
>>> 26343: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC1E11combined_fn
>>> 40584: 0000000001fbc260    27 FUNC    WEAK   DEFAULT   14 _ZN11code_helperC2E11combined_fn
>>> 12547: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
>>> 165150: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC2IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
>>> 181147: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
>>> 26558: 00000000029516e0    68 FUNC    WEAK   DEFAULT   14 _ZNSt4pairIPSt18_Rb_tree_node_baseS1_EC1IRPSt13_Rb_tree_nodeIP15basic_block_defERS1_Lb1EEEOT_OT0_
>>> 8400: 0000000002e13f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_1
>>> 8448: 0000000002e14260    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
>>> 10166: 0000000002e444a0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL11ALL_GPR_ARGE
>>> 11568: 0000000002e51420    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512FP16
>>> 11735: 0000000002e52f60    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_VPCLMULQDQ
>>> 12575: 0000000002e5f560    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_ROCKETLAKE
>>> 165019: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
>>> 9991: 0000000002e605a0    20 OBJECT  GLOBAL DEFAULT   16 class_narrowest_mode
>>> 12749: 0000000002e60f60   160 OBJECT  LOCAL  DEFAULT   16 _ZL22extra_order_size_table
>>> 14715: 0000000002e7e340    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
>>> 15895: 0000000002e84480    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_UINTR
>>> 17084: 0000000002e8c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SAPPHIRERAPIDS
>>> 18397: 0000000002e946a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_SSE4_2
>>> 18986: 0000000002e97580    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
>>> 18990: 0000000002e975c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL17PTA_GOLDMONT_PLUS
>>> 22195: 0000000002eb1640    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_FMA
>>> 30065: 0000000002eed6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_AVX512BF16
>>> 31474: 0000000002ef3560     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
>>> 34906: 0000000002f02580    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512BW
>>> 37696: 0000000002f0e420     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
>>> 37701: 0000000002f0e484     4 OBJECT  LOCAL  DEFAULT   16 _ZL40LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES
>>> 38868: 0000000002f13420    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNL
>>> 39129: 0000000002f143c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_XSAVES
>>> 40610: 0000000002f1e7c0     1 OBJECT  LOCAL  DEFAULT   16 _ZStL19piecewise_construct
>>> 42157: 0000000002f293c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
>>> 42201: 0000000002f29680    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_SKYLAKE_AVX512
>>> 42207: 0000000002f296e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL18PTA_ICELAKE_SERVER
>>> 49618: 0000000002f556e0     4 OBJECT  LOCAL  DEFAULT   16 _ZN15zero_regs_flagsL8USED_ARGE
>>> 50904: 0000000002f5d4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_AVX
>>> 51188: 0000000002f5e6e0    48 OBJECT  LOCAL  DEFAULT   16 _ZN12_GLOBAL__N_1L17pass_data_tm_initE
>>> 56440: 0000000002f7d440    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
>>> 57404: 0000000002f81640     4 OBJECT  LOCAL  DEFAULT   16 _ZL14MAX_LOCATION_T
>>> 57424: 0000000002f816a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_64BIT
>>> 60100: 0000000002f903a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_TILE
>>> 67672: 0000000002fae460    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_COOPERLAKE
>>> 68780: 0000000002fb37c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AVX512CD
>>> 70316: 0000000002fbb4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_LWP
>>> 70637: 0000000002fbc7a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
>>> 70837: 0000000002fbd4e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
>>> 73878: 0000000002fcb960    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
>>> 79867: 00000000030435c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_SILVERMONT
>>> 81991: 0000000003053520    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_F16C
>>> 82244: 0000000003054500    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
>>> 86070: 00000000033ec560    99 OBJECT  LOCAL  DEFAULT   16 _ZL26znver1_agu_min_issue_delay
>>> 86071: 00000000033ec5e0  1334 OBJECT  LOCAL  DEFAULT   16 _ZL15geode_translate
>>> 86228: 00000000034419c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_NO_80387
>>> 94224: 0000000003849420    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
>>> 94230: 0000000003849480    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_XOP
>>> 94647: 000000000384aa40    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SGX
>>> 95488: 000000000384e4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_KNM
>>> 95820: 000000000384f6a0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_WBNOINVD
>>> 95822: 000000000384f6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
>>> 95824: 000000000384f6e0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_WAITPKG
>>> 96072: 0000000003850640    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_LZCNT
>>> 96074: 0000000003850660    16 OBJECT  LOCAL  DEFAULT   16 _ZL9PTA_MOVBE
>>> 96080: 00000000038506c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_SSE
>>> 98344: 000000000385a4c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_ENQCMD
>>> 99309: 000000000385da40    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_POPCNT
>>> 103332: 000000000386f2c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CLFLUSHOPT
>>> 103344: 000000000386f380    16 OBJECT  LOCAL  DEFAULT   16 _ZL7PTA_PKU
>>> 103352: 000000000386f400    16 OBJECT  LOCAL  DEFAULT   16 _ZL15PTA_AVX512VBMI2
>>> 103709: 0000000003870a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL8PTA_SSE3
>>> 104337: 0000000003873660    16 OBJECT  LOCAL  DEFAULT   16 _ZL10PTA_HRESET
>>> 106315: 000000000387d260    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_NO_TUNE
>>> 109183: 000000000388c160    16 OBJECT  LOCAL  DEFAULT   16 _ZL16PTA_AVX5124VNNIW
>>> 111159: 0000000003894a40    16 OBJECT  LOCAL  DEFAULT   16 _ZL14PTA_CANNONLAKE
>>> 112043: 00000000038994c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL11PTA_PTWRITE
>>> 112049: 0000000003899520    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_CLDEMOTE
>>> 113040: 000000000389d6c0    16 OBJECT  LOCAL  DEFAULT   16 _ZL12PTA_AMX_BF16
>>> 21876: 0000000003d8d5c0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
>>> 31109: 0000000003d8e100    40 OBJECT  LOCAL  DEFAULT   28 _ZL30unspecified_modref_access_node
>>> 78193: 0000000003d932e0    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
>>> 78366: 0000000003d93320    56 OBJECT  LOCAL  DEFAULT   28 _ZL22mem_alloc_origin_names
>>> 
>>>      Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH 0/4] config: Allow a host to opt out of PCH.
  2021-11-05 16:37         ` Iain Sandoe
  2021-11-08  7:16           ` Richard Biener
@ 2021-11-08 11:46           ` Jakub Jelinek
  2021-11-08 19:48             ` [PATCH] pch: Add support for PCH for relocatable executables Jakub Jelinek
  1 sibling, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-08 11:46 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: Richard Biener, GCC Patches

On Fri, Nov 05, 2021 at 04:37:09PM +0000, Iain Sandoe wrote:
> It is hard to judge the relative effort in the two immediately visible solutions:
> 
> 1. relocatable PCH
> 2. taking the tree streamer from the modules implementation, moving its home
>     to c-family and adding hooks so that each FE can stream its own special trees.
> 
> ISTM, that part of the reason people dislike PCH is because the implementation is
> mixed up with the GC solution - the rendering is non-transparent etc.
> 
> So, in some ways, (2) above would be a better investment - the process of PCH is:
> generate:
> “get to the end of parsing a TU” .. stream the AST
> consume:
> .. see a header .. stream the PCH AST in if there is one available for the header.
> 
> There is no reason for this to be mixed into the GC solution - the read in (currently)
> happens to an empty TU and there should be nothing in the AST that carries any
> reference to the compiler’s executable.

I'm afraid (2) is much more work though even just for C++, because handling
just modules streaming and arbitrary headers is quite different.

Anyway, I've rebuilt my cc1plus as PIE (and am invoking it under gdb wrapper which
has ASLR disabled when building x86_64-pc-linux-gnu/bits/stdc++.h.gch/O2g.gch).
With the hack patch I've posted earlier, the results are much shorter than
before, in particular those scalar at messages only for ovl_op_info array
and then
object 0x7fffe9f6b3c0 at 0x7fffe9f6b3c8 points to executable 0x555556a2a180
object 0x7fffe9f6b3c0 at 0x7fffe9f6b3d0 points to executable 0x55555772f9b9
object 0x7fffe9f6b3a0 at 0x7fffe9f6b3a8 points to executable 0x555556a2a180
object 0x7fffe9f6b3a0 at 0x7fffe9f6b3b0 points to executable 0x55555767da08
object 0x7fffe9f6b400 at 0x7fffe9f6b408 points to executable 0x555556a2a180
object 0x7fffe9f6b400 at 0x7fffe9f6b410 points to executable 0x55555772f9d2
object 0x7fffe9f6b480 at 0x7fffe9f6b488 points to executable 0x555556a306d0
object 0x7fffe9f6b3e0 at 0x7fffe9f6b3e8 points to executable 0x555556a2a180
object 0x7fffe9f6b3e0 at 0x7fffe9f6b3f0 points to executable 0x55555772f9c0
object 0x7fffe9f6b420 at 0x7fffe9f6b428 points to executable 0x555556a2b880
object 0x7fffe9f6b440 at 0x7fffe9f6b448 points to executable 0x555556a2b7a0
object 0x7fffe9f6b460 at 0x7fffe9f6b468 points to executable 0x555556a30710
object 0x7fffe9f79168 at 0x7fffe9f791d8 points to executable 0x5555576832b9
object 0x7ffff7fca000 at 0x7ffff7fca048 points to executable 0x55555670b7d0
object 0x7ffff7fca000 at 0x7ffff7fca050 points to executable 0x5555561eb040
If I look at the unique addresses in the last column after subtracing my
PIE base of 0x555555554000, they are:
0000000c97040	_Z20ggc_round_alloc_sizem
00000011b77d0	_ZL20realloc_for_line_mapPvm
00000014d6180	_Z21output_section_asm_opPKv
00000014d77a0	_ZL10emit_localP9tree_nodePKcmm
00000014d7880	_ZL15emit_tls_commonP9tree_nodePKcmm
00000014dc6d0	_ZL8emit_bssP9tree_nodePKcmm
00000014dc710	_ZL11emit_commonP9tree_nodePKcmm
0000002129a08	"\t.text"
000000212f2b9	"GNU C++17"
00000021db9b9	"\t.data"
00000021db9c0	"\t.section"
00000021db9d2	"\t.bss"

For ovl_op_info array, I've mentioned that the array has:
struct GTY(()) ovl_op_info_t {
  tree identifier;
  const char *name;
  const char *mangled_name;
  // And a bunch of scalar members.
};
and while .name and .mangled_name are initially initialized to
NULL or string literals, init_operators then (at least in my understanding
not based on any command line switches and therefore probably always the
same way) reorders some of the elements plus creates those identifier trees.
I said I didn't know what exactly PCH does with const char * or char *
members.  Looking in more detail, gt_ggc_m_S clearly supports:
1) NULL
2) non-GC addresses (so most likely const literals):
  /* Look up the page on which the object is alloced.  If it was not
     GC allocated, gracefully bail out.  */
  entry = safe_lookup_page_table_entry (p);
  if (!entry)
    return;
3) GC addresses not pointing to start of objects - here it assumes
   it points to STRING_CST payload and marks the STRING_CST
4) GC addresses which are starts of objects
And then as can be seen in gt_pch_note_object during PCH, it only
has an exception for NULL and (void *) 1, otherwise for gt_pch_p_S
it remembers the pointer and uses strlen (pointer) + 1 to determine
the size.  While I haven't verified it yet, my understanding is that
if PCH save is done and some GC object or e.g. that
ovl_op_info[?][?].{,mangled_}name points to a .rodata string literal
that when the PCH is saved, we actually make the .gch file not point
it to the string literal in .rodata, but allocate in GC that string
literal and so when PCH is loaded, they will point to some GC allocated
memory containing a copy of that string literal.
So, in theory ovl_op_info would be fine, my printout happens for
scalars when saving the scalar data, but after that we do
write_pch_globals and we have:
  {
    &ovl_op_info[0][0].identifier,
    1 * (2) * (OVL_OP_MAX),
    sizeof (ovl_op_info[0][0]),
    &gt_ggc_mx_tree_node,
    &gt_pch_nx_tree_node
  },
  {
    &ovl_op_info[0][0].name,
    1 * (2) * (OVL_OP_MAX),
    sizeof (ovl_op_info[0][0]),
    (gt_pointer_walker) &gt_ggc_m_S,
    (gt_pointer_walker) &gt_pch_n_S
  },
  {
    &ovl_op_info[0][0].mangled_name,
    1 * (2) * (OVL_OP_MAX),
    sizeof (ovl_op_info[0][0]),
    (gt_pointer_walker) &gt_ggc_m_S,
    (gt_pointer_walker) &gt_pch_n_S
  },
registered which after restoring those overwrites those 3 members
with something different (for the latter two with those pointers
to GC allocated copies of the string literals).
Sure, we could move the ovl_op_info[?][?].identifier out of
the structure to another array, which would be GTY marked and this
one wouldn't, or name and mangled_name could be changed from const char *
to char [10] and char [12] arrays.

Now, looking at the fortunately just very few other pointers into the
PIE.
We clearly have:
typedef bool (*noswitch_section_callback) (tree decl, const char *name,
                                           unsigned HOST_WIDE_INT size,
                                           unsigned HOST_WIDE_INT rounded);
struct GTY(()) noswitch_section {
  struct section_common common;
  noswitch_section_callback GTY ((skip)) callback;
};
which covers
00000014d77a0   _ZL10emit_localP9tree_nodePKcmm
00000014d7880   _ZL15emit_tls_commonP9tree_nodePKcmm
00000014dc6d0   _ZL8emit_bssP9tree_nodePKcmm
00000014dc710   _ZL11emit_commonP9tree_nodePKcmm
typedef void *(*line_map_realloc) (void *, size_t);
typedef size_t (*line_map_round_alloc_size_func) (size_t);
class GTY(()) line_maps {
...
  line_map_realloc reallocator;
  line_map_round_alloc_size_func round_alloc_size;
...
};
which covers
0000000c97040   _Z20ggc_round_alloc_sizem
00000011b77d0   _ZL20realloc_for_line_mapPvm
typedef void (*unnamed_section_callback) (const void *);
struct GTY(()) unnamed_section {
  struct section_common common;
  unnamed_section_callback GTY ((skip)) callback;
  const void *GTY ((skip)) data;
  section *next;
};
which covers
00000014d6180   _Z21output_section_asm_opPKv
For the strings, I wonder about
struct GTY(()) tree_translation_unit_decl {
  struct tree_decl_common common;
  const char * GTY((skip(""))) language;
};
(whether we don't want to drop that GTY((skip(""))) stuff.
And the remaining one is again above, the data pointers
passed to get_unnnamed_section.

So, if we want to make PCH work for PIEs, I'd say we can:
1) add a new GTY option, say callback, which would act like
   skip for non-PCH and for PCH would make us skip it but
   remember for address bias translation
2) drop the skip for tree_translation_unit_decl::language
3) change get_unnamed_section to have const char * as
   last argument instead of const void *, change
   unnamed_section::data also to const char * and update
   everything related to that
4) maybe add a host hook whether it is ok to support binaries
   changing addresses (the only thing I'm worried is if
   some host that uses function descriptors allocates them
   dynamically instead of having them somewhere in the
   executable)
5) maybe add a gengtype warning if it sees in GTY tracked
   structure a function pointer without that new callback
   option

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-08 11:46           ` Jakub Jelinek
@ 2021-11-08 19:48             ` Jakub Jelinek
  2021-11-08 21:03               ` John David Anglin
                                 ` (2 more replies)
  0 siblings, 3 replies; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-08 19:48 UTC (permalink / raw)
  To: Iain Sandoe, Richard Biener
  Cc: gcc-patches, John David Anglin, Aldy Hernandez, Andrew MacLeod

[-- Attachment #1: Type: text/plain, Size: 28849 bytes --]

On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
> So, if we want to make PCH work for PIEs, I'd say we can:
> 1) add a new GTY option, say callback, which would act like
>    skip for non-PCH and for PCH would make us skip it but
>    remember for address bias translation
> 2) drop the skip for tree_translation_unit_decl::language
> 3) change get_unnamed_section to have const char * as
>    last argument instead of const void *, change
>    unnamed_section::data also to const char * and update
>    everything related to that
> 4) maybe add a host hook whether it is ok to support binaries
>    changing addresses (the only thing I'm worried is if
>    some host that uses function descriptors allocates them
>    dynamically instead of having them somewhere in the
>    executable)
> 5) maybe add a gengtype warning if it sees in GTY tracked
>    structure a function pointer without that new callback
>    option

So, here is 1), 2), 3) implemented.  With this patch alone,
g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
function::x_range_query member, which is set to &global_ranges on
cfun creation and is:
  range_query * GTY ((skip)) x_range_query;
which means when a PIE binary writes PCH and a PIE binary loaded
at a different address loads it, cfun->x_range_query might be a garbage
pointer.  We can either apply a patch like the attached one after
this inline patch, but then probably callback is misnamed and we should
rename it to relocate_and_skip or something similar.  Or we could
e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.

Not really sure about PA or IA-64 function descriptors, are any of those
allocated by the dynamic linker rather than created by the static linker?
I guess instead of removing the c-pch.c changes we could remember there
not just a function pointer, but also a data pointer and compare if both
are either the same or have the same load bias and punt only if they
have different bias.  Though, on architecture where all function pointers
would be dynamically allocated and could change any time even that wouldn't
be really a reliable check.

Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
the second patch, with it a few more, but nothing huge.  And for non-PIEs
there isn't really any extra work on the load side except freading two scalar
values and fseek.

Thoughts on this?

2021-11-08  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* ggc.h (gt_pch_note_callback): Declare.
	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
	(callback_type): Declare.
	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
	(callback_type): New variable.
	(process_gc_options): Add CALLBACK argument, handle callback
	option.
	(set_gc_used_type): Adjust process_gc_options caller, if callback,
	set type to &callback_type.
	(output_mangled_typename): Handle TYPE_CALLBACK.
	(walk_type): Likewise.  Handle callback option.
	(write_types_process_field): Handle TYPE_CALLBACK.
	(write_types_local_user_process_field): Likewise.
	(write_types_local_process_field): Likewise.
	(write_root): Likewise.
	(dump_typekind): Likewise.
	(dump_type): Likewise.
	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
	(state_writer::write_state_callback_type): New method.
	(state_writer::write_state_type): Handle TYPE_CALLBACK.
	(read_state_callback_type): New function.
	(read_state_type): Handle TYPE_CALLBACK.
	* ggc-common.c (callback_vec): New variable.
	(gt_pch_note_callback): New function.
	(gt_pch_save): Stream out gt_pch_save function address and relocation
	table.
	(gt_pch_restore): Stream in saved gt_pch_save function address and
	relocation table and apply relocations if needed.
	* doc/gty.texi (callback): Document new GTY option.
	* varasm.c (get_unnamed_section): Change callback argument's type and
	last argument's type from const void * to const char *.
	(output_section_asm_op): Change argument's type from const void *
	to const char *, remove unnecessary cast.
	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
	from language member.
	* output.h (unnamed_section_callback): Change argument type from
	const void * to const char *.
	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
	for callback member.  Change data member type from const void *
	to const char *.
	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
	for callback member.
	(get_unnamed_section): Change callback argument's type and
	last argument's type from const void * to const char *.
	(output_section_asm_op): Change argument's type from const void *
	to const char *.
	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
	Remove unneeded cast.
	* config/darwin.c (output_objc_section_asm_op): Change argument's type
	from const void * to const char *.
	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
	(som_output_comdat_data_section_asm_op): Likewise.
	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
	Likewise.
	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
	of dereferencing directive hardcode variable names and decide based on
	whether directive is NULL or not.
	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
	from const void * to const char *.
	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
	of dereferencing directive hardcode variable names and decide based on
	whether directive is NULL or not.
	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
	from const void * to const char *.
	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
gcc/c-family/
	* c-pch.c (struct c_pch_validity): Remove pch_init member.
	(pch_init): Don't initialize v.pch_init.
	(c_common_valid_pch): Don't warn and punt if .text addresses change.
libcpp/
	* include/line-map.h (class line_maps): Add GTY((callback)) to
	reallocator and round_alloc_size members.

--- gcc/ggc.h.jj	2021-08-19 11:42:27.366422386 +0200
+++ gcc/ggc.h	2021-11-08 16:46:02.604618109 +0100
@@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void
 /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
 extern int gt_pch_note_object (void *, void *, gt_note_pointers);
 
+/* Used by the gt_pch_p_* routines.  Register address of a callback
+   pointer.  */
+extern void gt_pch_note_callback (void *, void *);
+
 /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
    function.  */
 extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
--- gcc/gengtype.h.jj	2021-07-20 10:08:09.892687719 +0200
+++ gcc/gengtype.h	2021-11-08 15:19:59.194210185 +0100
@@ -154,6 +154,9 @@ enum typekind {
   TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
   TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
   TYPE_ARRAY,           /* Array of GTY-ed types.  */
+  TYPE_CALLBACK,	/* A function pointer that needs relocation if
+			   the executable has been loaded at a different
+			   address.  */
   TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
                            Various languages may have homonymous but
                            different structs.  */
@@ -331,6 +334,9 @@ extern struct type string_type;
 extern struct type scalar_nonchar;
 extern struct type scalar_char;
 
+/* The one and only TYPE_CALLBACK.  */
+extern struct type callback_type;
+
 /* Test if a type is a union, either a plain one or a language
    specific one.  */
 #define UNION_P(x)					\
--- gcc/gengtype.c.jj	2021-10-04 10:16:10.885140187 +0200
+++ gcc/gengtype.c	2021-11-08 16:30:41.981750183 +0100
@@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil,
   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
   int nb_lang_struct = 0;
   int nb_user_struct = 0, nb_undefined = 0;
+  int nb_callback = 0;
   type_p p = NULL;
   for (p = t; p; p = p->next)
     {
@@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil,
 	case TYPE_ARRAY:
 	  nb_array++;
 	  break;
+	case TYPE_CALLBACK:
+	  nb_callback++;
+	  break;
 	case TYPE_LANG_STRUCT:
 	  nb_lang_struct++;
 	  break;
@@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil,
     fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
   if (nb_pointer > 0 || nb_array > 0)
     fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
+  if (nb_callback > 0)
+    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
   if (nb_lang_struct > 0)
     fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
   if (nb_user_struct > 0)
@@ -495,6 +501,10 @@ struct type scalar_char = {
   TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
 };
 
+struct type callback_type = {
+  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
+};
+
 /* Lists of various things.  */
 
 pair_p typedefs = NULL;
@@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
 
 static void
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
-		    int *length, int *skip, type_p *nested_ptr)
+		    int *length, int *skip, int *callback, type_p *nested_ptr)
 {
   options_p o;
   for (o = opt; o; o = o->next)
@@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum
       *length = 1;
     else if (strcmp (o->name, "skip") == 0)
       *skip = 1;
+    else if (strcmp (o->name, "callback") == 0)
+      *callback = 1;
     else if (strcmp (o->name, "nested_ptr") == 0
 	     && o->kind == OPTION_NESTED)
       *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
@@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used
 	type_p dummy2;
 	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
 
-	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
+	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
 			    &dummy2);
 
 	if (t->u.s.base_class)
@@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used
 	    int maybe_undef = 0;
 	    int length = 0;
 	    int skip = 0;
+	    int callback = 0;
 	    type_p nested_ptr = NULL;
 	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
-				&nested_ptr);
+				&callback, &nested_ptr);
 
 	    if (nested_ptr && f->type->kind == TYPE_POINTER)
 	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
@@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used
 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
 	    else if (skip)
 	      ;			/* target type is not used through this field */
+	    else if (callback)
+	      f->type = &callback_type;
 	    else
 	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
 	  }
@@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, cons
       {
       case TYPE_NONE:
       case TYPE_UNDEFINED:
+      case TYPE_CALLBACK:
 	gcc_unreachable ();
 	break;
       case TYPE_POINTER:
@@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_da
       ;
     else if (strcmp (oo->name, "for_user") == 0)
       ;
+    else if (strcmp (oo->name, "callback") == 0)
+      ;
     else
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
 
@@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_da
     {
     case TYPE_SCALAR:
     case TYPE_STRING:
+    case TYPE_CALLBACK:
       d->process_field (t, d);
       break;
 
@@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, con
       break;
 
     case TYPE_SCALAR:
+    case TYPE_CALLBACK:
       break;
 
     case TYPE_ARRAY:
@@ -3820,6 +3840,7 @@ write_types_local_user_process_field (ty
       break;
 
     case TYPE_SCALAR:
+    case TYPE_CALLBACK:
       break;
 
     case TYPE_ARRAY:
@@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p
     case TYPE_SCALAR:
       break;
 
+    case TYPE_CALLBACK:
+      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
+	       d->prev_val[3]);
+      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
+	       d->indent, "", d->val);
+      break;
+
     case TYPE_ARRAY:
     case TYPE_NONE:
     case TYPE_UNDEFINED:
@@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p t
     case TYPE_UNDEFINED:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
+    case TYPE_CALLBACK:
       error_at_line (line, "global `%s' is unimplemented type", name);
     }
 }
@@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind
     case TYPE_ARRAY:
       printf ("TYPE_ARRAY");
       break;
+    case TYPE_CALLBACK:
+      printf ("TYPE_CALLBACK");
+      break;
     case TYPE_LANG_STRUCT:
       printf ("TYPE_LANG_STRUCT");
       break;
@@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
 	      t->u.scalar_is_char ? "true" : "false");
       break;
     case TYPE_STRING:
+    case TYPE_CALLBACK:
       break;
     case TYPE_STRUCT:
     case TYPE_UNION:
--- gcc/varasm.c.jj	2021-09-28 11:34:29.343147261 +0200
+++ gcc/varasm.c	2021-11-08 13:26:15.032606040 +0100
@@ -250,8 +250,8 @@ object_block_hasher::hash (object_block
 /* Return a new unnamed section with the given fields.  */
 
 section *
-get_unnamed_section (unsigned int flags, void (*callback) (const void *),
-		     const void *data)
+get_unnamed_section (unsigned int flags, void (*callback) (const char *),
+		     const char *data)
 {
   section *sect;
 
@@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
    a get_unnamed_section callback.  */
 
 void
-output_section_asm_op (const void *directive)
+output_section_asm_op (const char *directive)
 {
-  fprintf (asm_out_file, "%s\n", (const char *) directive);
+  fprintf (asm_out_file, "%s\n", directive);
 }
 
 /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
--- gcc/ggc-common.c.jj	2021-11-08 11:09:50.280318624 +0100
+++ gcc/ggc-common.c	2021-11-08 18:33:51.103390391 +0100
@@ -246,6 +246,7 @@ saving_hasher::equal (const ptr_data *p1
 }
 
 static hash_table<saving_hasher> *saving_htab;
+static vec<void *> callback_vec;
 
 /* Register an object in the hash table.  */
 
@@ -278,6 +279,23 @@ gt_pch_note_object (void *obj, void *not
   return 1;
 }
 
+/* Register address of a callback pointer.  */
+void
+gt_pch_note_callback (void *obj, void *base)
+{
+  void *ptr;
+  memcpy (&ptr, obj, sizeof (void *));
+  if (ptr != NULL)
+    {
+      struct ptr_data *data
+	= (struct ptr_data *)
+	  saving_htab->find_with_hash (base, POINTER_HASH (base));
+      gcc_assert (data);
+      callback_vec.safe_push ((char *) data->new_addr
+			      + ((char *) obj - (char *) base));
+    }
+}
+
 /* Register an object in the hash table.  */
 
 void
@@ -592,10 +610,20 @@ gt_pch_save (FILE *f)
   ggc_pch_finish (state.d, state.f);
   gt_pch_fixup_stringpool ();
 
+  unsigned num_callbacks = callback_vec.length ();
+  void (*pch_save) (FILE *) = &gt_pch_save;
+  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
+      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
+      || (num_callbacks
+	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
+		     f) != num_callbacks))
+    fatal_error (input_location, "cannot write PCH file: %m");
+
   XDELETE (state.ptrs);
   XDELETE (this_object);
   delete saving_htab;
   saving_htab = NULL;
+  callback_vec.release ();
 }
 
 /* Read the state of the compiler back in from F.  */
@@ -649,6 +677,30 @@ gt_pch_restore (FILE *f)
   ggc_pch_read (f, mmi.preferred_base);
 
   gt_pch_restore_stringpool ();
+
+  void (*pch_save) (FILE *);
+  unsigned num_callbacks;
+  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
+      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
+    fatal_error (input_location, "cannot read PCH file: %m");
+  if (pch_save != &gt_pch_save)
+    {
+      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
+      void **ptrs = XNEWVEC (void *, num_callbacks);
+      unsigned i;
+
+      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
+	fatal_error (input_location, "cannot read PCH file: %m");
+      for (i = 0; i < num_callbacks; ++i)
+	{
+	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
+	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
+	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
+	}
+      XDELETE (ptrs);
+    }
+  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
+    fatal_error (input_location, "cannot read PCH file: %m");
 }
 
 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
--- gcc/doc/gty.texi.jj	2021-08-19 11:42:27.363422428 +0200
+++ gcc/doc/gty.texi	2021-11-08 17:13:46.613882767 +0100
@@ -197,6 +197,15 @@ If @code{skip} is applied to a field, th
 This is somewhat dangerous; the only safe use is in a union when one
 field really isn't ever used.
 
+@findex callback
+@item callback
+
+@code{callback} should be applied to fields with pointer to function type
+and causes the field to be ignored similarly to @code{skip}, except when
+writing PCH and the field is non-NULL it will remember the field's address
+for relocation purposes if the process writing PCH has different load base
+from a process reading PCH.
+
 @findex for_user
 @item for_user
 
--- gcc/tree-core.h.jj	2021-11-04 12:27:02.377298411 +0100
+++ gcc/tree-core.h	2021-11-08 13:24:04.496465555 +0100
@@ -1964,7 +1964,7 @@ struct GTY(()) tree_function_decl {
 struct GTY(()) tree_translation_unit_decl {
   struct tree_decl_common common;
   /* Source language of this translation unit.  Used for DWARF output.  */
-  const char * GTY((skip(""))) language;
+  const char *language;
   /* TODO: Non-optimization used to build this translation unit.  */
   /* TODO: Root of a partial DWARF tree for global types and decls.  */
 };
--- gcc/gengtype-state.c.jj	2021-07-20 10:08:09.891687732 +0200
+++ gcc/gengtype-state.c	2021-11-08 15:19:16.157824146 +0100
@@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
     case TYPE_STRING:
     case TYPE_POINTER:
     case TYPE_ARRAY:
+    case TYPE_CALLBACK:
       return NULL;
     default:
       gcc_unreachable ();
@@ -171,6 +172,7 @@ private:
   void write_state_version (const char *version);
   void write_state_scalar_type (type_p current);
   void write_state_string_type (type_p current);
+  void write_state_callback_type (type_p current);
   void write_state_undefined_type (type_p current);
   void write_state_struct_union_type (type_p current, const char *kindstr);
   void write_state_struct_type (type_p current);
@@ -898,6 +900,20 @@ state_writer::write_state_string_type (t
     fatal ("Unexpected type in write_state_string_type");
 }
 
+/* Write the callback type.  There is only one such thing! */
+void
+state_writer::write_state_callback_type (type_p current)
+{
+  if (current == &callback_type)
+    {
+      write_any_indent (0);
+      fprintf (state_file, "callback ");
+      write_state_common_type_content (current);
+    }
+  else
+    fatal ("Unexpected type in write_state_callback_type");
+}
+
 /* Write an undefined type.  */
 void
 state_writer::write_state_undefined_type (type_p current)
@@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p c
 	case TYPE_STRING:
 	  write_state_string_type (current);
 	  break;
+	case TYPE_CALLBACK:
+	  write_state_callback_type (current);
+	  break;
 	}
     }
 
@@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
   read_state_common_type_content (*type);
 }
 
+/* Read the callback_type.  */
+static void
+read_state_callback_type (type_p *type)
+{
+  *type = &callback_type;
+  read_state_common_type_content (*type);
+}
+
 
 /* Read a lang_bitmap representing a set of GCC front-end languages.  */
 static void
@@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
 	      next_state_tokens (1);
 	      read_state_string_type (current);
 	    }
+	  else if (state_token_is_name (t0, "callback"))
+	    {
+	      next_state_tokens (1);
+	      read_state_callback_type (current);
+	    }
 	  else if (state_token_is_name (t0, "undefined"))
 	    {
 	      *current = XCNEW (struct type);
--- gcc/output.h.jj	2021-09-28 11:34:29.235148754 +0200
+++ gcc/output.h	2021-11-08 16:26:01.172755377 +0100
@@ -470,7 +470,7 @@ struct GTY(()) named_section {
 
 /* A callback that writes the assembly code for switching to an unnamed
    section.  The argument provides callback-specific data.  */
-typedef void (*unnamed_section_callback) (const void *);
+typedef void (*unnamed_section_callback) (const char *);
 
 /* Information about a SECTION_UNNAMED section.  */
 struct GTY(()) unnamed_section {
@@ -478,8 +478,8 @@ struct GTY(()) unnamed_section {
 
   /* The callback used to switch to the section, and the data that
      should be passed to the callback.  */
-  unnamed_section_callback GTY ((skip)) callback;
-  const void *GTY ((skip)) data;
+  unnamed_section_callback GTY ((callback)) callback;
+  const char *data;
 
   /* The next entry in the chain of unnamed sections.  */
   section *next;
@@ -503,7 +503,7 @@ struct GTY(()) noswitch_section {
   struct section_common common;
 
   /* The callback used to assemble decls in this section.  */
-  noswitch_section_callback GTY ((skip)) callback;
+  noswitch_section_callback GTY ((callback)) callback;
 };
 
 /* Information about a section, which may be named or unnamed.  */
@@ -538,8 +538,8 @@ extern GTY(()) section *bss_noswitch_sec
 extern GTY(()) section *in_section;
 extern GTY(()) bool in_cold_section_p;
 
-extern section *get_unnamed_section (unsigned int, void (*) (const void *),
-				     const void *);
+extern section *get_unnamed_section (unsigned int, void (*) (const char *),
+				     const char *);
 extern section *get_section (const char *, unsigned int, tree,
 			     bool not_existing = false);
 extern section *get_named_section (tree, const char *, int);
@@ -561,7 +561,7 @@ extern section *get_cdtor_priority_secti
 
 extern bool unlikely_text_section_p (section *);
 extern void switch_to_section (section *, tree = nullptr);
-extern void output_section_asm_op (const void *);
+extern void output_section_asm_op (const char *);
 
 extern void record_tm_clone_pair (tree, tree);
 extern void finish_tm_clone_pairs (void);
--- gcc/config/avr/avr.c.jj	2021-07-15 10:16:12.873583249 +0200
+++ gcc/config/avr/avr.c	2021-11-08 13:28:30.215676387 +0100
@@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const voi
 /* Unnamed section callback for progmem*.data sections.  */
 
 static void
-avr_output_progmem_section_asm_op (const void *data)
+avr_output_progmem_section_asm_op (const char *data)
 {
-  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
-           (const char*) data);
+  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
 }
 
 
--- gcc/config/darwin.c.jj	2021-10-21 10:23:27.450834602 +0200
+++ gcc/config/darwin.c	2021-11-08 13:27:19.106691421 +0100
@@ -134,7 +134,7 @@ int emit_aligned_common = false;
    DIRECTIVE is as for output_section_asm_op.  */
 
 static void
-output_objc_section_asm_op (const void *directive)
+output_objc_section_asm_op (const char *directive)
 {
   static bool been_here = false;
 
--- gcc/config/pa/pa.c.jj	2021-10-27 09:00:28.762277456 +0200
+++ gcc/config/pa/pa.c	2021-11-08 13:29:41.935652629 +0100
@@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t
    to the default text subspace.  */
 
 static void
-som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
 {
   gcc_assert (TARGET_SOM);
   if (TARGET_GAS)
@@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const vo
    sections.  This function is only used with SOM.  */
 
 static void
-som_output_comdat_data_section_asm_op (const void *data)
+som_output_comdat_data_section_asm_op (const char *data)
 {
   in_section = NULL;
   output_section_asm_op (data);
--- gcc/config/rs6000/rs6000.c.jj	2021-11-05 00:43:22.476626062 +0100
+++ gcc/config/rs6000/rs6000.c	2021-11-08 13:43:22.415940789 +0100
@@ -20597,7 +20597,7 @@ rs6000_ms_bitfield_layout_p (const_tree
 /* A get_unnamed_section callback, used for switching to toc_section.  */
 
 static void
-rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
 {
   if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
       && TARGET_MINIMAL_TOC)
@@ -21301,35 +21301,39 @@ rs6000_xcoff_asm_globalize_label (FILE *
    points to the section string variable.  */
 
 static void
-rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
+rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
 {
   fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
-	   *(const char *const *) directive,
+	   directive
+	   ? xcoff_private_rodata_section_name
+	   : xcoff_read_only_section_name,
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 /* Likewise for read-write sections.  */
 
 static void
-rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
+rs6000_xcoff_output_readwrite_section_asm_op (const char *)
 {
   fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
-	   *(const char *const *) directive,
+	   xcoff_private_data_section_name,
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 static void
-rs6000_xcoff_output_tls_section_asm_op (const void *directive)
+rs6000_xcoff_output_tls_section_asm_op (const char *directive)
 {
   fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
-	   *(const char *const *) directive,
+	   directive
+	   ? xcoff_private_data_section_name
+	   : xcoff_tls_data_section_name,
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 /* A get_unnamed_section callback, used for switching to toc_section.  */
 
 static void
-rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
 {
   if (TARGET_MINIMAL_TOC)
     {
@@ -21356,26 +21360,26 @@ rs6000_xcoff_asm_init_sections (void)
 {
   read_only_data_section
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
-			   &xcoff_read_only_section_name);
+			   NULL);
 
   private_data_section
     = get_unnamed_section (SECTION_WRITE,
 			   rs6000_xcoff_output_readwrite_section_asm_op,
-			   &xcoff_private_data_section_name);
+			   NULL);
 
   read_only_private_data_section
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
-			   &xcoff_private_rodata_section_name);
+			   "");
 
   tls_data_section
     = get_unnamed_section (SECTION_TLS,
 			   rs6000_xcoff_output_tls_section_asm_op,
-			   &xcoff_tls_data_section_name);
+			   NULL);
 
   tls_private_data_section
     = get_unnamed_section (SECTION_TLS,
 			   rs6000_xcoff_output_tls_section_asm_op,
-			   &xcoff_private_data_section_name);
+			   "");
 
   toc_section
     = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
--- gcc/c-family/c-pch.c.jj	2021-06-02 10:08:14.149450407 +0200
+++ gcc/c-family/c-pch.c	2021-11-08 17:34:17.302343697 +0100
@@ -54,7 +54,6 @@ struct c_pch_validity
 {
   uint32_t pch_write_symbols;
   signed char match[MATCH_SIZE];
-  void (*pch_init) (void);
   size_t target_data_length;
 };
 
@@ -117,7 +116,6 @@ pch_init (void)
 	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
       }
   }
-  v.pch_init = &pch_init;
   target_validity = targetm.get_pch_validity (&v.target_data_length);
 
   if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
@@ -278,19 +276,6 @@ c_common_valid_pch (cpp_reader *pfile, c
 	}
   }
 
-  /* If the text segment was not loaded at the same address as it was
-     when the PCH file was created, function pointers loaded from the
-     PCH will not be valid.  We could in theory remap all the function
-     pointers, but no support for that exists at present.
-     Since we have the same executable, it should only be necessary to
-     check one function.  */
-  if (v.pch_init != &pch_init)
-    {
-      cpp_warning (pfile, CPP_W_INVALID_PCH,
-		   "%s: had text segment at different address", name);
-      return 2;
-    }
-
   /* Check the target-specific validity data.  */
   {
     void *this_file_data = xmalloc (v.target_data_length);
--- libcpp/include/line-map.h.jj	2021-11-01 14:37:06.697853154 +0100
+++ libcpp/include/line-map.h	2021-11-08 16:16:34.562837006 +0100
@@ -803,11 +803,11 @@ public:
   unsigned int max_column_hint;
 
   /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
-  line_map_realloc reallocator;
+  line_map_realloc GTY((callback)) reallocator;
 
   /* The allocators' function used to know the actual size it
      allocated, for a certain allocation size requested.  */
-  line_map_round_alloc_size_func round_alloc_size;
+  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
 
   struct location_adhoc_data_map location_adhoc_data_map;
 


	Jakub

[-- Attachment #2: R156a --]
[-- Type: text/plain, Size: 502 bytes --]

--- gcc/function.h.jj	2021-09-01 11:37:41.953556518 +0200
+++ gcc/function.h	2021-11-08 19:41:23.884577455 +0100
@@ -314,7 +314,7 @@ struct GTY(()) function {
      global ranges.  If a pass wants on-demand ranges OTOH, it must
      call enable/disable_ranger().  The pointer is never null.  It
      should be queried by calling get_range_query().  */
-  range_query * GTY ((skip)) x_range_query;
+  range_query * GTY ((callback)) x_range_query;
 
   /* Last statement uid.  */
   int last_stmt_uid;

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-08 19:48             ` [PATCH] pch: Add support for PCH for relocatable executables Jakub Jelinek
@ 2021-11-08 21:03               ` John David Anglin
  2021-11-09  9:50                 ` Jakub Jelinek
  2021-11-09  7:12               ` Richard Biener
  2021-11-18  8:04               ` [PATCH] pch, v2: Add support for PCH for relocatable executables Jakub Jelinek
  2 siblings, 1 reply; 39+ messages in thread
From: John David Anglin @ 2021-11-08 21:03 UTC (permalink / raw)
  To: Jakub Jelinek, Iain Sandoe, Richard Biener
  Cc: gcc-patches, Aldy Hernandez, Andrew MacLeod

On 2021-11-08 2:48 p.m., Jakub Jelinek wrote:
> Not really sure about PA or IA-64 function descriptors, are any of those
> allocated by the dynamic linker rather than created by the static linker?
On PA, the static linker creates all function descriptors.  The dynamic linker is responsible for
resolving descriptors when lazy binding is used.

The primary difference between 32 and 64-bit descriptors is that there can be multiple descriptors
that resolve to the same function in the 32-bit run time.  In the 64-bit case, there is one official
procedure descriptor for each function.
> I guess instead of removing the c-pch.c changes we could remember there
> not just a function pointer, but also a data pointer and compare if both
> are either the same or have the same load bias and punt only if they
> have different bias.  Though, on architecture where all function pointers
> would be dynamically allocated and could change any time even that wouldn't
> be really a reliable check.
There is no call to dynamically allocate a descriptor but it is possible for code to dynamically build a descriptor.

Dave

-- 
John David Anglin  dave.anglin@bell.net


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-08 19:48             ` [PATCH] pch: Add support for PCH for relocatable executables Jakub Jelinek
  2021-11-08 21:03               ` John David Anglin
@ 2021-11-09  7:12               ` Richard Biener
  2021-11-09  8:07                 ` Iain Sandoe
  2021-11-09  9:44                 ` Jakub Jelinek
  2021-11-18  8:04               ` [PATCH] pch, v2: Add support for PCH for relocatable executables Jakub Jelinek
  2 siblings, 2 replies; 39+ messages in thread
From: Richard Biener @ 2021-11-09  7:12 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Iain Sandoe, gcc-patches, John David Anglin, Aldy Hernandez,
	Andrew MacLeod

On Mon, 8 Nov 2021, Jakub Jelinek wrote:

> On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
> > So, if we want to make PCH work for PIEs, I'd say we can:
> > 1) add a new GTY option, say callback, which would act like
> >    skip for non-PCH and for PCH would make us skip it but
> >    remember for address bias translation
> > 2) drop the skip for tree_translation_unit_decl::language
> > 3) change get_unnamed_section to have const char * as
> >    last argument instead of const void *, change
> >    unnamed_section::data also to const char * and update
> >    everything related to that
> > 4) maybe add a host hook whether it is ok to support binaries
> >    changing addresses (the only thing I'm worried is if
> >    some host that uses function descriptors allocates them
> >    dynamically instead of having them somewhere in the
> >    executable)
> > 5) maybe add a gengtype warning if it sees in GTY tracked
> >    structure a function pointer without that new callback
> >    option
> 
> So, here is 1), 2), 3) implemented.  With this patch alone,
> g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
> function::x_range_query member, which is set to &global_ranges on
> cfun creation and is:
>   range_query * GTY ((skip)) x_range_query;
> which means when a PIE binary writes PCH and a PIE binary loaded
> at a different address loads it, cfun->x_range_query might be a garbage
> pointer.  We can either apply a patch like the attached one after
> this inline patch, but then probably callback is misnamed and we should
> rename it to relocate_and_skip or something similar.  Or we could
> e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.

I think struct function allocation should initialize it to NULL and
the init to &global_ranges be done only when we do init_tree_ssa?
In fact x_range_query could be moved to the gimple_df substructure
to make that clear.

Hopefully PCH happens before init_tree_ssa.

> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.
> 
> Not really sure about PA or IA-64 function descriptors, are any of those
> allocated by the dynamic linker rather than created by the static linker?
> I guess instead of removing the c-pch.c changes we could remember there
> not just a function pointer, but also a data pointer and compare if both
> are either the same or have the same load bias and punt only if they
> have different bias.  Though, on architecture where all function pointers
> would be dynamically allocated and could change any time even that wouldn't
> be really a reliable check.
> 
> Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
> the second patch, with it a few more, but nothing huge.  And for non-PIEs
> there isn't really any extra work on the load side except freading two scalar
> values and fseek.
> 
> Thoughts on this?

I'm not keen on further life support for PCH, but then if the work is
done it's hard to reject it...

Note there might be still platforms not supporting PCH and so Iains
patches still look useful to me.

I also wonder whether we want to require active marking of types
with PCH support and assert when PCH write runs into objects without?

Richard.

> 2021-11-08  Jakub Jelinek  <jakub@redhat.com>
> 
> gcc/
> 	* ggc.h (gt_pch_note_callback): Declare.
> 	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
> 	(callback_type): Declare.
> 	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
> 	(callback_type): New variable.
> 	(process_gc_options): Add CALLBACK argument, handle callback
> 	option.
> 	(set_gc_used_type): Adjust process_gc_options caller, if callback,
> 	set type to &callback_type.
> 	(output_mangled_typename): Handle TYPE_CALLBACK.
> 	(walk_type): Likewise.  Handle callback option.
> 	(write_types_process_field): Handle TYPE_CALLBACK.
> 	(write_types_local_user_process_field): Likewise.
> 	(write_types_local_process_field): Likewise.
> 	(write_root): Likewise.
> 	(dump_typekind): Likewise.
> 	(dump_type): Likewise.
> 	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
> 	(state_writer::write_state_callback_type): New method.
> 	(state_writer::write_state_type): Handle TYPE_CALLBACK.
> 	(read_state_callback_type): New function.
> 	(read_state_type): Handle TYPE_CALLBACK.
> 	* ggc-common.c (callback_vec): New variable.
> 	(gt_pch_note_callback): New function.
> 	(gt_pch_save): Stream out gt_pch_save function address and relocation
> 	table.
> 	(gt_pch_restore): Stream in saved gt_pch_save function address and
> 	relocation table and apply relocations if needed.
> 	* doc/gty.texi (callback): Document new GTY option.
> 	* varasm.c (get_unnamed_section): Change callback argument's type and
> 	last argument's type from const void * to const char *.
> 	(output_section_asm_op): Change argument's type from const void *
> 	to const char *, remove unnecessary cast.
> 	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
> 	from language member.
> 	* output.h (unnamed_section_callback): Change argument type from
> 	const void * to const char *.
> 	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
> 	for callback member.  Change data member type from const void *
> 	to const char *.
> 	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
> 	for callback member.
> 	(get_unnamed_section): Change callback argument's type and
> 	last argument's type from const void * to const char *.
> 	(output_section_asm_op): Change argument's type from const void *
> 	to const char *.
> 	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
> 	Remove unneeded cast.
> 	* config/darwin.c (output_objc_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
> 	(som_output_comdat_data_section_asm_op): Likewise.
> 	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
> 	Likewise.
> 	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
> 	of dereferencing directive hardcode variable names and decide based on
> 	whether directive is NULL or not.
> 	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
> 	of dereferencing directive hardcode variable names and decide based on
> 	whether directive is NULL or not.
> 	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
> gcc/c-family/
> 	* c-pch.c (struct c_pch_validity): Remove pch_init member.
> 	(pch_init): Don't initialize v.pch_init.
> 	(c_common_valid_pch): Don't warn and punt if .text addresses change.
> libcpp/
> 	* include/line-map.h (class line_maps): Add GTY((callback)) to
> 	reallocator and round_alloc_size members.
> 
> --- gcc/ggc.h.jj	2021-08-19 11:42:27.366422386 +0200
> +++ gcc/ggc.h	2021-11-08 16:46:02.604618109 +0100
> @@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void
>  /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
>  extern int gt_pch_note_object (void *, void *, gt_note_pointers);
>  
> +/* Used by the gt_pch_p_* routines.  Register address of a callback
> +   pointer.  */
> +extern void gt_pch_note_callback (void *, void *);
> +
>  /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
>     function.  */
>  extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
> --- gcc/gengtype.h.jj	2021-07-20 10:08:09.892687719 +0200
> +++ gcc/gengtype.h	2021-11-08 15:19:59.194210185 +0100
> @@ -154,6 +154,9 @@ enum typekind {
>    TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
>    TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
>    TYPE_ARRAY,           /* Array of GTY-ed types.  */
> +  TYPE_CALLBACK,	/* A function pointer that needs relocation if
> +			   the executable has been loaded at a different
> +			   address.  */
>    TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
>                             Various languages may have homonymous but
>                             different structs.  */
> @@ -331,6 +334,9 @@ extern struct type string_type;
>  extern struct type scalar_nonchar;
>  extern struct type scalar_char;
>  
> +/* The one and only TYPE_CALLBACK.  */
> +extern struct type callback_type;
> +
>  /* Test if a type is a union, either a plain one or a language
>     specific one.  */
>  #define UNION_P(x)					\
> --- gcc/gengtype.c.jj	2021-10-04 10:16:10.885140187 +0200
> +++ gcc/gengtype.c	2021-11-08 16:30:41.981750183 +0100
> @@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil,
>    int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
>    int nb_lang_struct = 0;
>    int nb_user_struct = 0, nb_undefined = 0;
> +  int nb_callback = 0;
>    type_p p = NULL;
>    for (p = t; p; p = p->next)
>      {
> @@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil,
>  	case TYPE_ARRAY:
>  	  nb_array++;
>  	  break;
> +	case TYPE_CALLBACK:
> +	  nb_callback++;
> +	  break;
>  	case TYPE_LANG_STRUCT:
>  	  nb_lang_struct++;
>  	  break;
> @@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil,
>      fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
>    if (nb_pointer > 0 || nb_array > 0)
>      fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
> +  if (nb_callback > 0)
> +    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
>    if (nb_lang_struct > 0)
>      fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
>    if (nb_user_struct > 0)
> @@ -495,6 +501,10 @@ struct type scalar_char = {
>    TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
>  };
>  
> +struct type callback_type = {
> +  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
> +};
> +
>  /* Lists of various things.  */
>  
>  pair_p typedefs = NULL;
> @@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
>  
>  static void
>  process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
> -		    int *length, int *skip, type_p *nested_ptr)
> +		    int *length, int *skip, int *callback, type_p *nested_ptr)
>  {
>    options_p o;
>    for (o = opt; o; o = o->next)
> @@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum
>        *length = 1;
>      else if (strcmp (o->name, "skip") == 0)
>        *skip = 1;
> +    else if (strcmp (o->name, "callback") == 0)
> +      *callback = 1;
>      else if (strcmp (o->name, "nested_ptr") == 0
>  	     && o->kind == OPTION_NESTED)
>        *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
> @@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used
>  	type_p dummy2;
>  	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
>  
> -	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
> +	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
>  			    &dummy2);
>  
>  	if (t->u.s.base_class)
> @@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used
>  	    int maybe_undef = 0;
>  	    int length = 0;
>  	    int skip = 0;
> +	    int callback = 0;
>  	    type_p nested_ptr = NULL;
>  	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
> -				&nested_ptr);
> +				&callback, &nested_ptr);
>  
>  	    if (nested_ptr && f->type->kind == TYPE_POINTER)
>  	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
> @@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used
>  	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
>  	    else if (skip)
>  	      ;			/* target type is not used through this field */
> +	    else if (callback)
> +	      f->type = &callback_type;
>  	    else
>  	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
>  	  }
> @@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, cons
>        {
>        case TYPE_NONE:
>        case TYPE_UNDEFINED:
> +      case TYPE_CALLBACK:
>  	gcc_unreachable ();
>  	break;
>        case TYPE_POINTER:
> @@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_da
>        ;
>      else if (strcmp (oo->name, "for_user") == 0)
>        ;
> +    else if (strcmp (oo->name, "callback") == 0)
> +      ;
>      else
>        error_at_line (d->line, "unknown option `%s'\n", oo->name);
>  
> @@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_da
>      {
>      case TYPE_SCALAR:
>      case TYPE_STRING:
> +    case TYPE_CALLBACK:
>        d->process_field (t, d);
>        break;
>  
> @@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, con
>        break;
>  
>      case TYPE_SCALAR:
> +    case TYPE_CALLBACK:
>        break;
>  
>      case TYPE_ARRAY:
> @@ -3820,6 +3840,7 @@ write_types_local_user_process_field (ty
>        break;
>  
>      case TYPE_SCALAR:
> +    case TYPE_CALLBACK:
>        break;
>  
>      case TYPE_ARRAY:
> @@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p
>      case TYPE_SCALAR:
>        break;
>  
> +    case TYPE_CALLBACK:
> +      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
> +	       d->prev_val[3]);
> +      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
> +	       d->indent, "", d->val);
> +      break;
> +
>      case TYPE_ARRAY:
>      case TYPE_NONE:
>      case TYPE_UNDEFINED:
> @@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p t
>      case TYPE_UNDEFINED:
>      case TYPE_UNION:
>      case TYPE_LANG_STRUCT:
> +    case TYPE_CALLBACK:
>        error_at_line (line, "global `%s' is unimplemented type", name);
>      }
>  }
> @@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind
>      case TYPE_ARRAY:
>        printf ("TYPE_ARRAY");
>        break;
> +    case TYPE_CALLBACK:
> +      printf ("TYPE_CALLBACK");
> +      break;
>      case TYPE_LANG_STRUCT:
>        printf ("TYPE_LANG_STRUCT");
>        break;
> @@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
>  	      t->u.scalar_is_char ? "true" : "false");
>        break;
>      case TYPE_STRING:
> +    case TYPE_CALLBACK:
>        break;
>      case TYPE_STRUCT:
>      case TYPE_UNION:
> --- gcc/varasm.c.jj	2021-09-28 11:34:29.343147261 +0200
> +++ gcc/varasm.c	2021-11-08 13:26:15.032606040 +0100
> @@ -250,8 +250,8 @@ object_block_hasher::hash (object_block
>  /* Return a new unnamed section with the given fields.  */
>  
>  section *
> -get_unnamed_section (unsigned int flags, void (*callback) (const void *),
> -		     const void *data)
> +get_unnamed_section (unsigned int flags, void (*callback) (const char *),
> +		     const char *data)
>  {
>    section *sect;
>  
> @@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
>     a get_unnamed_section callback.  */
>  
>  void
> -output_section_asm_op (const void *directive)
> +output_section_asm_op (const char *directive)
>  {
> -  fprintf (asm_out_file, "%s\n", (const char *) directive);
> +  fprintf (asm_out_file, "%s\n", directive);
>  }
>  
>  /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
> --- gcc/ggc-common.c.jj	2021-11-08 11:09:50.280318624 +0100
> +++ gcc/ggc-common.c	2021-11-08 18:33:51.103390391 +0100
> @@ -246,6 +246,7 @@ saving_hasher::equal (const ptr_data *p1
>  }
>  
>  static hash_table<saving_hasher> *saving_htab;
> +static vec<void *> callback_vec;
>  
>  /* Register an object in the hash table.  */
>  
> @@ -278,6 +279,23 @@ gt_pch_note_object (void *obj, void *not
>    return 1;
>  }
>  
> +/* Register address of a callback pointer.  */
> +void
> +gt_pch_note_callback (void *obj, void *base)
> +{
> +  void *ptr;
> +  memcpy (&ptr, obj, sizeof (void *));
> +  if (ptr != NULL)
> +    {
> +      struct ptr_data *data
> +	= (struct ptr_data *)
> +	  saving_htab->find_with_hash (base, POINTER_HASH (base));
> +      gcc_assert (data);
> +      callback_vec.safe_push ((char *) data->new_addr
> +			      + ((char *) obj - (char *) base));
> +    }
> +}
> +
>  /* Register an object in the hash table.  */
>  
>  void
> @@ -592,10 +610,20 @@ gt_pch_save (FILE *f)
>    ggc_pch_finish (state.d, state.f);
>    gt_pch_fixup_stringpool ();
>  
> +  unsigned num_callbacks = callback_vec.length ();
> +  void (*pch_save) (FILE *) = &gt_pch_save;
> +  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
> +      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
> +      || (num_callbacks
> +	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
> +		     f) != num_callbacks))
> +    fatal_error (input_location, "cannot write PCH file: %m");
> +
>    XDELETE (state.ptrs);
>    XDELETE (this_object);
>    delete saving_htab;
>    saving_htab = NULL;
> +  callback_vec.release ();
>  }
>  
>  /* Read the state of the compiler back in from F.  */
> @@ -649,6 +677,30 @@ gt_pch_restore (FILE *f)
>    ggc_pch_read (f, mmi.preferred_base);
>  
>    gt_pch_restore_stringpool ();
> +
> +  void (*pch_save) (FILE *);
> +  unsigned num_callbacks;
> +  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
> +      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
> +    fatal_error (input_location, "cannot read PCH file: %m");
> +  if (pch_save != &gt_pch_save)
> +    {
> +      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
> +      void **ptrs = XNEWVEC (void *, num_callbacks);
> +      unsigned i;
> +
> +      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
> +	fatal_error (input_location, "cannot read PCH file: %m");
> +      for (i = 0; i < num_callbacks; ++i)
> +	{
> +	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
> +	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
> +	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
> +	}
> +      XDELETE (ptrs);
> +    }
> +  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
> +    fatal_error (input_location, "cannot read PCH file: %m");
>  }
>  
>  /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
> --- gcc/doc/gty.texi.jj	2021-08-19 11:42:27.363422428 +0200
> +++ gcc/doc/gty.texi	2021-11-08 17:13:46.613882767 +0100
> @@ -197,6 +197,15 @@ If @code{skip} is applied to a field, th
>  This is somewhat dangerous; the only safe use is in a union when one
>  field really isn't ever used.
>  
> +@findex callback
> +@item callback
> +
> +@code{callback} should be applied to fields with pointer to function type
> +and causes the field to be ignored similarly to @code{skip}, except when
> +writing PCH and the field is non-NULL it will remember the field's address
> +for relocation purposes if the process writing PCH has different load base
> +from a process reading PCH.
> +
>  @findex for_user
>  @item for_user
>  
> --- gcc/tree-core.h.jj	2021-11-04 12:27:02.377298411 +0100
> +++ gcc/tree-core.h	2021-11-08 13:24:04.496465555 +0100
> @@ -1964,7 +1964,7 @@ struct GTY(()) tree_function_decl {
>  struct GTY(()) tree_translation_unit_decl {
>    struct tree_decl_common common;
>    /* Source language of this translation unit.  Used for DWARF output.  */
> -  const char * GTY((skip(""))) language;
> +  const char *language;
>    /* TODO: Non-optimization used to build this translation unit.  */
>    /* TODO: Root of a partial DWARF tree for global types and decls.  */
>  };
> --- gcc/gengtype-state.c.jj	2021-07-20 10:08:09.891687732 +0200
> +++ gcc/gengtype-state.c	2021-11-08 15:19:16.157824146 +0100
> @@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
>      case TYPE_STRING:
>      case TYPE_POINTER:
>      case TYPE_ARRAY:
> +    case TYPE_CALLBACK:
>        return NULL;
>      default:
>        gcc_unreachable ();
> @@ -171,6 +172,7 @@ private:
>    void write_state_version (const char *version);
>    void write_state_scalar_type (type_p current);
>    void write_state_string_type (type_p current);
> +  void write_state_callback_type (type_p current);
>    void write_state_undefined_type (type_p current);
>    void write_state_struct_union_type (type_p current, const char *kindstr);
>    void write_state_struct_type (type_p current);
> @@ -898,6 +900,20 @@ state_writer::write_state_string_type (t
>      fatal ("Unexpected type in write_state_string_type");
>  }
>  
> +/* Write the callback type.  There is only one such thing! */
> +void
> +state_writer::write_state_callback_type (type_p current)
> +{
> +  if (current == &callback_type)
> +    {
> +      write_any_indent (0);
> +      fprintf (state_file, "callback ");
> +      write_state_common_type_content (current);
> +    }
> +  else
> +    fatal ("Unexpected type in write_state_callback_type");
> +}
> +
>  /* Write an undefined type.  */
>  void
>  state_writer::write_state_undefined_type (type_p current)
> @@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p c
>  	case TYPE_STRING:
>  	  write_state_string_type (current);
>  	  break;
> +	case TYPE_CALLBACK:
> +	  write_state_callback_type (current);
> +	  break;
>  	}
>      }
>  
> @@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
>    read_state_common_type_content (*type);
>  }
>  
> +/* Read the callback_type.  */
> +static void
> +read_state_callback_type (type_p *type)
> +{
> +  *type = &callback_type;
> +  read_state_common_type_content (*type);
> +}
> +
>  
>  /* Read a lang_bitmap representing a set of GCC front-end languages.  */
>  static void
> @@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
>  	      next_state_tokens (1);
>  	      read_state_string_type (current);
>  	    }
> +	  else if (state_token_is_name (t0, "callback"))
> +	    {
> +	      next_state_tokens (1);
> +	      read_state_callback_type (current);
> +	    }
>  	  else if (state_token_is_name (t0, "undefined"))
>  	    {
>  	      *current = XCNEW (struct type);
> --- gcc/output.h.jj	2021-09-28 11:34:29.235148754 +0200
> +++ gcc/output.h	2021-11-08 16:26:01.172755377 +0100
> @@ -470,7 +470,7 @@ struct GTY(()) named_section {
>  
>  /* A callback that writes the assembly code for switching to an unnamed
>     section.  The argument provides callback-specific data.  */
> -typedef void (*unnamed_section_callback) (const void *);
> +typedef void (*unnamed_section_callback) (const char *);
>  
>  /* Information about a SECTION_UNNAMED section.  */
>  struct GTY(()) unnamed_section {
> @@ -478,8 +478,8 @@ struct GTY(()) unnamed_section {
>  
>    /* The callback used to switch to the section, and the data that
>       should be passed to the callback.  */
> -  unnamed_section_callback GTY ((skip)) callback;
> -  const void *GTY ((skip)) data;
> +  unnamed_section_callback GTY ((callback)) callback;
> +  const char *data;
>  
>    /* The next entry in the chain of unnamed sections.  */
>    section *next;
> @@ -503,7 +503,7 @@ struct GTY(()) noswitch_section {
>    struct section_common common;
>  
>    /* The callback used to assemble decls in this section.  */
> -  noswitch_section_callback GTY ((skip)) callback;
> +  noswitch_section_callback GTY ((callback)) callback;
>  };
>  
>  /* Information about a section, which may be named or unnamed.  */
> @@ -538,8 +538,8 @@ extern GTY(()) section *bss_noswitch_sec
>  extern GTY(()) section *in_section;
>  extern GTY(()) bool in_cold_section_p;
>  
> -extern section *get_unnamed_section (unsigned int, void (*) (const void *),
> -				     const void *);
> +extern section *get_unnamed_section (unsigned int, void (*) (const char *),
> +				     const char *);
>  extern section *get_section (const char *, unsigned int, tree,
>  			     bool not_existing = false);
>  extern section *get_named_section (tree, const char *, int);
> @@ -561,7 +561,7 @@ extern section *get_cdtor_priority_secti
>  
>  extern bool unlikely_text_section_p (section *);
>  extern void switch_to_section (section *, tree = nullptr);
> -extern void output_section_asm_op (const void *);
> +extern void output_section_asm_op (const char *);
>  
>  extern void record_tm_clone_pair (tree, tree);
>  extern void finish_tm_clone_pairs (void);
> --- gcc/config/avr/avr.c.jj	2021-07-15 10:16:12.873583249 +0200
> +++ gcc/config/avr/avr.c	2021-11-08 13:28:30.215676387 +0100
> @@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const voi
>  /* Unnamed section callback for progmem*.data sections.  */
>  
>  static void
> -avr_output_progmem_section_asm_op (const void *data)
> +avr_output_progmem_section_asm_op (const char *data)
>  {
> -  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
> -           (const char*) data);
> +  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
>  }
>  
>  
> --- gcc/config/darwin.c.jj	2021-10-21 10:23:27.450834602 +0200
> +++ gcc/config/darwin.c	2021-11-08 13:27:19.106691421 +0100
> @@ -134,7 +134,7 @@ int emit_aligned_common = false;
>     DIRECTIVE is as for output_section_asm_op.  */
>  
>  static void
> -output_objc_section_asm_op (const void *directive)
> +output_objc_section_asm_op (const char *directive)
>  {
>    static bool been_here = false;
>  
> --- gcc/config/pa/pa.c.jj	2021-10-27 09:00:28.762277456 +0200
> +++ gcc/config/pa/pa.c	2021-11-08 13:29:41.935652629 +0100
> @@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t
>     to the default text subspace.  */
>  
>  static void
> -som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
> +som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>  {
>    gcc_assert (TARGET_SOM);
>    if (TARGET_GAS)
> @@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const vo
>     sections.  This function is only used with SOM.  */
>  
>  static void
> -som_output_comdat_data_section_asm_op (const void *data)
> +som_output_comdat_data_section_asm_op (const char *data)
>  {
>    in_section = NULL;
>    output_section_asm_op (data);
> --- gcc/config/rs6000/rs6000.c.jj	2021-11-05 00:43:22.476626062 +0100
> +++ gcc/config/rs6000/rs6000.c	2021-11-08 13:43:22.415940789 +0100
> @@ -20597,7 +20597,7 @@ rs6000_ms_bitfield_layout_p (const_tree
>  /* A get_unnamed_section callback, used for switching to toc_section.  */
>  
>  static void
> -rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
> +rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>  {
>    if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>        && TARGET_MINIMAL_TOC)
> @@ -21301,35 +21301,39 @@ rs6000_xcoff_asm_globalize_label (FILE *
>     points to the section string variable.  */
>  
>  static void
> -rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
> +rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
>  {
>    fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
> -	   *(const char *const *) directive,
> +	   directive
> +	   ? xcoff_private_rodata_section_name
> +	   : xcoff_read_only_section_name,
>  	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>  }
>  
>  /* Likewise for read-write sections.  */
>  
>  static void
> -rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
> +rs6000_xcoff_output_readwrite_section_asm_op (const char *)
>  {
>    fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
> -	   *(const char *const *) directive,
> +	   xcoff_private_data_section_name,
>  	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>  }
>  
>  static void
> -rs6000_xcoff_output_tls_section_asm_op (const void *directive)
> +rs6000_xcoff_output_tls_section_asm_op (const char *directive)
>  {
>    fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
> -	   *(const char *const *) directive,
> +	   directive
> +	   ? xcoff_private_data_section_name
> +	   : xcoff_tls_data_section_name,
>  	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>  }
>  
>  /* A get_unnamed_section callback, used for switching to toc_section.  */
>  
>  static void
> -rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
> +rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>  {
>    if (TARGET_MINIMAL_TOC)
>      {
> @@ -21356,26 +21360,26 @@ rs6000_xcoff_asm_init_sections (void)
>  {
>    read_only_data_section
>      = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
> -			   &xcoff_read_only_section_name);
> +			   NULL);
>  
>    private_data_section
>      = get_unnamed_section (SECTION_WRITE,
>  			   rs6000_xcoff_output_readwrite_section_asm_op,
> -			   &xcoff_private_data_section_name);
> +			   NULL);
>  
>    read_only_private_data_section
>      = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
> -			   &xcoff_private_rodata_section_name);
> +			   "");
>  
>    tls_data_section
>      = get_unnamed_section (SECTION_TLS,
>  			   rs6000_xcoff_output_tls_section_asm_op,
> -			   &xcoff_tls_data_section_name);
> +			   NULL);
>  
>    tls_private_data_section
>      = get_unnamed_section (SECTION_TLS,
>  			   rs6000_xcoff_output_tls_section_asm_op,
> -			   &xcoff_private_data_section_name);
> +			   "");
>  
>    toc_section
>      = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
> --- gcc/c-family/c-pch.c.jj	2021-06-02 10:08:14.149450407 +0200
> +++ gcc/c-family/c-pch.c	2021-11-08 17:34:17.302343697 +0100
> @@ -54,7 +54,6 @@ struct c_pch_validity
>  {
>    uint32_t pch_write_symbols;
>    signed char match[MATCH_SIZE];
> -  void (*pch_init) (void);
>    size_t target_data_length;
>  };
>  
> @@ -117,7 +116,6 @@ pch_init (void)
>  	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
>        }
>    }
> -  v.pch_init = &pch_init;
>    target_validity = targetm.get_pch_validity (&v.target_data_length);
>  
>    if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
> @@ -278,19 +276,6 @@ c_common_valid_pch (cpp_reader *pfile, c
>  	}
>    }
>  
> -  /* If the text segment was not loaded at the same address as it was
> -     when the PCH file was created, function pointers loaded from the
> -     PCH will not be valid.  We could in theory remap all the function
> -     pointers, but no support for that exists at present.
> -     Since we have the same executable, it should only be necessary to
> -     check one function.  */
> -  if (v.pch_init != &pch_init)
> -    {
> -      cpp_warning (pfile, CPP_W_INVALID_PCH,
> -		   "%s: had text segment at different address", name);
> -      return 2;
> -    }
> -
>    /* Check the target-specific validity data.  */
>    {
>      void *this_file_data = xmalloc (v.target_data_length);
> --- libcpp/include/line-map.h.jj	2021-11-01 14:37:06.697853154 +0100
> +++ libcpp/include/line-map.h	2021-11-08 16:16:34.562837006 +0100
> @@ -803,11 +803,11 @@ public:
>    unsigned int max_column_hint;
>  
>    /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
> -  line_map_realloc reallocator;
> +  line_map_realloc GTY((callback)) reallocator;
>  
>    /* The allocators' function used to know the actual size it
>       allocated, for a certain allocation size requested.  */
> -  line_map_round_alloc_size_func round_alloc_size;
> +  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
>  
>    struct location_adhoc_data_map location_adhoc_data_map;
>  
> 
> 
> 	Jakub
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09  7:12               ` Richard Biener
@ 2021-11-09  8:07                 ` Iain Sandoe
  2021-11-09 11:40                   ` Iain Sandoe
  2021-11-09  9:44                 ` Jakub Jelinek
  1 sibling, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-09  8:07 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, John David Anglin, Aldy Hernandez, Andrew MacLeod,
	Richard Biener



> On 9 Nov 2021, at 07:12, Richard Biener <rguenther@suse.de> wrote:
> 
> On Mon, 8 Nov 2021, Jakub Jelinek wrote:
> 
>> On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
>>> So, if we want to make PCH work for PIEs, I'd say we can:
>>> 1) add a new GTY option, say callback, which would act like
>>>   skip for non-PCH and for PCH would make us skip it but
>>>   remember for address bias translation
>>> 2) drop the skip for tree_translation_unit_decl::language
>>> 3) change get_unnamed_section to have const char * as
>>>   last argument instead of const void *, change
>>>   unnamed_section::data also to const char * and update
>>>   everything related to that
>>> 4) maybe add a host hook whether it is ok to support binaries
>>>   changing addresses (the only thing I'm worried is if
>>>   some host that uses function descriptors allocates them
>>>   dynamically instead of having them somewhere in the
>>>   executable)
>>> 5) maybe add a gengtype warning if it sees in GTY tracked
>>>   structure a function pointer without that new callback
>>>   option
>> 
>> So, here is 1), 2), 3) implemented.  With this patch alone,
>> g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
>> function::x_range_query member, which is set to &global_ranges on
>> cfun creation and is:
>>  range_query * GTY ((skip)) x_range_query;
>> which means when a PIE binary writes PCH and a PIE binary loaded
>> at a different address loads it, cfun->x_range_query might be a garbage
>> pointer.  We can either apply a patch like the attached one after
>> this inline patch, but then probably callback is misnamed and we should
>> rename it to relocate_and_skip or something similar.  Or we could
>> e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
> 
> I think struct function allocation should initialize it to NULL and
> the init to &global_ranges be done only when we do init_tree_ssa?
> In fact x_range_query could be moved to the gimple_df substructure
> to make that clear.
> 
> Hopefully PCH happens before init_tree_ssa.
> 
>> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.
>> 
>> Not really sure about PA or IA-64 function descriptors, are any of those
>> allocated by the dynamic linker rather than created by the static linker?
>> I guess instead of removing the c-pch.c changes we could remember there
>> not just a function pointer, but also a data pointer and compare if both
>> are either the same or have the same load bias and punt only if they
>> have different bias.  Though, on architecture where all function pointers
>> would be dynamically allocated and could change any time even that wouldn't
>> be really a reliable check.
>> 
>> Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
>> the second patch, with it a few more, but nothing huge.  And for non-PIEs
>> there isn't really any extra work on the load side except freading two scalar
>> values and fseek.
>> 
>> Thoughts on this?

- thanks for doing it, I still think a working solution is better than a disable.

- This would be a fix for PR 71934

- I applied the patches on Darwin and there’s still some case(s) to find and fix
  cc1/cc1plus hang on pch input, when any diagnostic is emitted (doing some
  linemap lookup) .. hopefully, I can find some time to figure out what is not 
  happy.

> I'm not keen on further life support for PCH, but then if the work is
> done it's hard to reject it...
> 
> Note there might be still platforms not supporting PCH and so Iains
> patches still look useful to me.

Yeah, what would be most useful at this stage is some way to get those
tested against some wider set of package builds to see if anything fires
that breaks stuff.

> I also wonder whether we want to require active marking of types
> with PCH support and assert when PCH write runs into objects without?

anything that makes GTY markup more robust is a Good Idea.
Iain

> 
> Richard.
> 
>> 2021-11-08  Jakub Jelinek  <jakub@redhat.com>
>> 
>> gcc/
>> 	* ggc.h (gt_pch_note_callback): Declare.
>> 	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
>> 	(callback_type): Declare.
>> 	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
>> 	(callback_type): New variable.
>> 	(process_gc_options): Add CALLBACK argument, handle callback
>> 	option.
>> 	(set_gc_used_type): Adjust process_gc_options caller, if callback,
>> 	set type to &callback_type.
>> 	(output_mangled_typename): Handle TYPE_CALLBACK.
>> 	(walk_type): Likewise.  Handle callback option.
>> 	(write_types_process_field): Handle TYPE_CALLBACK.
>> 	(write_types_local_user_process_field): Likewise.
>> 	(write_types_local_process_field): Likewise.
>> 	(write_root): Likewise.
>> 	(dump_typekind): Likewise.
>> 	(dump_type): Likewise.
>> 	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
>> 	(state_writer::write_state_callback_type): New method.
>> 	(state_writer::write_state_type): Handle TYPE_CALLBACK.
>> 	(read_state_callback_type): New function.
>> 	(read_state_type): Handle TYPE_CALLBACK.
>> 	* ggc-common.c (callback_vec): New variable.
>> 	(gt_pch_note_callback): New function.
>> 	(gt_pch_save): Stream out gt_pch_save function address and relocation
>> 	table.
>> 	(gt_pch_restore): Stream in saved gt_pch_save function address and
>> 	relocation table and apply relocations if needed.
>> 	* doc/gty.texi (callback): Document new GTY option.
>> 	* varasm.c (get_unnamed_section): Change callback argument's type and
>> 	last argument's type from const void * to const char *.
>> 	(output_section_asm_op): Change argument's type from const void *
>> 	to const char *, remove unnecessary cast.
>> 	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
>> 	from language member.
>> 	* output.h (unnamed_section_callback): Change argument type from
>> 	const void * to const char *.
>> 	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
>> 	for callback member.  Change data member type from const void *
>> 	to const char *.
>> 	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
>> 	for callback member.
>> 	(get_unnamed_section): Change callback argument's type and
>> 	last argument's type from const void * to const char *.
>> 	(output_section_asm_op): Change argument's type from const void *
>> 	to const char *.
>> 	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
>> 	Remove unneeded cast.
>> 	* config/darwin.c (output_objc_section_asm_op): Change argument's type
>> 	from const void * to const char *.
>> 	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
>> 	(som_output_comdat_data_section_asm_op): Likewise.
>> 	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
>> 	Likewise.
>> 	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
>> 	of dereferencing directive hardcode variable names and decide based on
>> 	whether directive is NULL or not.
>> 	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
>> 	from const void * to const char *.
>> 	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
>> 	of dereferencing directive hardcode variable names and decide based on
>> 	whether directive is NULL or not.
>> 	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
>> 	from const void * to const char *.
>> 	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
>> gcc/c-family/
>> 	* c-pch.c (struct c_pch_validity): Remove pch_init member.
>> 	(pch_init): Don't initialize v.pch_init.
>> 	(c_common_valid_pch): Don't warn and punt if .text addresses change.
>> libcpp/
>> 	* include/line-map.h (class line_maps): Add GTY((callback)) to
>> 	reallocator and round_alloc_size members.
>> 
>> --- gcc/ggc.h.jj	2021-08-19 11:42:27.366422386 +0200
>> +++ gcc/ggc.h	2021-11-08 16:46:02.604618109 +0100
>> @@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void
>> /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
>> extern int gt_pch_note_object (void *, void *, gt_note_pointers);
>> 
>> +/* Used by the gt_pch_p_* routines.  Register address of a callback
>> +   pointer.  */
>> +extern void gt_pch_note_callback (void *, void *);
>> +
>> /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
>>    function.  */
>> extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
>> --- gcc/gengtype.h.jj	2021-07-20 10:08:09.892687719 +0200
>> +++ gcc/gengtype.h	2021-11-08 15:19:59.194210185 +0100
>> @@ -154,6 +154,9 @@ enum typekind {
>>   TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
>>   TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
>>   TYPE_ARRAY,           /* Array of GTY-ed types.  */
>> +  TYPE_CALLBACK,	/* A function pointer that needs relocation if
>> +			   the executable has been loaded at a different
>> +			   address.  */
>>   TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
>>                            Various languages may have homonymous but
>>                            different structs.  */
>> @@ -331,6 +334,9 @@ extern struct type string_type;
>> extern struct type scalar_nonchar;
>> extern struct type scalar_char;
>> 
>> +/* The one and only TYPE_CALLBACK.  */
>> +extern struct type callback_type;
>> +
>> /* Test if a type is a union, either a plain one or a language
>>    specific one.  */
>> #define UNION_P(x)					\
>> --- gcc/gengtype.c.jj	2021-10-04 10:16:10.885140187 +0200
>> +++ gcc/gengtype.c	2021-11-08 16:30:41.981750183 +0100
>> @@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil,
>>   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
>>   int nb_lang_struct = 0;
>>   int nb_user_struct = 0, nb_undefined = 0;
>> +  int nb_callback = 0;
>>   type_p p = NULL;
>>   for (p = t; p; p = p->next)
>>     {
>> @@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil,
>> 	case TYPE_ARRAY:
>> 	  nb_array++;
>> 	  break;
>> +	case TYPE_CALLBACK:
>> +	  nb_callback++;
>> +	  break;
>> 	case TYPE_LANG_STRUCT:
>> 	  nb_lang_struct++;
>> 	  break;
>> @@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil,
>>     fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
>>   if (nb_pointer > 0 || nb_array > 0)
>>     fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
>> +  if (nb_callback > 0)
>> +    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
>>   if (nb_lang_struct > 0)
>>     fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
>>   if (nb_user_struct > 0)
>> @@ -495,6 +501,10 @@ struct type scalar_char = {
>>   TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
>> };
>> 
>> +struct type callback_type = {
>> +  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
>> +};
>> +
>> /* Lists of various things.  */
>> 
>> pair_p typedefs = NULL;
>> @@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
>> 
>> static void
>> process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
>> -		    int *length, int *skip, type_p *nested_ptr)
>> +		    int *length, int *skip, int *callback, type_p *nested_ptr)
>> {
>>   options_p o;
>>   for (o = opt; o; o = o->next)
>> @@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum
>>       *length = 1;
>>     else if (strcmp (o->name, "skip") == 0)
>>       *skip = 1;
>> +    else if (strcmp (o->name, "callback") == 0)
>> +      *callback = 1;
>>     else if (strcmp (o->name, "nested_ptr") == 0
>> 	     && o->kind == OPTION_NESTED)
>>       *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
>> @@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used
>> 	type_p dummy2;
>> 	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
>> 
>> -	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
>> +	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
>> 			    &dummy2);
>> 
>> 	if (t->u.s.base_class)
>> @@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used
>> 	    int maybe_undef = 0;
>> 	    int length = 0;
>> 	    int skip = 0;
>> +	    int callback = 0;
>> 	    type_p nested_ptr = NULL;
>> 	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
>> -				&nested_ptr);
>> +				&callback, &nested_ptr);
>> 
>> 	    if (nested_ptr && f->type->kind == TYPE_POINTER)
>> 	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
>> @@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used
>> 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
>> 	    else if (skip)
>> 	      ;			/* target type is not used through this field */
>> +	    else if (callback)
>> +	      f->type = &callback_type;
>> 	    else
>> 	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
>> 	  }
>> @@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, cons
>>       {
>>       case TYPE_NONE:
>>       case TYPE_UNDEFINED:
>> +      case TYPE_CALLBACK:
>> 	gcc_unreachable ();
>> 	break;
>>       case TYPE_POINTER:
>> @@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_da
>>       ;
>>     else if (strcmp (oo->name, "for_user") == 0)
>>       ;
>> +    else if (strcmp (oo->name, "callback") == 0)
>> +      ;
>>     else
>>       error_at_line (d->line, "unknown option `%s'\n", oo->name);
>> 
>> @@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_da
>>     {
>>     case TYPE_SCALAR:
>>     case TYPE_STRING:
>> +    case TYPE_CALLBACK:
>>       d->process_field (t, d);
>>       break;
>> 
>> @@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, con
>>       break;
>> 
>>     case TYPE_SCALAR:
>> +    case TYPE_CALLBACK:
>>       break;
>> 
>>     case TYPE_ARRAY:
>> @@ -3820,6 +3840,7 @@ write_types_local_user_process_field (ty
>>       break;
>> 
>>     case TYPE_SCALAR:
>> +    case TYPE_CALLBACK:
>>       break;
>> 
>>     case TYPE_ARRAY:
>> @@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p
>>     case TYPE_SCALAR:
>>       break;
>> 
>> +    case TYPE_CALLBACK:
>> +      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
>> +	       d->prev_val[3]);
>> +      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
>> +	       d->indent, "", d->val);
>> +      break;
>> +
>>     case TYPE_ARRAY:
>>     case TYPE_NONE:
>>     case TYPE_UNDEFINED:
>> @@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p t
>>     case TYPE_UNDEFINED:
>>     case TYPE_UNION:
>>     case TYPE_LANG_STRUCT:
>> +    case TYPE_CALLBACK:
>>       error_at_line (line, "global `%s' is unimplemented type", name);
>>     }
>> }
>> @@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind
>>     case TYPE_ARRAY:
>>       printf ("TYPE_ARRAY");
>>       break;
>> +    case TYPE_CALLBACK:
>> +      printf ("TYPE_CALLBACK");
>> +      break;
>>     case TYPE_LANG_STRUCT:
>>       printf ("TYPE_LANG_STRUCT");
>>       break;
>> @@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
>> 	      t->u.scalar_is_char ? "true" : "false");
>>       break;
>>     case TYPE_STRING:
>> +    case TYPE_CALLBACK:
>>       break;
>>     case TYPE_STRUCT:
>>     case TYPE_UNION:
>> --- gcc/varasm.c.jj	2021-09-28 11:34:29.343147261 +0200
>> +++ gcc/varasm.c	2021-11-08 13:26:15.032606040 +0100
>> @@ -250,8 +250,8 @@ object_block_hasher::hash (object_block
>> /* Return a new unnamed section with the given fields.  */
>> 
>> section *
>> -get_unnamed_section (unsigned int flags, void (*callback) (const void *),
>> -		     const void *data)
>> +get_unnamed_section (unsigned int flags, void (*callback) (const char *),
>> +		     const char *data)
>> {
>>   section *sect;
>> 
>> @@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
>>    a get_unnamed_section callback.  */
>> 
>> void
>> -output_section_asm_op (const void *directive)
>> +output_section_asm_op (const char *directive)
>> {
>> -  fprintf (asm_out_file, "%s\n", (const char *) directive);
>> +  fprintf (asm_out_file, "%s\n", directive);
>> }
>> 
>> /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
>> --- gcc/ggc-common.c.jj	2021-11-08 11:09:50.280318624 +0100
>> +++ gcc/ggc-common.c	2021-11-08 18:33:51.103390391 +0100
>> @@ -246,6 +246,7 @@ saving_hasher::equal (const ptr_data *p1
>> }
>> 
>> static hash_table<saving_hasher> *saving_htab;
>> +static vec<void *> callback_vec;
>> 
>> /* Register an object in the hash table.  */
>> 
>> @@ -278,6 +279,23 @@ gt_pch_note_object (void *obj, void *not
>>   return 1;
>> }
>> 
>> +/* Register address of a callback pointer.  */
>> +void
>> +gt_pch_note_callback (void *obj, void *base)
>> +{
>> +  void *ptr;
>> +  memcpy (&ptr, obj, sizeof (void *));
>> +  if (ptr != NULL)
>> +    {
>> +      struct ptr_data *data
>> +	= (struct ptr_data *)
>> +	  saving_htab->find_with_hash (base, POINTER_HASH (base));
>> +      gcc_assert (data);
>> +      callback_vec.safe_push ((char *) data->new_addr
>> +			      + ((char *) obj - (char *) base));
>> +    }
>> +}
>> +
>> /* Register an object in the hash table.  */
>> 
>> void
>> @@ -592,10 +610,20 @@ gt_pch_save (FILE *f)
>>   ggc_pch_finish (state.d, state.f);
>>   gt_pch_fixup_stringpool ();
>> 
>> +  unsigned num_callbacks = callback_vec.length ();
>> +  void (*pch_save) (FILE *) = &gt_pch_save;
>> +  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
>> +      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
>> +      || (num_callbacks
>> +	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
>> +		     f) != num_callbacks))
>> +    fatal_error (input_location, "cannot write PCH file: %m");
>> +
>>   XDELETE (state.ptrs);
>>   XDELETE (this_object);
>>   delete saving_htab;
>>   saving_htab = NULL;
>> +  callback_vec.release ();
>> }
>> 
>> /* Read the state of the compiler back in from F.  */
>> @@ -649,6 +677,30 @@ gt_pch_restore (FILE *f)
>>   ggc_pch_read (f, mmi.preferred_base);
>> 
>>   gt_pch_restore_stringpool ();
>> +
>> +  void (*pch_save) (FILE *);
>> +  unsigned num_callbacks;
>> +  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
>> +      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
>> +    fatal_error (input_location, "cannot read PCH file: %m");
>> +  if (pch_save != &gt_pch_save)
>> +    {
>> +      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
>> +      void **ptrs = XNEWVEC (void *, num_callbacks);
>> +      unsigned i;
>> +
>> +      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
>> +	fatal_error (input_location, "cannot read PCH file: %m");
>> +      for (i = 0; i < num_callbacks; ++i)
>> +	{
>> +	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
>> +	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
>> +	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
>> +	}
>> +      XDELETE (ptrs);
>> +    }
>> +  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
>> +    fatal_error (input_location, "cannot read PCH file: %m");
>> }
>> 
>> /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
>> --- gcc/doc/gty.texi.jj	2021-08-19 11:42:27.363422428 +0200
>> +++ gcc/doc/gty.texi	2021-11-08 17:13:46.613882767 +0100
>> @@ -197,6 +197,15 @@ If @code{skip} is applied to a field, th
>> This is somewhat dangerous; the only safe use is in a union when one
>> field really isn't ever used.
>> 
>> +@findex callback
>> +@item callback
>> +
>> +@code{callback} should be applied to fields with pointer to function type
>> +and causes the field to be ignored similarly to @code{skip}, except when
>> +writing PCH and the field is non-NULL it will remember the field's address
>> +for relocation purposes if the process writing PCH has different load base
>> +from a process reading PCH.
>> +
>> @findex for_user
>> @item for_user
>> 
>> --- gcc/tree-core.h.jj	2021-11-04 12:27:02.377298411 +0100
>> +++ gcc/tree-core.h	2021-11-08 13:24:04.496465555 +0100
>> @@ -1964,7 +1964,7 @@ struct GTY(()) tree_function_decl {
>> struct GTY(()) tree_translation_unit_decl {
>>   struct tree_decl_common common;
>>   /* Source language of this translation unit.  Used for DWARF output.  */
>> -  const char * GTY((skip(""))) language;
>> +  const char *language;
>>   /* TODO: Non-optimization used to build this translation unit.  */
>>   /* TODO: Root of a partial DWARF tree for global types and decls.  */
>> };
>> --- gcc/gengtype-state.c.jj	2021-07-20 10:08:09.891687732 +0200
>> +++ gcc/gengtype-state.c	2021-11-08 15:19:16.157824146 +0100
>> @@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
>>     case TYPE_STRING:
>>     case TYPE_POINTER:
>>     case TYPE_ARRAY:
>> +    case TYPE_CALLBACK:
>>       return NULL;
>>     default:
>>       gcc_unreachable ();
>> @@ -171,6 +172,7 @@ private:
>>   void write_state_version (const char *version);
>>   void write_state_scalar_type (type_p current);
>>   void write_state_string_type (type_p current);
>> +  void write_state_callback_type (type_p current);
>>   void write_state_undefined_type (type_p current);
>>   void write_state_struct_union_type (type_p current, const char *kindstr);
>>   void write_state_struct_type (type_p current);
>> @@ -898,6 +900,20 @@ state_writer::write_state_string_type (t
>>     fatal ("Unexpected type in write_state_string_type");
>> }
>> 
>> +/* Write the callback type.  There is only one such thing! */
>> +void
>> +state_writer::write_state_callback_type (type_p current)
>> +{
>> +  if (current == &callback_type)
>> +    {
>> +      write_any_indent (0);
>> +      fprintf (state_file, "callback ");
>> +      write_state_common_type_content (current);
>> +    }
>> +  else
>> +    fatal ("Unexpected type in write_state_callback_type");
>> +}
>> +
>> /* Write an undefined type.  */
>> void
>> state_writer::write_state_undefined_type (type_p current)
>> @@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p c
>> 	case TYPE_STRING:
>> 	  write_state_string_type (current);
>> 	  break;
>> +	case TYPE_CALLBACK:
>> +	  write_state_callback_type (current);
>> +	  break;
>> 	}
>>     }
>> 
>> @@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
>>   read_state_common_type_content (*type);
>> }
>> 
>> +/* Read the callback_type.  */
>> +static void
>> +read_state_callback_type (type_p *type)
>> +{
>> +  *type = &callback_type;
>> +  read_state_common_type_content (*type);
>> +}
>> +
>> 
>> /* Read a lang_bitmap representing a set of GCC front-end languages.  */
>> static void
>> @@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
>> 	      next_state_tokens (1);
>> 	      read_state_string_type (current);
>> 	    }
>> +	  else if (state_token_is_name (t0, "callback"))
>> +	    {
>> +	      next_state_tokens (1);
>> +	      read_state_callback_type (current);
>> +	    }
>> 	  else if (state_token_is_name (t0, "undefined"))
>> 	    {
>> 	      *current = XCNEW (struct type);
>> --- gcc/output.h.jj	2021-09-28 11:34:29.235148754 +0200
>> +++ gcc/output.h	2021-11-08 16:26:01.172755377 +0100
>> @@ -470,7 +470,7 @@ struct GTY(()) named_section {
>> 
>> /* A callback that writes the assembly code for switching to an unnamed
>>    section.  The argument provides callback-specific data.  */
>> -typedef void (*unnamed_section_callback) (const void *);
>> +typedef void (*unnamed_section_callback) (const char *);
>> 
>> /* Information about a SECTION_UNNAMED section.  */
>> struct GTY(()) unnamed_section {
>> @@ -478,8 +478,8 @@ struct GTY(()) unnamed_section {
>> 
>>   /* The callback used to switch to the section, and the data that
>>      should be passed to the callback.  */
>> -  unnamed_section_callback GTY ((skip)) callback;
>> -  const void *GTY ((skip)) data;
>> +  unnamed_section_callback GTY ((callback)) callback;
>> +  const char *data;
>> 
>>   /* The next entry in the chain of unnamed sections.  */
>>   section *next;
>> @@ -503,7 +503,7 @@ struct GTY(()) noswitch_section {
>>   struct section_common common;
>> 
>>   /* The callback used to assemble decls in this section.  */
>> -  noswitch_section_callback GTY ((skip)) callback;
>> +  noswitch_section_callback GTY ((callback)) callback;
>> };
>> 
>> /* Information about a section, which may be named or unnamed.  */
>> @@ -538,8 +538,8 @@ extern GTY(()) section *bss_noswitch_sec
>> extern GTY(()) section *in_section;
>> extern GTY(()) bool in_cold_section_p;
>> 
>> -extern section *get_unnamed_section (unsigned int, void (*) (const void *),
>> -				     const void *);
>> +extern section *get_unnamed_section (unsigned int, void (*) (const char *),
>> +				     const char *);
>> extern section *get_section (const char *, unsigned int, tree,
>> 			     bool not_existing = false);
>> extern section *get_named_section (tree, const char *, int);
>> @@ -561,7 +561,7 @@ extern section *get_cdtor_priority_secti
>> 
>> extern bool unlikely_text_section_p (section *);
>> extern void switch_to_section (section *, tree = nullptr);
>> -extern void output_section_asm_op (const void *);
>> +extern void output_section_asm_op (const char *);
>> 
>> extern void record_tm_clone_pair (tree, tree);
>> extern void finish_tm_clone_pairs (void);
>> --- gcc/config/avr/avr.c.jj	2021-07-15 10:16:12.873583249 +0200
>> +++ gcc/config/avr/avr.c	2021-11-08 13:28:30.215676387 +0100
>> @@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const voi
>> /* Unnamed section callback for progmem*.data sections.  */
>> 
>> static void
>> -avr_output_progmem_section_asm_op (const void *data)
>> +avr_output_progmem_section_asm_op (const char *data)
>> {
>> -  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
>> -           (const char*) data);
>> +  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
>> }
>> 
>> 
>> --- gcc/config/darwin.c.jj	2021-10-21 10:23:27.450834602 +0200
>> +++ gcc/config/darwin.c	2021-11-08 13:27:19.106691421 +0100
>> @@ -134,7 +134,7 @@ int emit_aligned_common = false;
>>    DIRECTIVE is as for output_section_asm_op.  */
>> 
>> static void
>> -output_objc_section_asm_op (const void *directive)
>> +output_objc_section_asm_op (const char *directive)
>> {
>>   static bool been_here = false;
>> 
>> --- gcc/config/pa/pa.c.jj	2021-10-27 09:00:28.762277456 +0200
>> +++ gcc/config/pa/pa.c	2021-11-08 13:29:41.935652629 +0100
>> @@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t
>>    to the default text subspace.  */
>> 
>> static void
>> -som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>> +som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>> {
>>   gcc_assert (TARGET_SOM);
>>   if (TARGET_GAS)
>> @@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const vo
>>    sections.  This function is only used with SOM.  */
>> 
>> static void
>> -som_output_comdat_data_section_asm_op (const void *data)
>> +som_output_comdat_data_section_asm_op (const char *data)
>> {
>>   in_section = NULL;
>>   output_section_asm_op (data);
>> --- gcc/config/rs6000/rs6000.c.jj	2021-11-05 00:43:22.476626062 +0100
>> +++ gcc/config/rs6000/rs6000.c	2021-11-08 13:43:22.415940789 +0100
>> @@ -20597,7 +20597,7 @@ rs6000_ms_bitfield_layout_p (const_tree
>> /* A get_unnamed_section callback, used for switching to toc_section.  */
>> 
>> static void
>> -rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>> +rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>> {
>>   if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>>       && TARGET_MINIMAL_TOC)
>> @@ -21301,35 +21301,39 @@ rs6000_xcoff_asm_globalize_label (FILE *
>>    points to the section string variable.  */
>> 
>> static void
>> -rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
>> +rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
>> {
>>   fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
>> -	   *(const char *const *) directive,
>> +	   directive
>> +	   ? xcoff_private_rodata_section_name
>> +	   : xcoff_read_only_section_name,
>> 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>> }
>> 
>> /* Likewise for read-write sections.  */
>> 
>> static void
>> -rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
>> +rs6000_xcoff_output_readwrite_section_asm_op (const char *)
>> {
>>   fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
>> -	   *(const char *const *) directive,
>> +	   xcoff_private_data_section_name,
>> 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>> }
>> 
>> static void
>> -rs6000_xcoff_output_tls_section_asm_op (const void *directive)
>> +rs6000_xcoff_output_tls_section_asm_op (const char *directive)
>> {
>>   fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
>> -	   *(const char *const *) directive,
>> +	   directive
>> +	   ? xcoff_private_data_section_name
>> +	   : xcoff_tls_data_section_name,
>> 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>> }
>> 
>> /* A get_unnamed_section callback, used for switching to toc_section.  */
>> 
>> static void
>> -rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>> +rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>> {
>>   if (TARGET_MINIMAL_TOC)
>>     {
>> @@ -21356,26 +21360,26 @@ rs6000_xcoff_asm_init_sections (void)
>> {
>>   read_only_data_section
>>     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
>> -			   &xcoff_read_only_section_name);
>> +			   NULL);
>> 
>>   private_data_section
>>     = get_unnamed_section (SECTION_WRITE,
>> 			   rs6000_xcoff_output_readwrite_section_asm_op,
>> -			   &xcoff_private_data_section_name);
>> +			   NULL);
>> 
>>   read_only_private_data_section
>>     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
>> -			   &xcoff_private_rodata_section_name);
>> +			   "");
>> 
>>   tls_data_section
>>     = get_unnamed_section (SECTION_TLS,
>> 			   rs6000_xcoff_output_tls_section_asm_op,
>> -			   &xcoff_tls_data_section_name);
>> +			   NULL);
>> 
>>   tls_private_data_section
>>     = get_unnamed_section (SECTION_TLS,
>> 			   rs6000_xcoff_output_tls_section_asm_op,
>> -			   &xcoff_private_data_section_name);
>> +			   "");
>> 
>>   toc_section
>>     = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
>> --- gcc/c-family/c-pch.c.jj	2021-06-02 10:08:14.149450407 +0200
>> +++ gcc/c-family/c-pch.c	2021-11-08 17:34:17.302343697 +0100
>> @@ -54,7 +54,6 @@ struct c_pch_validity
>> {
>>   uint32_t pch_write_symbols;
>>   signed char match[MATCH_SIZE];
>> -  void (*pch_init) (void);
>>   size_t target_data_length;
>> };
>> 
>> @@ -117,7 +116,6 @@ pch_init (void)
>> 	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
>>       }
>>   }
>> -  v.pch_init = &pch_init;
>>   target_validity = targetm.get_pch_validity (&v.target_data_length);
>> 
>>   if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
>> @@ -278,19 +276,6 @@ c_common_valid_pch (cpp_reader *pfile, c
>> 	}
>>   }
>> 
>> -  /* If the text segment was not loaded at the same address as it was
>> -     when the PCH file was created, function pointers loaded from the
>> -     PCH will not be valid.  We could in theory remap all the function
>> -     pointers, but no support for that exists at present.
>> -     Since we have the same executable, it should only be necessary to
>> -     check one function.  */
>> -  if (v.pch_init != &pch_init)
>> -    {
>> -      cpp_warning (pfile, CPP_W_INVALID_PCH,
>> -		   "%s: had text segment at different address", name);
>> -      return 2;
>> -    }
>> -
>>   /* Check the target-specific validity data.  */
>>   {
>>     void *this_file_data = xmalloc (v.target_data_length);
>> --- libcpp/include/line-map.h.jj	2021-11-01 14:37:06.697853154 +0100
>> +++ libcpp/include/line-map.h	2021-11-08 16:16:34.562837006 +0100
>> @@ -803,11 +803,11 @@ public:
>>   unsigned int max_column_hint;
>> 
>>   /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
>> -  line_map_realloc reallocator;
>> +  line_map_realloc GTY((callback)) reallocator;
>> 
>>   /* The allocators' function used to know the actual size it
>>      allocated, for a certain allocation size requested.  */
>> -  line_map_round_alloc_size_func round_alloc_size;
>> +  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
>> 
>>   struct location_adhoc_data_map location_adhoc_data_map;
>> 
>> 
>> 
>> 	Jakub
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09  7:12               ` Richard Biener
  2021-11-09  8:07                 ` Iain Sandoe
@ 2021-11-09  9:44                 ` Jakub Jelinek
  2021-11-09 11:32                   ` Jakub Jelinek
  1 sibling, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09  9:44 UTC (permalink / raw)
  To: Richard Biener
  Cc: Iain Sandoe, gcc-patches, John David Anglin, Aldy Hernandez,
	Andrew MacLeod

On Tue, Nov 09, 2021 at 08:12:05AM +0100, Richard Biener wrote:
> > So, here is 1), 2), 3) implemented.  With this patch alone,
> > g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
> > function::x_range_query member, which is set to &global_ranges on
> > cfun creation and is:
> >   range_query * GTY ((skip)) x_range_query;
> > which means when a PIE binary writes PCH and a PIE binary loaded
> > at a different address loads it, cfun->x_range_query might be a garbage
> > pointer.  We can either apply a patch like the attached one after
> > this inline patch, but then probably callback is misnamed and we should
> > rename it to relocate_and_skip or something similar.  Or we could
> > e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
> 
> I think struct function allocation should initialize it to NULL and
> the init to &global_ranges be done only when we do init_tree_ssa?
> In fact x_range_query could be moved to the gimple_df substructure
> to make that clear.

Agreed, Andrew/Aldy, what do you think?

> Hopefully PCH happens before init_tree_ssa.

I think it does.

> I'm not keen on further life support for PCH, but then if the work is
> done it's hard to reject it...
> 
> Note there might be still platforms not supporting PCH and so Iains
> patches still look useful to me.

Sure, I think it is fine to opt out of PCH support if needed, just that
PIE shouldn't automatically imply that.

> I also wonder whether we want to require active marking of types
> with PCH support and assert when PCH write runs into objects without?

At least for scalar types I'd prefer not to mark them.
For aggregates, why not, but my gengtype knowledge is very limited,
it has been a pain to add the TYPE_CALLBACK stuff in there already...

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-08 21:03               ` John David Anglin
@ 2021-11-09  9:50                 ` Jakub Jelinek
  0 siblings, 0 replies; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09  9:50 UTC (permalink / raw)
  To: John David Anglin
  Cc: Iain Sandoe, Richard Biener, gcc-patches, Aldy Hernandez, Andrew MacLeod

On Mon, Nov 08, 2021 at 04:03:09PM -0500, John David Anglin wrote:
> On 2021-11-08 2:48 p.m., Jakub Jelinek wrote:
> > Not really sure about PA or IA-64 function descriptors, are any of those
> > allocated by the dynamic linker rather than created by the static linker?
> On PA, the static linker creates all function descriptors.  The dynamic linker is responsible for
> resolving descriptors when lazy binding is used.
> 
> The primary difference between 32 and 64-bit descriptors is that there can be multiple descriptors
> that resolve to the same function in the 32-bit run time.  In the 64-bit case, there is one official
> procedure descriptor for each function.

What I (or the PCH patch I've posted) cares about is if one does:
int foo () { return 1; }
int bar () { return 2; }
int v1, v2;
int
main ()
{
  __builtin_printf ("%p %p %p %p\n", (void *) &foo, (void *) &bar, &v1, &v2);
  return 0;
}
whether either the addresses are always the same (non-relocatable binary),
or they differ, but the differences between say the first address and the
other addresses are the same all the time (i.e. if one does what the patch
is doing,
+  if (pch_save != &gt_pch_save)
+    {
+      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
		 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+      void **ptrs = XNEWVEC (void *, num_callbacks);
+      unsigned i;
+    
+      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
+       fatal_error (input_location, "cannot read PCH file: %m");
+      for (i = 0; i < num_callbacks; ++i)
+       {
+         memcpy (&pch_save, ptrs[i], sizeof (pch_save));
+         pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+         memcpy (ptrs[i], &pch_save, sizeof (pch_save));
+       }
+      XDELETE (ptrs);
+    }
whether it will work correctly.
If there are any hosts where it wouldn't, we'd need to disable PCH or at
least PCH with different load bias on such host.

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09  9:44                 ` Jakub Jelinek
@ 2021-11-09 11:32                   ` Jakub Jelinek
  2021-11-09 12:03                     ` Richard Biener
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09 11:32 UTC (permalink / raw)
  To: Richard Biener, gcc-patches, John David Anglin, Iain Sandoe

On Tue, Nov 09, 2021 at 10:44:45AM +0100, Jakub Jelinek via Gcc-patches wrote:
> On Tue, Nov 09, 2021 at 08:12:05AM +0100, Richard Biener wrote:
> > > So, here is 1), 2), 3) implemented.  With this patch alone,
> > > g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
> > > function::x_range_query member, which is set to &global_ranges on
> > > cfun creation and is:
> > >   range_query * GTY ((skip)) x_range_query;
> > > which means when a PIE binary writes PCH and a PIE binary loaded
> > > at a different address loads it, cfun->x_range_query might be a garbage
> > > pointer.  We can either apply a patch like the attached one after
> > > this inline patch, but then probably callback is misnamed and we should
> > > rename it to relocate_and_skip or something similar.  Or we could
> > > e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
> > 
> > I think struct function allocation should initialize it to NULL and
> > the init to &global_ranges be done only when we do init_tree_ssa?
> > In fact x_range_query could be moved to the gimple_df substructure
> > to make that clear.
> 
> Agreed, Andrew/Aldy, what do you think?
> 
> > Hopefully PCH happens before init_tree_ssa.
> 
> I think it does.

Unfortunately, seems cfun->x_range_query is used already in the FEs :(.

I was trying:

--- gcc/function.h.jj	2021-08-31 22:55:23.072795814 +0200
+++ gcc/function.h	2021-11-09 11:33:22.656779018 +0100
@@ -312,8 +312,9 @@ struct GTY(()) function {
 
   /* Range query mechanism for functions.  The default is to pick up
      global ranges.  If a pass wants on-demand ranges OTOH, it must
-     call enable/disable_ranger().  The pointer is never null.  It
-     should be queried by calling get_range_query().  */
+     call enable/disable_ranger().  The pointer is never null in between
+     init_tree_ssa and delete_tree_ssa.  It should be queried by calling
+     get_range_query().  */
   range_query * GTY ((skip)) x_range_query;
 
   /* Last statement uid.  */
--- gcc/function.c.jj	2021-07-20 22:31:11.088835781 +0200
+++ gcc/function.c	2021-11-09 11:33:47.695424319 +0100
@@ -4873,8 +4873,6 @@ allocate_struct_function (tree fndecl, b
      binding annotations among them.  */
   cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
     && MAY_HAVE_DEBUG_MARKER_STMTS;
-
-  cfun->x_range_query = &global_ranges;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
--- gcc/tree-ssa.c.jj	2021-11-03 23:02:44.367985554 +0100
+++ gcc/tree-ssa.c	2021-11-09 12:02:07.095351378 +0100
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.
 #include "stringpool.h"
 #include "attribs.h"
 #include "asan.h"
+#include "value-query.h"
 
 /* Pointer map of variable mappings, keyed by edge.  */
 static hash_map<edge, auto_vec<edge_var_map> > *edge_var_maps;
@@ -1224,6 +1225,7 @@ init_tree_ssa (struct function *fn, int
 {
   fn->gimple_df = ggc_cleared_alloc<gimple_df> ();
   fn->gimple_df->default_defs = hash_table<ssa_name_hasher>::create_ggc (20);
+  fn->x_range_query = &global_ranges;
   pt_solution_reset (&fn->gimple_df->escaped);
   init_ssanames (fn, size);
 }
@@ -1246,6 +1248,7 @@ delete_tree_ssa (struct function *fn)
     delete fn->gimple_df->decls_to_pointers;
   fn->gimple_df->decls_to_pointers = NULL;
   fn->gimple_df = NULL;
+  fn->x_range_query = NULL;
 
   /* We no longer need the edge variable maps.  */
   redirect_edge_var_map_empty ();

but that ICEs with:
#0  0x0000555556d27348 in get_range (val=val@entry=0x7fffe9f8c2d0, stmt=0x7fffffffbb80, stmt@entry=0x0, minmax=minmax@entry=0x7fffffffbc10, rvals=0x0)
    at ../../gcc/tree-ssa-strlen.c:217
#1  0x0000555556a2fe73 in get_offset_range (x=0x7fffe9f8c2d0, stmt=0x0, r=0x7fffffffbd70, rvals=<optimized out>) at ../../gcc/pointer-query.cc:92
#2  0x0000555556a33d3e in handle_array_ref (aref=0x7fffe7e17620, addr=<optimized out>, ostype=1, pref=0x7fffffffc000, snlim=..., qry=<optimized out>, stmt=<optimized out>)
    at ../../gcc/pointer-query.cc:1621
#3  0x0000555556a3669d in compute_objsize (ptr=0x7fffe81b3100, stmt=<optimized out>, ostype=1, pref=0x7fffffffc000, ptr_qry=0x7fffffffbf00) at ../../gcc/pointer-query.cc:2154
#4  0x0000555556a368e4 in compute_objsize (ptr=ptr@entry=0x7fffe81b3100, stmt=stmt@entry=0x0, ostype=ostype@entry=1, pref=pref@entry=0x7fffffffc000, rvals=rvals@entry=0x0)
    at ../../gcc/pointer-query.cc:2172
#5  0x0000555556383f09 in compute_objsize (pref=0x7fffffffc000, ostype=1, ptr=0x7fffe81b3100) at ../../gcc/pointer-query.h:262
#6  warn_placement_new_too_small (type=0x7fffe9f8a3f0, nelts=0x7fffe81b3160, size=0x7fffe9f8c108, oper=0x7fffe81b3100) at ../../gcc/cp/init.c:2621
#7  0x000055555638cf9e in build_new_1 (placement=<optimized out>, type=0x7fffe9f8a3f0, nelts=<optimized out>, init=0x7fffffffc3d0, globally_qualified_p=<optimized out>, complain=3)
    at ../../gcc/cp/init.c:3287
#8  0x000055555638dd92 in build_new (loc=<optimized out>, placement=placement@entry=0x7fffffffc3c8, type=<optimized out>, type@entry=0x7fffe9f8a3f0, nelts=0x7fffe81b3160, 
    nelts@entry=0x7fffe81b3120, init=init@entry=0x7fffffffc3d0, use_global_new=use_global_new@entry=0, complain=3) at ../../gcc/cp/init.c:3838

Apparently the range_of_expr can handle some tree cases through
range_query::get_tree_range, like INTEGER_CSTs, ADDR_EXPRs,
and some binary and unary ops.

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09  8:07                 ` Iain Sandoe
@ 2021-11-09 11:40                   ` Iain Sandoe
  2021-11-09 12:18                     ` Jakub Jelinek
  0 siblings, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-09 11:40 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: GCC Patches, John David Anglin, Aldy Hernandez, Andrew MacLeod,
	Richard Biener



> On 9 Nov 2021, at 08:07, Iain Sandoe <iain@sandoe.co.uk> wrote:
> 
> 
> 
>> On 9 Nov 2021, at 07:12, Richard Biener <rguenther@suse.de> wrote:
>> 
>> On Mon, 8 Nov 2021, Jakub Jelinek wrote:
>> 
>>> On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
>>>> So, if we want to make PCH work for PIEs, I'd say we can:
>>>> 1) add a new GTY option, say callback, which would act like
>>>>  skip for non-PCH and for PCH would make us skip it but
>>>>  remember for address bias translation
>>>> 2) drop the skip for tree_translation_unit_decl::language
>>>> 3) change get_unnamed_section to have const char * as
>>>>  last argument instead of const void *, change
>>>>  unnamed_section::data also to const char * and update
>>>>  everything related to that
>>>> 4) maybe add a host hook whether it is ok to support binaries
>>>>  changing addresses (the only thing I'm worried is if
>>>>  some host that uses function descriptors allocates them
>>>>  dynamically instead of having them somewhere in the
>>>>  executable)
>>>> 5) maybe add a gengtype warning if it sees in GTY tracked
>>>>  structure a function pointer without that new callback
>>>>  option
>>> 
>>> So, here is 1), 2), 3) implemented.  With this patch alone,
>>> g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
>>> function::x_range_query member, which is set to &global_ranges on
>>> cfun creation and is:
>>> range_query * GTY ((skip)) x_range_query;
>>> which means when a PIE binary writes PCH and a PIE binary loaded
>>> at a different address loads it, cfun->x_range_query might be a garbage
>>> pointer.  We can either apply a patch like the attached one after
>>> this inline patch, but then probably callback is misnamed and we should
>>> rename it to relocate_and_skip or something similar.  Or we could
>>> e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
>> 
>> I think struct function allocation should initialize it to NULL and
>> the init to &global_ranges be done only when we do init_tree_ssa?
>> In fact x_range_query could be moved to the gimple_df substructure
>> to make that clear.
>> 
>> Hopefully PCH happens before init_tree_ssa.
>> 
>>> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.
>>> 
>>> Not really sure about PA or IA-64 function descriptors, are any of those
>>> allocated by the dynamic linker rather than created by the static linker?
>>> I guess instead of removing the c-pch.c changes we could remember there
>>> not just a function pointer, but also a data pointer and compare if both
>>> are either the same or have the same load bias and punt only if they
>>> have different bias.  Though, on architecture where all function pointers
>>> would be dynamically allocated and could change any time even that wouldn't
>>> be really a reliable check.
>>> 
>>> Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
>>> the second patch, with it a few more, but nothing huge.  And for non-PIEs
>>> there isn't really any extra work on the load side except freading two scalar
>>> values and fseek.
>>> 
>>> Thoughts on this?
> 
> - thanks for doing it, I still think a working solution is better than a disable.
> 
> - This would be a fix for PR 71934
> 
> - I applied the patches on Darwin and there’s still some case(s) to find and fix
>  cc1/cc1plus hang on pch input, when any diagnostic is emitted (doing some
>  linemap lookup) .. hopefully, I can find some time to figure out what is not 
>  happy.

There were two issues, of which one remains and probably affects all targets.

1.  The Darwin PCH memory allocation scheme used a system that works reliably
    for no-PIE but not for PIE

.. I hacked in a similar scheme to the mmap one used on Linux .. the suspect stuff
   there is in choosing some place in the map that is likely to succeed…

  With that I get passes on all c-family pch.exp (I didn’t try to bootstrap).

2. This problem remains.

  - if we try to emit a diagnostic when the PCH read-in has failed, it seems that
   cc1 hangs somewhere in trying to lookup line table info.

 - this was happening with the Darwin fixed PCH memory address because it
   was trying to report a fatal error in being unable to read the file (or trying to
  execute fancy_abort, in response to a segv).

.. I didn’t try this on Linux - but I would imagine it would be quick to see if the
   problem manifests, one would only need to simulate an error.

Iain

> 
>> I'm not keen on further life support for PCH, but then if the work is
>> done it's hard to reject it...
>> 
>> Note there might be still platforms not supporting PCH and so Iains
>> patches still look useful to me.
> 
> Yeah, what would be most useful at this stage is some way to get those
> tested against some wider set of package builds to see if anything fires
> that breaks stuff.
> 
>> I also wonder whether we want to require active marking of types
>> with PCH support and assert when PCH write runs into objects without?
> 
> anything that makes GTY markup more robust is a Good Idea.
> Iain
> 
>> 
>> Richard.
>> 
>>> 2021-11-08  Jakub Jelinek  <jakub@redhat.com>
>>> 
>>> gcc/
>>> 	* ggc.h (gt_pch_note_callback): Declare.
>>> 	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
>>> 	(callback_type): Declare.
>>> 	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
>>> 	(callback_type): New variable.
>>> 	(process_gc_options): Add CALLBACK argument, handle callback
>>> 	option.
>>> 	(set_gc_used_type): Adjust process_gc_options caller, if callback,
>>> 	set type to &callback_type.
>>> 	(output_mangled_typename): Handle TYPE_CALLBACK.
>>> 	(walk_type): Likewise.  Handle callback option.
>>> 	(write_types_process_field): Handle TYPE_CALLBACK.
>>> 	(write_types_local_user_process_field): Likewise.
>>> 	(write_types_local_process_field): Likewise.
>>> 	(write_root): Likewise.
>>> 	(dump_typekind): Likewise.
>>> 	(dump_type): Likewise.
>>> 	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
>>> 	(state_writer::write_state_callback_type): New method.
>>> 	(state_writer::write_state_type): Handle TYPE_CALLBACK.
>>> 	(read_state_callback_type): New function.
>>> 	(read_state_type): Handle TYPE_CALLBACK.
>>> 	* ggc-common.c (callback_vec): New variable.
>>> 	(gt_pch_note_callback): New function.
>>> 	(gt_pch_save): Stream out gt_pch_save function address and relocation
>>> 	table.
>>> 	(gt_pch_restore): Stream in saved gt_pch_save function address and
>>> 	relocation table and apply relocations if needed.
>>> 	* doc/gty.texi (callback): Document new GTY option.
>>> 	* varasm.c (get_unnamed_section): Change callback argument's type and
>>> 	last argument's type from const void * to const char *.
>>> 	(output_section_asm_op): Change argument's type from const void *
>>> 	to const char *, remove unnecessary cast.
>>> 	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
>>> 	from language member.
>>> 	* output.h (unnamed_section_callback): Change argument type from
>>> 	const void * to const char *.
>>> 	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
>>> 	for callback member.  Change data member type from const void *
>>> 	to const char *.
>>> 	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
>>> 	for callback member.
>>> 	(get_unnamed_section): Change callback argument's type and
>>> 	last argument's type from const void * to const char *.
>>> 	(output_section_asm_op): Change argument's type from const void *
>>> 	to const char *.
>>> 	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
>>> 	Remove unneeded cast.
>>> 	* config/darwin.c (output_objc_section_asm_op): Change argument's type
>>> 	from const void * to const char *.
>>> 	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
>>> 	(som_output_comdat_data_section_asm_op): Likewise.
>>> 	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
>>> 	Likewise.
>>> 	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
>>> 	of dereferencing directive hardcode variable names and decide based on
>>> 	whether directive is NULL or not.
>>> 	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
>>> 	from const void * to const char *.
>>> 	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
>>> 	of dereferencing directive hardcode variable names and decide based on
>>> 	whether directive is NULL or not.
>>> 	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
>>> 	from const void * to const char *.
>>> 	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
>>> gcc/c-family/
>>> 	* c-pch.c (struct c_pch_validity): Remove pch_init member.
>>> 	(pch_init): Don't initialize v.pch_init.
>>> 	(c_common_valid_pch): Don't warn and punt if .text addresses change.
>>> libcpp/
>>> 	* include/line-map.h (class line_maps): Add GTY((callback)) to
>>> 	reallocator and round_alloc_size members.
>>> 
>>> --- gcc/ggc.h.jj	2021-08-19 11:42:27.366422386 +0200
>>> +++ gcc/ggc.h	2021-11-08 16:46:02.604618109 +0100
>>> @@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void
>>> /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
>>> extern int gt_pch_note_object (void *, void *, gt_note_pointers);
>>> 
>>> +/* Used by the gt_pch_p_* routines.  Register address of a callback
>>> +   pointer.  */
>>> +extern void gt_pch_note_callback (void *, void *);
>>> +
>>> /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
>>>   function.  */
>>> extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
>>> --- gcc/gengtype.h.jj	2021-07-20 10:08:09.892687719 +0200
>>> +++ gcc/gengtype.h	2021-11-08 15:19:59.194210185 +0100
>>> @@ -154,6 +154,9 @@ enum typekind {
>>>  TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
>>>  TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
>>>  TYPE_ARRAY,           /* Array of GTY-ed types.  */
>>> +  TYPE_CALLBACK,	/* A function pointer that needs relocation if
>>> +			   the executable has been loaded at a different
>>> +			   address.  */
>>>  TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
>>>                           Various languages may have homonymous but
>>>                           different structs.  */
>>> @@ -331,6 +334,9 @@ extern struct type string_type;
>>> extern struct type scalar_nonchar;
>>> extern struct type scalar_char;
>>> 
>>> +/* The one and only TYPE_CALLBACK.  */
>>> +extern struct type callback_type;
>>> +
>>> /* Test if a type is a union, either a plain one or a language
>>>   specific one.  */
>>> #define UNION_P(x)					\
>>> --- gcc/gengtype.c.jj	2021-10-04 10:16:10.885140187 +0200
>>> +++ gcc/gengtype.c	2021-11-08 16:30:41.981750183 +0100
>>> @@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil,
>>>  int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
>>>  int nb_lang_struct = 0;
>>>  int nb_user_struct = 0, nb_undefined = 0;
>>> +  int nb_callback = 0;
>>>  type_p p = NULL;
>>>  for (p = t; p; p = p->next)
>>>    {
>>> @@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil,
>>> 	case TYPE_ARRAY:
>>> 	  nb_array++;
>>> 	  break;
>>> +	case TYPE_CALLBACK:
>>> +	  nb_callback++;
>>> +	  break;
>>> 	case TYPE_LANG_STRUCT:
>>> 	  nb_lang_struct++;
>>> 	  break;
>>> @@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil,
>>>    fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
>>>  if (nb_pointer > 0 || nb_array > 0)
>>>    fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
>>> +  if (nb_callback > 0)
>>> +    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
>>>  if (nb_lang_struct > 0)
>>>    fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
>>>  if (nb_user_struct > 0)
>>> @@ -495,6 +501,10 @@ struct type scalar_char = {
>>>  TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
>>> };
>>> 
>>> +struct type callback_type = {
>>> +  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
>>> +};
>>> +
>>> /* Lists of various things.  */
>>> 
>>> pair_p typedefs = NULL;
>>> @@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
>>> 
>>> static void
>>> process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
>>> -		    int *length, int *skip, type_p *nested_ptr)
>>> +		    int *length, int *skip, int *callback, type_p *nested_ptr)
>>> {
>>>  options_p o;
>>>  for (o = opt; o; o = o->next)
>>> @@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum
>>>      *length = 1;
>>>    else if (strcmp (o->name, "skip") == 0)
>>>      *skip = 1;
>>> +    else if (strcmp (o->name, "callback") == 0)
>>> +      *callback = 1;
>>>    else if (strcmp (o->name, "nested_ptr") == 0
>>> 	     && o->kind == OPTION_NESTED)
>>>      *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
>>> @@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used
>>> 	type_p dummy2;
>>> 	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
>>> 
>>> -	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
>>> +	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
>>> 			    &dummy2);
>>> 
>>> 	if (t->u.s.base_class)
>>> @@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used
>>> 	    int maybe_undef = 0;
>>> 	    int length = 0;
>>> 	    int skip = 0;
>>> +	    int callback = 0;
>>> 	    type_p nested_ptr = NULL;
>>> 	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
>>> -				&nested_ptr);
>>> +				&callback, &nested_ptr);
>>> 
>>> 	    if (nested_ptr && f->type->kind == TYPE_POINTER)
>>> 	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
>>> @@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used
>>> 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
>>> 	    else if (skip)
>>> 	      ;			/* target type is not used through this field */
>>> +	    else if (callback)
>>> +	      f->type = &callback_type;
>>> 	    else
>>> 	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
>>> 	  }
>>> @@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, cons
>>>      {
>>>      case TYPE_NONE:
>>>      case TYPE_UNDEFINED:
>>> +      case TYPE_CALLBACK:
>>> 	gcc_unreachable ();
>>> 	break;
>>>      case TYPE_POINTER:
>>> @@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_da
>>>      ;
>>>    else if (strcmp (oo->name, "for_user") == 0)
>>>      ;
>>> +    else if (strcmp (oo->name, "callback") == 0)
>>> +      ;
>>>    else
>>>      error_at_line (d->line, "unknown option `%s'\n", oo->name);
>>> 
>>> @@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_da
>>>    {
>>>    case TYPE_SCALAR:
>>>    case TYPE_STRING:
>>> +    case TYPE_CALLBACK:
>>>      d->process_field (t, d);
>>>      break;
>>> 
>>> @@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, con
>>>      break;
>>> 
>>>    case TYPE_SCALAR:
>>> +    case TYPE_CALLBACK:
>>>      break;
>>> 
>>>    case TYPE_ARRAY:
>>> @@ -3820,6 +3840,7 @@ write_types_local_user_process_field (ty
>>>      break;
>>> 
>>>    case TYPE_SCALAR:
>>> +    case TYPE_CALLBACK:
>>>      break;
>>> 
>>>    case TYPE_ARRAY:
>>> @@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p
>>>    case TYPE_SCALAR:
>>>      break;
>>> 
>>> +    case TYPE_CALLBACK:
>>> +      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
>>> +	       d->prev_val[3]);
>>> +      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
>>> +	       d->indent, "", d->val);
>>> +      break;
>>> +
>>>    case TYPE_ARRAY:
>>>    case TYPE_NONE:
>>>    case TYPE_UNDEFINED:
>>> @@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p t
>>>    case TYPE_UNDEFINED:
>>>    case TYPE_UNION:
>>>    case TYPE_LANG_STRUCT:
>>> +    case TYPE_CALLBACK:
>>>      error_at_line (line, "global `%s' is unimplemented type", name);
>>>    }
>>> }
>>> @@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind
>>>    case TYPE_ARRAY:
>>>      printf ("TYPE_ARRAY");
>>>      break;
>>> +    case TYPE_CALLBACK:
>>> +      printf ("TYPE_CALLBACK");
>>> +      break;
>>>    case TYPE_LANG_STRUCT:
>>>      printf ("TYPE_LANG_STRUCT");
>>>      break;
>>> @@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
>>> 	      t->u.scalar_is_char ? "true" : "false");
>>>      break;
>>>    case TYPE_STRING:
>>> +    case TYPE_CALLBACK:
>>>      break;
>>>    case TYPE_STRUCT:
>>>    case TYPE_UNION:
>>> --- gcc/varasm.c.jj	2021-09-28 11:34:29.343147261 +0200
>>> +++ gcc/varasm.c	2021-11-08 13:26:15.032606040 +0100
>>> @@ -250,8 +250,8 @@ object_block_hasher::hash (object_block
>>> /* Return a new unnamed section with the given fields.  */
>>> 
>>> section *
>>> -get_unnamed_section (unsigned int flags, void (*callback) (const void *),
>>> -		     const void *data)
>>> +get_unnamed_section (unsigned int flags, void (*callback) (const char *),
>>> +		     const char *data)
>>> {
>>>  section *sect;
>>> 
>>> @@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
>>>   a get_unnamed_section callback.  */
>>> 
>>> void
>>> -output_section_asm_op (const void *directive)
>>> +output_section_asm_op (const char *directive)
>>> {
>>> -  fprintf (asm_out_file, "%s\n", (const char *) directive);
>>> +  fprintf (asm_out_file, "%s\n", directive);
>>> }
>>> 
>>> /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
>>> --- gcc/ggc-common.c.jj	2021-11-08 11:09:50.280318624 +0100
>>> +++ gcc/ggc-common.c	2021-11-08 18:33:51.103390391 +0100
>>> @@ -246,6 +246,7 @@ saving_hasher::equal (const ptr_data *p1
>>> }
>>> 
>>> static hash_table<saving_hasher> *saving_htab;
>>> +static vec<void *> callback_vec;
>>> 
>>> /* Register an object in the hash table.  */
>>> 
>>> @@ -278,6 +279,23 @@ gt_pch_note_object (void *obj, void *not
>>>  return 1;
>>> }
>>> 
>>> +/* Register address of a callback pointer.  */
>>> +void
>>> +gt_pch_note_callback (void *obj, void *base)
>>> +{
>>> +  void *ptr;
>>> +  memcpy (&ptr, obj, sizeof (void *));
>>> +  if (ptr != NULL)
>>> +    {
>>> +      struct ptr_data *data
>>> +	= (struct ptr_data *)
>>> +	  saving_htab->find_with_hash (base, POINTER_HASH (base));
>>> +      gcc_assert (data);
>>> +      callback_vec.safe_push ((char *) data->new_addr
>>> +			      + ((char *) obj - (char *) base));
>>> +    }
>>> +}
>>> +
>>> /* Register an object in the hash table.  */
>>> 
>>> void
>>> @@ -592,10 +610,20 @@ gt_pch_save (FILE *f)
>>>  ggc_pch_finish (state.d, state.f);
>>>  gt_pch_fixup_stringpool ();
>>> 
>>> +  unsigned num_callbacks = callback_vec.length ();
>>> +  void (*pch_save) (FILE *) = &gt_pch_save;
>>> +  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
>>> +      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
>>> +      || (num_callbacks
>>> +	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
>>> +		     f) != num_callbacks))
>>> +    fatal_error (input_location, "cannot write PCH file: %m");
>>> +
>>>  XDELETE (state.ptrs);
>>>  XDELETE (this_object);
>>>  delete saving_htab;
>>>  saving_htab = NULL;
>>> +  callback_vec.release ();
>>> }
>>> 
>>> /* Read the state of the compiler back in from F.  */
>>> @@ -649,6 +677,30 @@ gt_pch_restore (FILE *f)
>>>  ggc_pch_read (f, mmi.preferred_base);
>>> 
>>>  gt_pch_restore_stringpool ();
>>> +
>>> +  void (*pch_save) (FILE *);
>>> +  unsigned num_callbacks;
>>> +  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
>>> +      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
>>> +    fatal_error (input_location, "cannot read PCH file: %m");
>>> +  if (pch_save != &gt_pch_save)
>>> +    {
>>> +      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
>>> +      void **ptrs = XNEWVEC (void *, num_callbacks);
>>> +      unsigned i;
>>> +
>>> +      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
>>> +	fatal_error (input_location, "cannot read PCH file: %m");
>>> +      for (i = 0; i < num_callbacks; ++i)
>>> +	{
>>> +	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
>>> +	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
>>> +	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
>>> +	}
>>> +      XDELETE (ptrs);
>>> +    }
>>> +  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
>>> +    fatal_error (input_location, "cannot read PCH file: %m");
>>> }
>>> 
>>> /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
>>> --- gcc/doc/gty.texi.jj	2021-08-19 11:42:27.363422428 +0200
>>> +++ gcc/doc/gty.texi	2021-11-08 17:13:46.613882767 +0100
>>> @@ -197,6 +197,15 @@ If @code{skip} is applied to a field, th
>>> This is somewhat dangerous; the only safe use is in a union when one
>>> field really isn't ever used.
>>> 
>>> +@findex callback
>>> +@item callback
>>> +
>>> +@code{callback} should be applied to fields with pointer to function type
>>> +and causes the field to be ignored similarly to @code{skip}, except when
>>> +writing PCH and the field is non-NULL it will remember the field's address
>>> +for relocation purposes if the process writing PCH has different load base
>>> +from a process reading PCH.
>>> +
>>> @findex for_user
>>> @item for_user
>>> 
>>> --- gcc/tree-core.h.jj	2021-11-04 12:27:02.377298411 +0100
>>> +++ gcc/tree-core.h	2021-11-08 13:24:04.496465555 +0100
>>> @@ -1964,7 +1964,7 @@ struct GTY(()) tree_function_decl {
>>> struct GTY(()) tree_translation_unit_decl {
>>>  struct tree_decl_common common;
>>>  /* Source language of this translation unit.  Used for DWARF output.  */
>>> -  const char * GTY((skip(""))) language;
>>> +  const char *language;
>>>  /* TODO: Non-optimization used to build this translation unit.  */
>>>  /* TODO: Root of a partial DWARF tree for global types and decls.  */
>>> };
>>> --- gcc/gengtype-state.c.jj	2021-07-20 10:08:09.891687732 +0200
>>> +++ gcc/gengtype-state.c	2021-11-08 15:19:16.157824146 +0100
>>> @@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
>>>    case TYPE_STRING:
>>>    case TYPE_POINTER:
>>>    case TYPE_ARRAY:
>>> +    case TYPE_CALLBACK:
>>>      return NULL;
>>>    default:
>>>      gcc_unreachable ();
>>> @@ -171,6 +172,7 @@ private:
>>>  void write_state_version (const char *version);
>>>  void write_state_scalar_type (type_p current);
>>>  void write_state_string_type (type_p current);
>>> +  void write_state_callback_type (type_p current);
>>>  void write_state_undefined_type (type_p current);
>>>  void write_state_struct_union_type (type_p current, const char *kindstr);
>>>  void write_state_struct_type (type_p current);
>>> @@ -898,6 +900,20 @@ state_writer::write_state_string_type (t
>>>    fatal ("Unexpected type in write_state_string_type");
>>> }
>>> 
>>> +/* Write the callback type.  There is only one such thing! */
>>> +void
>>> +state_writer::write_state_callback_type (type_p current)
>>> +{
>>> +  if (current == &callback_type)
>>> +    {
>>> +      write_any_indent (0);
>>> +      fprintf (state_file, "callback ");
>>> +      write_state_common_type_content (current);
>>> +    }
>>> +  else
>>> +    fatal ("Unexpected type in write_state_callback_type");
>>> +}
>>> +
>>> /* Write an undefined type.  */
>>> void
>>> state_writer::write_state_undefined_type (type_p current)
>>> @@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p c
>>> 	case TYPE_STRING:
>>> 	  write_state_string_type (current);
>>> 	  break;
>>> +	case TYPE_CALLBACK:
>>> +	  write_state_callback_type (current);
>>> +	  break;
>>> 	}
>>>    }
>>> 
>>> @@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
>>>  read_state_common_type_content (*type);
>>> }
>>> 
>>> +/* Read the callback_type.  */
>>> +static void
>>> +read_state_callback_type (type_p *type)
>>> +{
>>> +  *type = &callback_type;
>>> +  read_state_common_type_content (*type);
>>> +}
>>> +
>>> 
>>> /* Read a lang_bitmap representing a set of GCC front-end languages.  */
>>> static void
>>> @@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
>>> 	      next_state_tokens (1);
>>> 	      read_state_string_type (current);
>>> 	    }
>>> +	  else if (state_token_is_name (t0, "callback"))
>>> +	    {
>>> +	      next_state_tokens (1);
>>> +	      read_state_callback_type (current);
>>> +	    }
>>> 	  else if (state_token_is_name (t0, "undefined"))
>>> 	    {
>>> 	      *current = XCNEW (struct type);
>>> --- gcc/output.h.jj	2021-09-28 11:34:29.235148754 +0200
>>> +++ gcc/output.h	2021-11-08 16:26:01.172755377 +0100
>>> @@ -470,7 +470,7 @@ struct GTY(()) named_section {
>>> 
>>> /* A callback that writes the assembly code for switching to an unnamed
>>>   section.  The argument provides callback-specific data.  */
>>> -typedef void (*unnamed_section_callback) (const void *);
>>> +typedef void (*unnamed_section_callback) (const char *);
>>> 
>>> /* Information about a SECTION_UNNAMED section.  */
>>> struct GTY(()) unnamed_section {
>>> @@ -478,8 +478,8 @@ struct GTY(()) unnamed_section {
>>> 
>>>  /* The callback used to switch to the section, and the data that
>>>     should be passed to the callback.  */
>>> -  unnamed_section_callback GTY ((skip)) callback;
>>> -  const void *GTY ((skip)) data;
>>> +  unnamed_section_callback GTY ((callback)) callback;
>>> +  const char *data;
>>> 
>>>  /* The next entry in the chain of unnamed sections.  */
>>>  section *next;
>>> @@ -503,7 +503,7 @@ struct GTY(()) noswitch_section {
>>>  struct section_common common;
>>> 
>>>  /* The callback used to assemble decls in this section.  */
>>> -  noswitch_section_callback GTY ((skip)) callback;
>>> +  noswitch_section_callback GTY ((callback)) callback;
>>> };
>>> 
>>> /* Information about a section, which may be named or unnamed.  */
>>> @@ -538,8 +538,8 @@ extern GTY(()) section *bss_noswitch_sec
>>> extern GTY(()) section *in_section;
>>> extern GTY(()) bool in_cold_section_p;
>>> 
>>> -extern section *get_unnamed_section (unsigned int, void (*) (const void *),
>>> -				     const void *);
>>> +extern section *get_unnamed_section (unsigned int, void (*) (const char *),
>>> +				     const char *);
>>> extern section *get_section (const char *, unsigned int, tree,
>>> 			     bool not_existing = false);
>>> extern section *get_named_section (tree, const char *, int);
>>> @@ -561,7 +561,7 @@ extern section *get_cdtor_priority_secti
>>> 
>>> extern bool unlikely_text_section_p (section *);
>>> extern void switch_to_section (section *, tree = nullptr);
>>> -extern void output_section_asm_op (const void *);
>>> +extern void output_section_asm_op (const char *);
>>> 
>>> extern void record_tm_clone_pair (tree, tree);
>>> extern void finish_tm_clone_pairs (void);
>>> --- gcc/config/avr/avr.c.jj	2021-07-15 10:16:12.873583249 +0200
>>> +++ gcc/config/avr/avr.c	2021-11-08 13:28:30.215676387 +0100
>>> @@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const voi
>>> /* Unnamed section callback for progmem*.data sections.  */
>>> 
>>> static void
>>> -avr_output_progmem_section_asm_op (const void *data)
>>> +avr_output_progmem_section_asm_op (const char *data)
>>> {
>>> -  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
>>> -           (const char*) data);
>>> +  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
>>> }
>>> 
>>> 
>>> --- gcc/config/darwin.c.jj	2021-10-21 10:23:27.450834602 +0200
>>> +++ gcc/config/darwin.c	2021-11-08 13:27:19.106691421 +0100
>>> @@ -134,7 +134,7 @@ int emit_aligned_common = false;
>>>   DIRECTIVE is as for output_section_asm_op.  */
>>> 
>>> static void
>>> -output_objc_section_asm_op (const void *directive)
>>> +output_objc_section_asm_op (const char *directive)
>>> {
>>>  static bool been_here = false;
>>> 
>>> --- gcc/config/pa/pa.c.jj	2021-10-27 09:00:28.762277456 +0200
>>> +++ gcc/config/pa/pa.c	2021-11-08 13:29:41.935652629 +0100
>>> @@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t
>>>   to the default text subspace.  */
>>> 
>>> static void
>>> -som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>>> +som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>>> {
>>>  gcc_assert (TARGET_SOM);
>>>  if (TARGET_GAS)
>>> @@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const vo
>>>   sections.  This function is only used with SOM.  */
>>> 
>>> static void
>>> -som_output_comdat_data_section_asm_op (const void *data)
>>> +som_output_comdat_data_section_asm_op (const char *data)
>>> {
>>>  in_section = NULL;
>>>  output_section_asm_op (data);
>>> --- gcc/config/rs6000/rs6000.c.jj	2021-11-05 00:43:22.476626062 +0100
>>> +++ gcc/config/rs6000/rs6000.c	2021-11-08 13:43:22.415940789 +0100
>>> @@ -20597,7 +20597,7 @@ rs6000_ms_bitfield_layout_p (const_tree
>>> /* A get_unnamed_section callback, used for switching to toc_section.  */
>>> 
>>> static void
>>> -rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>>> +rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>>> {
>>>  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>>>      && TARGET_MINIMAL_TOC)
>>> @@ -21301,35 +21301,39 @@ rs6000_xcoff_asm_globalize_label (FILE *
>>>   points to the section string variable.  */
>>> 
>>> static void
>>> -rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
>>> +rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
>>> {
>>>  fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
>>> -	   *(const char *const *) directive,
>>> +	   directive
>>> +	   ? xcoff_private_rodata_section_name
>>> +	   : xcoff_read_only_section_name,
>>> 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>>> }
>>> 
>>> /* Likewise for read-write sections.  */
>>> 
>>> static void
>>> -rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
>>> +rs6000_xcoff_output_readwrite_section_asm_op (const char *)
>>> {
>>>  fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
>>> -	   *(const char *const *) directive,
>>> +	   xcoff_private_data_section_name,
>>> 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>>> }
>>> 
>>> static void
>>> -rs6000_xcoff_output_tls_section_asm_op (const void *directive)
>>> +rs6000_xcoff_output_tls_section_asm_op (const char *directive)
>>> {
>>>  fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
>>> -	   *(const char *const *) directive,
>>> +	   directive
>>> +	   ? xcoff_private_data_section_name
>>> +	   : xcoff_tls_data_section_name,
>>> 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>>> }
>>> 
>>> /* A get_unnamed_section callback, used for switching to toc_section.  */
>>> 
>>> static void
>>> -rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
>>> +rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>>> {
>>>  if (TARGET_MINIMAL_TOC)
>>>    {
>>> @@ -21356,26 +21360,26 @@ rs6000_xcoff_asm_init_sections (void)
>>> {
>>>  read_only_data_section
>>>    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
>>> -			   &xcoff_read_only_section_name);
>>> +			   NULL);
>>> 
>>>  private_data_section
>>>    = get_unnamed_section (SECTION_WRITE,
>>> 			   rs6000_xcoff_output_readwrite_section_asm_op,
>>> -			   &xcoff_private_data_section_name);
>>> +			   NULL);
>>> 
>>>  read_only_private_data_section
>>>    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
>>> -			   &xcoff_private_rodata_section_name);
>>> +			   "");
>>> 
>>>  tls_data_section
>>>    = get_unnamed_section (SECTION_TLS,
>>> 			   rs6000_xcoff_output_tls_section_asm_op,
>>> -			   &xcoff_tls_data_section_name);
>>> +			   NULL);
>>> 
>>>  tls_private_data_section
>>>    = get_unnamed_section (SECTION_TLS,
>>> 			   rs6000_xcoff_output_tls_section_asm_op,
>>> -			   &xcoff_private_data_section_name);
>>> +			   "");
>>> 
>>>  toc_section
>>>    = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
>>> --- gcc/c-family/c-pch.c.jj	2021-06-02 10:08:14.149450407 +0200
>>> +++ gcc/c-family/c-pch.c	2021-11-08 17:34:17.302343697 +0100
>>> @@ -54,7 +54,6 @@ struct c_pch_validity
>>> {
>>>  uint32_t pch_write_symbols;
>>>  signed char match[MATCH_SIZE];
>>> -  void (*pch_init) (void);
>>>  size_t target_data_length;
>>> };
>>> 
>>> @@ -117,7 +116,6 @@ pch_init (void)
>>> 	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
>>>      }
>>>  }
>>> -  v.pch_init = &pch_init;
>>>  target_validity = targetm.get_pch_validity (&v.target_data_length);
>>> 
>>>  if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
>>> @@ -278,19 +276,6 @@ c_common_valid_pch (cpp_reader *pfile, c
>>> 	}
>>>  }
>>> 
>>> -  /* If the text segment was not loaded at the same address as it was
>>> -     when the PCH file was created, function pointers loaded from the
>>> -     PCH will not be valid.  We could in theory remap all the function
>>> -     pointers, but no support for that exists at present.
>>> -     Since we have the same executable, it should only be necessary to
>>> -     check one function.  */
>>> -  if (v.pch_init != &pch_init)
>>> -    {
>>> -      cpp_warning (pfile, CPP_W_INVALID_PCH,
>>> -		   "%s: had text segment at different address", name);
>>> -      return 2;
>>> -    }
>>> -
>>>  /* Check the target-specific validity data.  */
>>>  {
>>>    void *this_file_data = xmalloc (v.target_data_length);
>>> --- libcpp/include/line-map.h.jj	2021-11-01 14:37:06.697853154 +0100
>>> +++ libcpp/include/line-map.h	2021-11-08 16:16:34.562837006 +0100
>>> @@ -803,11 +803,11 @@ public:
>>>  unsigned int max_column_hint;
>>> 
>>>  /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
>>> -  line_map_realloc reallocator;
>>> +  line_map_realloc GTY((callback)) reallocator;
>>> 
>>>  /* The allocators' function used to know the actual size it
>>>     allocated, for a certain allocation size requested.  */
>>> -  line_map_round_alloc_size_func round_alloc_size;
>>> +  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
>>> 
>>>  struct location_adhoc_data_map location_adhoc_data_map;
>>> 
>>> 
>>> 
>>> 	Jakub
>>> 
>> 
>> -- 
>> Richard Biener <rguenther@suse.de>
>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>> Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 11:32                   ` Jakub Jelinek
@ 2021-11-09 12:03                     ` Richard Biener
  2021-11-09 12:29                       ` Jakub Jelinek
  0 siblings, 1 reply; 39+ messages in thread
From: Richard Biener @ 2021-11-09 12:03 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, John David Anglin, Iain Sandoe

On Tue, 9 Nov 2021, Jakub Jelinek wrote:

> On Tue, Nov 09, 2021 at 10:44:45AM +0100, Jakub Jelinek via Gcc-patches wrote:
> > On Tue, Nov 09, 2021 at 08:12:05AM +0100, Richard Biener wrote:
> > > > So, here is 1), 2), 3) implemented.  With this patch alone,
> > > > g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
> > > > function::x_range_query member, which is set to &global_ranges on
> > > > cfun creation and is:
> > > >   range_query * GTY ((skip)) x_range_query;
> > > > which means when a PIE binary writes PCH and a PIE binary loaded
> > > > at a different address loads it, cfun->x_range_query might be a garbage
> > > > pointer.  We can either apply a patch like the attached one after
> > > > this inline patch, but then probably callback is misnamed and we should
> > > > rename it to relocate_and_skip or something similar.  Or we could
> > > > e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
> > > 
> > > I think struct function allocation should initialize it to NULL and
> > > the init to &global_ranges be done only when we do init_tree_ssa?
> > > In fact x_range_query could be moved to the gimple_df substructure
> > > to make that clear.
> > 
> > Agreed, Andrew/Aldy, what do you think?
> > 
> > > Hopefully PCH happens before init_tree_ssa.
> > 
> > I think it does.
> 
> Unfortunately, seems cfun->x_range_query is used already in the FEs :(.
> 
> I was trying:
> 
> --- gcc/function.h.jj	2021-08-31 22:55:23.072795814 +0200
> +++ gcc/function.h	2021-11-09 11:33:22.656779018 +0100
> @@ -312,8 +312,9 @@ struct GTY(()) function {
>  
>    /* Range query mechanism for functions.  The default is to pick up
>       global ranges.  If a pass wants on-demand ranges OTOH, it must
> -     call enable/disable_ranger().  The pointer is never null.  It
> -     should be queried by calling get_range_query().  */
> +     call enable/disable_ranger().  The pointer is never null in between
> +     init_tree_ssa and delete_tree_ssa.  It should be queried by calling
> +     get_range_query().  */
>    range_query * GTY ((skip)) x_range_query;
>  
>    /* Last statement uid.  */
> --- gcc/function.c.jj	2021-07-20 22:31:11.088835781 +0200
> +++ gcc/function.c	2021-11-09 11:33:47.695424319 +0100
> @@ -4873,8 +4873,6 @@ allocate_struct_function (tree fndecl, b
>       binding annotations among them.  */
>    cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
>      && MAY_HAVE_DEBUG_MARKER_STMTS;
> -
> -  cfun->x_range_query = &global_ranges;
>  }
>  
>  /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
> --- gcc/tree-ssa.c.jj	2021-11-03 23:02:44.367985554 +0100
> +++ gcc/tree-ssa.c	2021-11-09 12:02:07.095351378 +0100
> @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.
>  #include "stringpool.h"
>  #include "attribs.h"
>  #include "asan.h"
> +#include "value-query.h"
>  
>  /* Pointer map of variable mappings, keyed by edge.  */
>  static hash_map<edge, auto_vec<edge_var_map> > *edge_var_maps;
> @@ -1224,6 +1225,7 @@ init_tree_ssa (struct function *fn, int
>  {
>    fn->gimple_df = ggc_cleared_alloc<gimple_df> ();
>    fn->gimple_df->default_defs = hash_table<ssa_name_hasher>::create_ggc (20);
> +  fn->x_range_query = &global_ranges;
>    pt_solution_reset (&fn->gimple_df->escaped);
>    init_ssanames (fn, size);
>  }
> @@ -1246,6 +1248,7 @@ delete_tree_ssa (struct function *fn)
>      delete fn->gimple_df->decls_to_pointers;
>    fn->gimple_df->decls_to_pointers = NULL;
>    fn->gimple_df = NULL;
> +  fn->x_range_query = NULL;
>  
>    /* We no longer need the edge variable maps.  */
>    redirect_edge_var_map_empty ();
> 
> but that ICEs with:
> #0  0x0000555556d27348 in get_range (val=val@entry=0x7fffe9f8c2d0, stmt=0x7fffffffbb80, stmt@entry=0x0, minmax=minmax@entry=0x7fffffffbc10, rvals=0x0)
>     at ../../gcc/tree-ssa-strlen.c:217
> #1  0x0000555556a2fe73 in get_offset_range (x=0x7fffe9f8c2d0, stmt=0x0, r=0x7fffffffbd70, rvals=<optimized out>) at ../../gcc/pointer-query.cc:92
> #2  0x0000555556a33d3e in handle_array_ref (aref=0x7fffe7e17620, addr=<optimized out>, ostype=1, pref=0x7fffffffc000, snlim=..., qry=<optimized out>, stmt=<optimized out>)
>     at ../../gcc/pointer-query.cc:1621
> #3  0x0000555556a3669d in compute_objsize (ptr=0x7fffe81b3100, stmt=<optimized out>, ostype=1, pref=0x7fffffffc000, ptr_qry=0x7fffffffbf00) at ../../gcc/pointer-query.cc:2154
> #4  0x0000555556a368e4 in compute_objsize (ptr=ptr@entry=0x7fffe81b3100, stmt=stmt@entry=0x0, ostype=ostype@entry=1, pref=pref@entry=0x7fffffffc000, rvals=rvals@entry=0x0)
>     at ../../gcc/pointer-query.cc:2172
> #5  0x0000555556383f09 in compute_objsize (pref=0x7fffffffc000, ostype=1, ptr=0x7fffe81b3100) at ../../gcc/pointer-query.h:262
> #6  warn_placement_new_too_small (type=0x7fffe9f8a3f0, nelts=0x7fffe81b3160, size=0x7fffe9f8c108, oper=0x7fffe81b3100) at ../../gcc/cp/init.c:2621
> #7  0x000055555638cf9e in build_new_1 (placement=<optimized out>, type=0x7fffe9f8a3f0, nelts=<optimized out>, init=0x7fffffffc3d0, globally_qualified_p=<optimized out>, complain=3)
>     at ../../gcc/cp/init.c:3287
> #8  0x000055555638dd92 in build_new (loc=<optimized out>, placement=placement@entry=0x7fffffffc3c8, type=<optimized out>, type@entry=0x7fffe9f8a3f0, nelts=0x7fffe81b3160, 
>     nelts@entry=0x7fffe81b3120, init=init@entry=0x7fffffffc3d0, use_global_new=use_global_new@entry=0, complain=3) at ../../gcc/cp/init.c:3838
> 
> Apparently the range_of_expr can handle some tree cases through
> range_query::get_tree_range, like INTEGER_CSTs, ADDR_EXPRs,
> and some binary and unary ops.

But that shouldn't need a range query object ... this was all
available pre-ranger and just got stuffed there for no good reason?

Richard.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 11:40                   ` Iain Sandoe
@ 2021-11-09 12:18                     ` Jakub Jelinek
  2021-11-10  8:14                       ` Iain Sandoe
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09 12:18 UTC (permalink / raw)
  To: Iain Sandoe
  Cc: GCC Patches, John David Anglin, Aldy Hernandez, Andrew MacLeod,
	Richard Biener

On Tue, Nov 09, 2021 at 11:40:08AM +0000, Iain Sandoe wrote:
> There were two issues, of which one remains and probably affects all targets.
> 
> 1.  The Darwin PCH memory allocation scheme used a system that works reliably
>     for no-PIE but not for PIE
> 
> .. I hacked in a similar scheme to the mmap one used on Linux .. the suspect stuff
>    there is in choosing some place in the map that is likely to succeed…
> 
>   With that I get passes on all c-family pch.exp (I didn’t try to bootstrap).

Yeah, certainly.

> 2. This problem remains.
> 
>   - if we try to emit a diagnostic when the PCH read-in has failed, it seems that
>    cc1 hangs somewhere in trying to lookup line table info.
> 
>  - this was happening with the Darwin fixed PCH memory address because it
>    was trying to report a fatal error in being unable to read the file (or trying to
>   execute fancy_abort, in response to a segv).

I guess once we:
  /* Read in all the scalar variables.  */
  for (rt = gt_pch_scalar_rtab; *rt; rt++)
    for (rti = *rt; rti->base != NULL; rti++)
      if (fread (rti->base, rti->stride, 1, f) != 1)
        fatal_error (input_location, "cannot read PCH file: %m");

  /* Read in all the global pointers, in 6 easy loops.  */
  for (rt = gt_ggc_rtab; *rt; rt++)
    for (rti = *rt; rti->base != NULL; rti++)
      for (i = 0; i < rti->nelt; i++)
        if (fread ((char *)rti->base + rti->stride * i,
                   sizeof (void *), 1, f) != 1)
          fatal_error (input_location, "cannot read PCH file: %m");
we overwrite the GTY(()) marked global vars including
extern GTY(()) class line_maps *line_table;
with pointers into the area we haven't mapped yet (or if the error happens
after that mmap but before everything is fixed up (e.g. the new relocation
processing), it is no wonder it doesn't work well.

Could we save line_table (and perhaps a few other vars) into non-GTY! copies
of them in ggc-common.c and instead of those fatal_error (input_location, ...)
calls in gt_pch_restore and ggc_pch_read call fatal_pch_error (...) where
void
fatal_pch_error (const char *gmsg)
{
  line_table = saved_line_table;
  // Restore anything else that is needed for fatal_error
  fatal_error (input_location, gmsg);
}

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 12:03                     ` Richard Biener
@ 2021-11-09 12:29                       ` Jakub Jelinek
  2021-11-09 14:41                         ` Andrew MacLeod
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09 12:29 UTC (permalink / raw)
  To: Richard Biener, Andrew MacLeod, Aldy Hernandez
  Cc: gcc-patches, John David Anglin, Iain Sandoe

On Tue, Nov 09, 2021 at 01:03:38PM +0100, Richard Biener wrote:
> > Apparently the range_of_expr can handle some tree cases through
> > range_query::get_tree_range, like INTEGER_CSTs, ADDR_EXPRs,
> > and some binary and unary ops.
> 
> But that shouldn't need a range query object ... this was all
> available pre-ranger and just got stuffed there for no good reason?

That is for Andrew/Aldy to answer.
All I can say is that get_tree_range is a non-static member function
of range_query and therefore it needs non-NULL query object.

But I must say I wonder if all this pain is worth it, if it wouldn't
be easier to keep cfun->x_range_query NULL most of the time and use
ATTRIBUTE_RETURNS_NONNULL inline range_query *
get_range_query (const struct function *fun)
{
  return fun->x_range_query ? fun->x_range_query : &global_ranges;
}

(of course, the function then would need to be in some header
where global_ranges is declared).

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 12:29                       ` Jakub Jelinek
@ 2021-11-09 14:41                         ` Andrew MacLeod
  2021-11-09 14:58                           ` Jakub Jelinek
  0 siblings, 1 reply; 39+ messages in thread
From: Andrew MacLeod @ 2021-11-09 14:41 UTC (permalink / raw)
  To: Jakub Jelinek, Richard Biener, Aldy Hernandez
  Cc: gcc-patches, John David Anglin, Iain Sandoe

[-- Attachment #1: Type: text/plain, Size: 1614 bytes --]

On 11/9/21 7:29 AM, Jakub Jelinek wrote:
> On Tue, Nov 09, 2021 at 01:03:38PM +0100, Richard Biener wrote:
>>> Apparently the range_of_expr can handle some tree cases through
>>> range_query::get_tree_range, like INTEGER_CSTs, ADDR_EXPRs,
>>> and some binary and unary ops.
>> But that shouldn't need a range query object ... this was all
>> available pre-ranger and just got stuffed there for no good reason?
resolving the binary ops requires calls back into range_of_expr to 
resolve operands.  It could be split out if needed/desired.
> That is for Andrew/Aldy to answer.
> All I can say is that get_tree_range is a non-static member function
> of range_query and therefore it needs non-NULL query object.
>
> But I must say I wonder if all this pain is worth it, if it wouldn't
> be easier to keep cfun->x_range_query NULL most of the time and use
> ATTRIBUTE_RETURNS_NONNULL inline range_query *
> get_range_query (const struct function *fun)
> {
>    return fun->x_range_query ? fun->x_range_query : &global_ranges;
> }
>
> (of course, the function then would need to be in some header
> where global_ranges is declared).
>
> 	Jakub
>
Yeah, Im not particular about how we do this...  I think thats perfectly 
reasonable.   Would something like the following solve this issue?

It creates a global-range class pointer, initializes it to point to the 
global query, and we can simply hide its existence and refer to it 
directly from function.h if you thinks thats reasonable and will work OK 
for this.   Then we dont have any inclusion issues.

Let me know and I'll run it thru the gauntlet.

Andrew



[-- Attachment #2: query.diff --]
[-- Type: text/x-patch, Size: 3187 bytes --]

commit 17a5b03c95549b5488bc8dd2af4f6e2cc9ddf098
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Nov 9 09:29:23 2021 -0500

    Keep x_range_query NULL for global ranges.
    
    Instead of x_range_query alwasy pointing to an object, have it default to
    NULL and return a pointer to the global query in that case.
    
            * function.c (allocate_struct_function): Set x_range_query to NULL.
            * function.h (get_range_query): Return context query or global.
            * gimple-range.cc (enable_ranger): Check current query is NULL.
            (disable_ranger): Clear function current query field.
            * value_query.cc (global_range_query_ptr): New.
            * value-query.h (global_ranges): Remove.

diff --git a/gcc/function.c b/gcc/function.c
index af3d57b32a3..8768c5fcf22 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4874,7 +4874,7 @@ allocate_struct_function (tree fndecl, bool abstract_p)
   cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
     && MAY_HAVE_DEBUG_MARKER_STMTS;
 
-  cfun->x_range_query = &global_ranges;
+  cfun->x_range_query = NULL;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 36003e7576a..3c1b2aa2b90 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -725,7 +725,9 @@ extern void used_types_insert (tree);
 ATTRIBUTE_RETURNS_NONNULL inline range_query *
 get_range_query (const struct function *fun)
 {
-  return fun->x_range_query;
+  // From value-query.h
+  extern range_query *global_range_query_ptr;
+  return fun->x_range_query ? fun->x_range_query : global_range_query_ptr;
 }
 
 extern range_query *get_global_range_query ();
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 87dba6e81d8..a2b68b2bc80 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -467,6 +467,7 @@ enable_ranger (struct function *fun)
 {
   gimple_ranger *r;
 
+  gcc_checking_assert (!fun->x_range_query);
   r = new gimple_ranger;
   fun->x_range_query = r;
 
@@ -479,7 +480,7 @@ enable_ranger (struct function *fun)
 void
 disable_ranger (struct function *fun)
 {
+  gcc_checking_assert (fun->x_range_query);
   delete fun->x_range_query;
-
-  fun->x_range_query = &global_ranges;
+  fun->x_range_query = NULL;
 }
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 17ebd86ce5f..8d1b27d9bfb 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -433,7 +433,9 @@ gimple_range_global (tree name)
 // ----------------------------------------------
 // global_range_query implementation.
 
+// This is utlized by function.h get_range_query() only.
 global_range_query global_ranges;
+range_query *global_range_query_ptr = &global_ranges;
 
 // Like get_range_query, but for accessing global ranges.
 
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 5161d23714b..f56abc4777c 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -126,7 +126,6 @@ public:
   bool range_of_expr (irange &r, tree expr, gimple * = NULL) OVERRIDE;
 };
 
-extern global_range_query global_ranges;
 extern value_range gimple_range_global (tree name);
 extern bool update_global_range (irange &r, tree name);
 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 14:41                         ` Andrew MacLeod
@ 2021-11-09 14:58                           ` Jakub Jelinek
  2021-11-09 15:23                             ` Andrew MacLeod
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09 14:58 UTC (permalink / raw)
  To: Andrew MacLeod
  Cc: Richard Biener, Aldy Hernandez, gcc-patches, John David Anglin,
	Iain Sandoe

On Tue, Nov 09, 2021 at 09:41:08AM -0500, Andrew MacLeod wrote:
> Yeah, Im not particular about how we do this...  I think thats perfectly
> reasonable.   Would something like the following solve this issue?

Yes, but see below.

> commit 17a5b03c95549b5488bc8dd2af4f6e2cc9ddf098
> Author: Andrew MacLeod <amacleod@redhat.com>
> Date:   Tue Nov 9 09:29:23 2021 -0500
> 
>     Keep x_range_query NULL for global ranges.
>     
>     Instead of x_range_query alwasy pointing to an object, have it default to
>     NULL and return a pointer to the global query in that case.
>     
>             * function.c (allocate_struct_function): Set x_range_query to NULL.
>             * function.h (get_range_query): Return context query or global.
>             * gimple-range.cc (enable_ranger): Check current query is NULL.
>             (disable_ranger): Clear function current query field.
>             * value_query.cc (global_range_query_ptr): New.
>             * value-query.h (global_ranges): Remove.
> 
> diff --git a/gcc/function.c b/gcc/function.c
> index af3d57b32a3..8768c5fcf22 100644
> --- a/gcc/function.c
> +++ b/gcc/function.c
> @@ -4874,7 +4874,7 @@ allocate_struct_function (tree fndecl, bool abstract_p)
>    cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
>      && MAY_HAVE_DEBUG_MARKER_STMTS;
>  
> -  cfun->x_range_query = &global_ranges;
> +  cfun->x_range_query = NULL;

This isn't needed, at the start of function we do
  cfun = ggc_cleared_alloc<function> ();
which already zero initializes the whole structure, including x_range_query.
So instead this can be removed.

> --- a/gcc/function.h
> +++ b/gcc/function.h
> @@ -725,7 +725,9 @@ extern void used_types_insert (tree);
>  ATTRIBUTE_RETURNS_NONNULL inline range_query *
>  get_range_query (const struct function *fun)
>  {
> -  return fun->x_range_query;
> +  // From value-query.h
> +  extern range_query *global_range_query_ptr;
> +  return fun->x_range_query ? fun->x_range_query : global_range_query_ptr;

Wouldn't it be better to do:
  extern range_query global_ranges;
  return fun->x_range_query ? fun->x_range_query : &global_ranges;
I think declaring a variable extern can be done with incomplete type
and &var is cheaper than ptr, because for the latter you need to
read the pointer value from memory, while for &var you can just
compute the address of the var which you need to compute for reading
ptr from memory too.

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 14:58                           ` Jakub Jelinek
@ 2021-11-09 15:23                             ` Andrew MacLeod
  2021-11-09 15:28                               ` Jakub Jelinek
  0 siblings, 1 reply; 39+ messages in thread
From: Andrew MacLeod @ 2021-11-09 15:23 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Biener, Aldy Hernandez, gcc-patches, John David Anglin,
	Iain Sandoe

[-- Attachment #1: Type: text/plain, Size: 2866 bytes --]

On 11/9/21 9:58 AM, Jakub Jelinek wrote:
> On Tue, Nov 09, 2021 at 09:41:08AM -0500, Andrew MacLeod wrote:
>> Yeah, Im not particular about how we do this...  I think thats perfectly
>> reasonable.   Would something like the following solve this issue?
> Yes, but see below.
>
>> commit 17a5b03c95549b5488bc8dd2af4f6e2cc9ddf098
>> Author: Andrew MacLeod <amacleod@redhat.com>
>> Date:   Tue Nov 9 09:29:23 2021 -0500
>>
>>      Keep x_range_query NULL for global ranges.
>>      
>>      Instead of x_range_query alwasy pointing to an object, have it default to
>>      NULL and return a pointer to the global query in that case.
>>      
>>              * function.c (allocate_struct_function): Set x_range_query to NULL.
>>              * function.h (get_range_query): Return context query or global.
>>              * gimple-range.cc (enable_ranger): Check current query is NULL.
>>              (disable_ranger): Clear function current query field.
>>              * value_query.cc (global_range_query_ptr): New.
>>              * value-query.h (global_ranges): Remove.
>>
>> diff --git a/gcc/function.c b/gcc/function.c
>> index af3d57b32a3..8768c5fcf22 100644
>> --- a/gcc/function.c
>> +++ b/gcc/function.c
>> @@ -4874,7 +4874,7 @@ allocate_struct_function (tree fndecl, bool abstract_p)
>>     cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
>>       && MAY_HAVE_DEBUG_MARKER_STMTS;
>>   
>> -  cfun->x_range_query = &global_ranges;
>> +  cfun->x_range_query = NULL;
> This isn't needed, at the start of function we do
>    cfun = ggc_cleared_alloc<function> ();
> which already zero initializes the whole structure, including x_range_query.
> So instead this can be removed.
>
>> --- a/gcc/function.h
>> +++ b/gcc/function.h
>> @@ -725,7 +725,9 @@ extern void used_types_insert (tree);
>>   ATTRIBUTE_RETURNS_NONNULL inline range_query *
>>   get_range_query (const struct function *fun)
>>   {
>> -  return fun->x_range_query;
>> +  // From value-query.h
>> +  extern range_query *global_range_query_ptr;
>> +  return fun->x_range_query ? fun->x_range_query : global_range_query_ptr;
> Wouldn't it be better to do:
>    extern range_query global_ranges;
>    return fun->x_range_query ? fun->x_range_query : &global_ranges;
> I think declaring a variable extern can be done with incomplete type
> and &var is cheaper than ptr, because for the latter you need to
> read the pointer value from memory, while for &var you can just
> compute the address of the var which you need to compute for reading
> ptr from memory too.
>
> 	

yeah, that doesnt work because range_query is a pure virtual. However, 
there also does not seem to be any reason why we need to jump thru hoops 
since get_range_query() doesn't need to be in function.h..   If I 
relocate it to value-query.h like so it seems to work quite well...   
How about this?

Andrew



[-- Attachment #2: query2.diff --]
[-- Type: text/x-patch, Size: 3643 bytes --]

commit 0d5b27e95b7aef4415163e4277de06b48437d6f8
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Nov 9 09:29:23 2021 -0500

    Keep x_range_query NULL for global ranges.
    
    Instead of x_range_query always pointing to an object, have it default to
    NULL and return a pointer to the global query in that case.
    
            * function.c (allocate_struct_function): Don't set x_range_query.
            * function.h (get_range_query): Move to value-query.h.
            * gimple-range.cc (enable_ranger): Check that query is currently NULL.
            (disable_ranger): Clear function current query field.
            * value_query.cc (get_global_range_query): Relocate to:
            * value-query.h (get_global_range_query): Here and inline.
            (get_range_query): Relocate here from function.h.

diff --git a/gcc/function.c b/gcc/function.c
index af3d57b32a3..61b3bd036b8 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4873,8 +4873,6 @@ allocate_struct_function (tree fndecl, bool abstract_p)
      binding annotations among them.  */
   cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
     && MAY_HAVE_DEBUG_MARKER_STMTS;
-
-  cfun->x_range_query = &global_ranges;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 36003e7576a..899430833ce 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -719,15 +719,4 @@ extern const char *current_function_name (void);
 
 extern void used_types_insert (tree);
 
-/* Returns the currently active range access class.  When there is no active
-   range class, global ranges are used.  Never returns null.  */
-
-ATTRIBUTE_RETURNS_NONNULL inline range_query *
-get_range_query (const struct function *fun)
-{
-  return fun->x_range_query;
-}
-
-extern range_query *get_global_range_query ();
-
 #endif  /* GCC_FUNCTION_H */
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 87dba6e81d8..a2b68b2bc80 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -467,6 +467,7 @@ enable_ranger (struct function *fun)
 {
   gimple_ranger *r;
 
+  gcc_checking_assert (!fun->x_range_query);
   r = new gimple_ranger;
   fun->x_range_query = r;
 
@@ -479,7 +480,7 @@ enable_ranger (struct function *fun)
 void
 disable_ranger (struct function *fun)
 {
+  gcc_checking_assert (fun->x_range_query);
   delete fun->x_range_query;
-
-  fun->x_range_query = &global_ranges;
+  fun->x_range_query = NULL;
 }
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 17ebd86ce5f..b7d9e6653b1 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -435,14 +435,6 @@ gimple_range_global (tree name)
 
 global_range_query global_ranges;
 
-// Like get_range_query, but for accessing global ranges.
-
-range_query *
-get_global_range_query ()
-{
-  return &global_ranges;
-}
-
 bool
 global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
 {
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 5161d23714b..323772c8deb 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -127,6 +127,17 @@ public:
 };
 
 extern global_range_query global_ranges;
+inline range_query *get_global_range_query () { return &global_ranges; }
+
+/* Returns the currently active range access class.  When there is no active
+   range class, global ranges are used.  Never returns null.  */
+
+ATTRIBUTE_RETURNS_NONNULL inline range_query *
+get_range_query (const struct function *fun)
+{
+  return fun->x_range_query ? fun->x_range_query : &global_ranges;
+}
+
 extern value_range gimple_range_global (tree name);
 extern bool update_global_range (irange &r, tree name);
 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 15:23                             ` Andrew MacLeod
@ 2021-11-09 15:28                               ` Jakub Jelinek
  2021-11-09 18:29                                 ` [COMMITTED] Keep x_range_query NULL for global ranges Andrew MacLeod
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-09 15:28 UTC (permalink / raw)
  To: Andrew MacLeod
  Cc: Richard Biener, Aldy Hernandez, gcc-patches, John David Anglin,
	Iain Sandoe

On Tue, Nov 09, 2021 at 10:23:19AM -0500, Andrew MacLeod wrote:
> yeah, that doesnt work because range_query is a pure virtual. However, there
> also does not seem to be any reason why we need to jump thru hoops since
> get_range_query() doesn't need to be in function.h..   If I relocate it to
> value-query.h like so it seems to work quite well...   How about this?

Ah, ok.  Indeed while one can extern global_range_query global_ranges;
with incomplete global_range_query type, inheritance will not be known.

> --- a/gcc/value-query.h
> +++ b/gcc/value-query.h
> @@ -127,6 +127,17 @@ public:
>  };
>  
>  extern global_range_query global_ranges;
> +inline range_query *get_global_range_query () { return &global_ranges; }

Formatting, there should be empty line after global_ranges, and
inline range_query *
get_global_range_entry ()
{
  return &global_ranges;
}

> +
> +/* Returns the currently active range access class.  When there is no active
> +   range class, global ranges are used.  Never returns null.  */
> +
> +ATTRIBUTE_RETURNS_NONNULL inline range_query *
> +get_range_query (const struct function *fun)
> +{
> +  return fun->x_range_query ? fun->x_range_query : &global_ranges;
> +}
> +
>  extern value_range gimple_range_global (tree name);
>  extern bool update_global_range (irange &r, tree name);
>  

Ok for trunk with the above nits fixed if it passes bootstrap/regtest,
thanks.

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [COMMITTED] Keep x_range_query NULL for global ranges.
  2021-11-09 15:28                               ` Jakub Jelinek
@ 2021-11-09 18:29                                 ` Andrew MacLeod
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew MacLeod @ 2021-11-09 18:29 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Richard Biener, Aldy Hernandez, gcc-patches, John David Anglin,
	Iain Sandoe

[-- Attachment #1: Type: text/plain, Size: 1589 bytes --]

On 11/9/21 10:28 AM, Jakub Jelinek wrote:
> On Tue, Nov 09, 2021 at 10:23:19AM -0500, Andrew MacLeod wrote:
>> yeah, that doesnt work because range_query is a pure virtual. However, there
>> also does not seem to be any reason why we need to jump thru hoops since
>> get_range_query() doesn't need to be in function.h..   If I relocate it to
>> value-query.h like so it seems to work quite well...   How about this?
> Ah, ok.  Indeed while one can extern global_range_query global_ranges;
> with incomplete global_range_query type, inheritance will not be known.
>
>> --- a/gcc/value-query.h
>> +++ b/gcc/value-query.h
>> @@ -127,6 +127,17 @@ public:
>>   };
>>   
>>   extern global_range_query global_ranges;
>> +inline range_query *get_global_range_query () { return &global_ranges; }
> Formatting, there should be empty line after global_ranges, and
> inline range_query *
> get_global_range_entry ()
> {
>    return &global_ranges;
> }
>
>> +
>> +/* Returns the currently active range access class.  When there is no active
>> +   range class, global ranges are used.  Never returns null.  */
>> +
>> +ATTRIBUTE_RETURNS_NONNULL inline range_query *
>> +get_range_query (const struct function *fun)
>> +{
>> +  return fun->x_range_query ? fun->x_range_query : &global_ranges;
>> +}
>> +
>>   extern value_range gimple_range_global (tree name);
>>   extern bool update_global_range (irange &r, tree name);
>>   
> Ok for trunk with the above nits fixed if it passes bootstrap/regtest,
> thanks.
>
> 	Jakub
>
Bootstraps on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew


[-- Attachment #2: query4.diff --]
[-- Type: text/x-patch, Size: 3652 bytes --]

commit 56af35de3d11960100996b96034dc9ccd7c75ca3
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Nov 9 09:29:23 2021 -0500

    Keep x_range_query NULL for global ranges.
    
    Instead of x_range_query always pointing to an object, have it default to
    NULL and return a pointer to the global query in that case.
    
            * function.c (allocate_struct_function): Don't set x_range_query.
            * function.h (get_range_query): Move to value-query.h.
            * gimple-range.cc (enable_ranger): Check that query is currently NULL.
            (disable_ranger): Clear function current query field.
            * value-query.cc (get_global_range_query): Relocate to:
            * value-query.h (get_global_range_query): Here and inline.
            (get_range_query): Relocate here from function.h.

diff --git a/gcc/function.c b/gcc/function.c
index af3d57b32a3..61b3bd036b8 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -4873,8 +4873,6 @@ allocate_struct_function (tree fndecl, bool abstract_p)
      binding annotations among them.  */
   cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt
     && MAY_HAVE_DEBUG_MARKER_STMTS;
-
-  cfun->x_range_query = &global_ranges;
 }
 
 /* This is like allocate_struct_function, but pushes a new cfun for FNDECL
diff --git a/gcc/function.h b/gcc/function.h
index 36003e7576a..899430833ce 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -719,15 +719,4 @@ extern const char *current_function_name (void);
 
 extern void used_types_insert (tree);
 
-/* Returns the currently active range access class.  When there is no active
-   range class, global ranges are used.  Never returns null.  */
-
-ATTRIBUTE_RETURNS_NONNULL inline range_query *
-get_range_query (const struct function *fun)
-{
-  return fun->x_range_query;
-}
-
-extern range_query *get_global_range_query ();
-
 #endif  /* GCC_FUNCTION_H */
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 87dba6e81d8..a2b68b2bc80 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -467,6 +467,7 @@ enable_ranger (struct function *fun)
 {
   gimple_ranger *r;
 
+  gcc_checking_assert (!fun->x_range_query);
   r = new gimple_ranger;
   fun->x_range_query = r;
 
@@ -479,7 +480,7 @@ enable_ranger (struct function *fun)
 void
 disable_ranger (struct function *fun)
 {
+  gcc_checking_assert (fun->x_range_query);
   delete fun->x_range_query;
-
-  fun->x_range_query = &global_ranges;
+  fun->x_range_query = NULL;
 }
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 17ebd86ce5f..b7d9e6653b1 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -435,14 +435,6 @@ gimple_range_global (tree name)
 
 global_range_query global_ranges;
 
-// Like get_range_query, but for accessing global ranges.
-
-range_query *
-get_global_range_query ()
-{
-  return &global_ranges;
-}
-
 bool
 global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
 {
diff --git a/gcc/value-query.h b/gcc/value-query.h
index 5161d23714b..38e23bb357b 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -127,6 +127,22 @@ public:
 };
 
 extern global_range_query global_ranges;
+
+inline range_query *
+get_global_range_query ()
+{
+  return &global_ranges;
+}
+
+/* Returns the currently active range access class.  When there is no active
+   range class, global ranges are used.  Never returns null.  */
+
+ATTRIBUTE_RETURNS_NONNULL inline range_query *
+get_range_query (const struct function *fun)
+{
+  return fun->x_range_query ? fun->x_range_query : &global_ranges;
+}
+
 extern value_range gimple_range_global (tree name);
 extern bool update_global_range (irange &r, tree name);
 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-09 12:18                     ` Jakub Jelinek
@ 2021-11-10  8:14                       ` Iain Sandoe
  2021-11-10 20:24                         ` Iain Sandoe
  0 siblings, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-10  8:14 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, John David Anglin, GCC Patches



> On 9 Nov 2021, at 12:18, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> On Tue, Nov 09, 2021 at 11:40:08AM +0000, Iain Sandoe wrote:
>> There were two issues, of which one remains and probably affects all targets.
>> 
>> 1.  The Darwin PCH memory allocation scheme used a system that works reliably
>>    for no-PIE but not for PIE
>> 
>> .. I hacked in a similar scheme to the mmap one used on Linux .. the suspect stuff
>>   there is in choosing some place in the map that is likely to succeed…
>> 
>>  With that I get passes on all c-family pch.exp (I didn’t try to bootstrap).
> 
> Yeah, certainly.

Overnight testing for i686, powerpc and x86_64 darwin suggests I’ve found some
suitable compromise map addresses (but that scheme has always seemed a bit
fragile if the ASLR parameters get updated for a new OS edition).

>> 2. This problem remains.
>> 
>>  - if we try to emit a diagnostic when the PCH read-in has failed, it seems that
>>   cc1 hangs somewhere in trying to lookup line table info.
>> 
>> - this was happening with the Darwin fixed PCH memory address because it
>>   was trying to report a fatal error in being unable to read the file (or trying to
>>  execute fancy_abort, in response to a segv).
> 
> I guess once we:
>  /* Read in all the scalar variables.  */
>  for (rt = gt_pch_scalar_rtab; *rt; rt++)
>    for (rti = *rt; rti->base != NULL; rti++)
>      if (fread (rti->base, rti->stride, 1, f) != 1)
>        fatal_error (input_location, "cannot read PCH file: %m");
> 
>  /* Read in all the global pointers, in 6 easy loops.  */
>  for (rt = gt_ggc_rtab; *rt; rt++)
>    for (rti = *rt; rti->base != NULL; rti++)
>      for (i = 0; i < rti->nelt; i++)
>        if (fread ((char *)rti->base + rti->stride * i,
>                   sizeof (void *), 1, f) != 1)
>          fatal_error (input_location, "cannot read PCH file: %m");
> we overwrite the GTY(()) marked global vars including
> extern GTY(()) class line_maps *line_table;
> with pointers into the area we haven't mapped yet (or if the error happens
> after that mmap but before everything is fixed up (e.g. the new relocation
> processing), it is no wonder it doesn't work well.
> 
> Could we save line_table (and perhaps a few other vars) into non-GTY! copies
> of them in ggc-common.c and instead of those fatal_error (input_location, ...)
> calls in gt_pch_restore and ggc_pch_read call fatal_pch_error (...) where
> void
> fatal_pch_error (const char *gmsg)
> {
>  line_table = saved_line_table;
>  // Restore anything else that is needed for fatal_error
>  fatal_error (input_location, gmsg);
> }

That seems reasonable for the case that we call fatal_error from ggc-common, but
I don’t think it will work if fancy_abort is called (for e.g. a segv) - we might need to 
make a local fancy_abort() as well for that specific file, perhaps.

Or in some way defer overwriting the data until we’ve succeeded in reading/relocating
the whole file (not sure what the largest PCH is we might encounter).

ISTR that we force clear everything before starting the read, since I had problems with
phasing diagnostic output when making a previous change to this area, so the snapshot
might be needed quite early.

Iain


> 
> 	Jakub
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-10  8:14                       ` Iain Sandoe
@ 2021-11-10 20:24                         ` Iain Sandoe
  2021-11-13 20:32                           ` Iain Sandoe
  0 siblings, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-10 20:24 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Richard Biener, GCC Patches, David Malcolm

Hi Folks,

> On 10 Nov 2021, at 08:14, Iain Sandoe <iain@sandoe.co.uk> wrote:

>> On 9 Nov 2021, at 12:18, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>> 
>> On Tue, Nov 09, 2021 at 11:40:08AM +0000, Iain Sandoe wrote:
>>> There were two issues, of which one remains and probably affects all targets.

>>> 2. This problem remains.

This problem is also present on master without making any changes to the PCH
implementation - if one fixes up the read-in to simulate a corrupted file, cc1 hangs

(which means it’s no barrier to the revised PCH implementation)

>>> - if we try to emit a diagnostic when the PCH read-in has failed, it seems that
>>>  cc1 hangs somewhere in trying to lookup line table info.
>>> 
>>> - this was happening with the Darwin fixed PCH memory address because it
>>>  was trying to report a fatal error in being unable to read the file (or trying to
>>> execute fancy_abort, in response to a segv).
>> 
>> I guess once we:
>> /* Read in all the scalar variables.  */
>> for (rt = gt_pch_scalar_rtab; *rt; rt++)
>>   for (rti = *rt; rti->base != NULL; rti++)
>>     if (fread (rti->base, rti->stride, 1, f) != 1)
>>       fatal_error (input_location, "cannot read PCH file: %m");
>> 
>> /* Read in all the global pointers, in 6 easy loops.  */
>> for (rt = gt_ggc_rtab; *rt; rt++)
>>   for (rti = *rt; rti->base != NULL; rti++)
>>     for (i = 0; i < rti->nelt; i++)
>>       if (fread ((char *)rti->base + rti->stride * i,
>>                  sizeof (void *), 1, f) != 1)
>>         fatal_error (input_location, "cannot read PCH file: %m");
>> we overwrite the GTY(()) marked global vars including
>> extern GTY(()) class line_maps *line_table;

>> with pointers into the area we haven't mapped yet (or if the error happens
>> after that mmap but before everything is fixed up (e.g. the new relocation
>> processing), it is no wonder it doesn't work well.

indeed.
>> 
>> Could we save line_table (and perhaps a few other vars) into non-GTY! copies
>> of them in ggc-common.c and instead of those fatal_error (input_location, ...)
>> calls in gt_pch_restore and ggc_pch_read call fatal_pch_error (...) where
>> void
>> fatal_pch_error (const char *gmsg)
>> {
>> line_table = saved_line_table;
>> // Restore anything else that is needed for fatal_error
>> fatal_error (input_location, gmsg);
>> }

> 
> That seems reasonable for the case that we call fatal_error from ggc-common, but
> I don’t think it will work if fancy_abort is called (for e.g. a segv) - we might need to 
> make a local fancy_abort() as well for that specific file, perhaps.
> 
> Or in some way defer overwriting the data until we’ve succeeded in reading/relocating
> the whole file (not sure what the largest PCH is we might encounter).

(answering my own question) around 150Mb for largest libstdc++ and similar for an 
Objective-C include of Foundation + AppKit etc.

The underlying reason here is that diagnostics have become much more sophisticated,
and they do all sorts of context checking and include the libcpp stuff directly which is a lot
of GTY(()) stuff.

I cannot immediately see any small set of state that we can save / restore around the
PCH read in,

Perhaps what would be more realistic would be a call into the diagnostics stuff to say
“disable fancy stuff and just report the minimum”,

as noted, I don’t think this (second) issue is actually a barrier to making the PCH change
since it’s preexisting - I just ran into it while debugging suitable VM addresses to use with
ASLR on.

thoughts?
Iain



^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-10 20:24                         ` Iain Sandoe
@ 2021-11-13 20:32                           ` Iain Sandoe
  2021-11-16  8:52                             ` Jakub Jelinek
  0 siblings, 1 reply; 39+ messages in thread
From: Iain Sandoe @ 2021-11-13 20:32 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 2307 bytes --]

Hi Folks,

IMO both this series
 - which restores the ability to work with PIE exes but requires a known address for the PCH 
and the series I posted
 - which allows a configuration to opt out of PCH anyway

could be useful - for Darwin I prefer this series.

of course, it would be very nice to have a relocatable impl (or the tree streamer) .. I fear
that relying on finding a fixed hole in the VM addresses is probably fragile w.r.t OS updates.

> On 10 Nov 2021, at 20:24, Iain Sandoe <iain@sandoe.co.uk> wrote:

>> On 10 Nov 2021, at 08:14, Iain Sandoe <iain@sandoe.co.uk> wrote:
> 
>>> On 9 Nov 2021, at 12:18, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>> 
>>> On Tue, Nov 09, 2021 at 11:40:08AM +0000, Iain Sandoe wrote:
>>>> There were two issues, of which one remains and probably affects all targets.
> 
>>>> 2. This problem remains.
> 
> This problem is also present on master without making any changes to the PCH
> implementation - if one fixes up the read-in to simulate a corrupted file, cc1 hangs
> 
> (which means it’s no barrier to the revised PCH implementation)


>> That seems reasonable for the case that we call fatal_error from ggc-common, but
>> I don’t think it will work if fancy_abort is called (for e.g. a segv) - we might need to 
>> make a local fancy_abort() as well for that specific file, perhaps.
>> 
>> Or in some way defer overwriting the data until we’ve succeeded in reading/relocating
>> the whole file (not sure what the largest PCH is we might encounter).

> 
> (answering my own question) around 150Mb for largest libstdc++ and similar for an 
> Objective-C include of Foundation + AppKit etc.
> 
> The underlying reason here is that diagnostics have become much more sophisticated,
> and they do all sorts of context checking and include the libcpp stuff directly which is a lot
> of GTY(()) stuff.
> 
> I cannot immediately see any small set of state that we can save / restore around the
> PCH read in,

I was wrong about that… patch posted that fixes most of this issue.


===

To add to Jakub's two patches that do the heavy lifting - two configure changes (I have also
darwin-local changes which are under test at the moment with the intention to apply them
anyway).




[-- Attachment #2: 0001-configure-gcc-Add-enable-pie-tools.patch --]
[-- Type: application/octet-stream, Size: 3994 bytes --]

From 697f235d8efbc53e2c5e63859cded0205f337969 Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@sandoe.co.uk>
Date: Fri, 12 Nov 2021 17:01:50 +0000
Subject: [PATCH 1/2] configure, gcc: Add --enable-pie-tools.

This adds a configure option to allow a configurer to choose
to build the compilers and other supporting tools as PIE.

This is distinct from whether the compiler defaults to
producing PIE code or not (i.e. one could have a PIE compiler
producing non-PIE code by default, or vice-versa).

Note that this implementation expects that the option will
have been validated at the top-level before being passed to
the gcc/ directory configure.

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

config/ChangeLog:

	* mh-darwin: Note that shared (PIC) code is also
	needed to support PIE.

gcc/ChangeLog:

	* Makefile.in: When pie-tools are enabled, do not add
	-no-PIE options to the compile and link lines.
	* config.in: Regenerate.
	* configure: Regenerate.
	* configure.ac: Add --enable-pie-tools confingure option.
---
 config/mh-darwin |  3 ++-
 gcc/Makefile.in  |  3 +++
 gcc/config.in    |  7 +++++++
 gcc/configure    | 30 ++++++++++++++++++++++++------
 gcc/configure.ac | 13 +++++++++++++
 5 files changed, 49 insertions(+), 7 deletions(-)

diff --git a/config/mh-darwin b/config/mh-darwin
index b72835ae953..bb4112773c9 100644
--- a/config/mh-darwin
+++ b/config/mh-darwin
@@ -11,7 +11,8 @@
 # non-bootstrapped compiler), later stages will be built by GCC which supports
 # the required flags.
 
-# We cannot use mdynamic-no-pic when building shared host resources.
+# We cannot use mdynamic-no-pic when building shared host resources, or for PIE
+# tool executables, which also enables host-shared.
 
 ifeq (${host_shared},no)
 BOOTSTRAP_TOOL_CAN_USE_MDYNAMIC_NO_PIC := $(shell \
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 571e9c28e29..878fada6862 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -270,11 +270,13 @@ COMPILER += $(CET_HOST_FLAGS)
 NO_PIE_CFLAGS = @NO_PIE_CFLAGS@
 NO_PIE_FLAG = @NO_PIE_FLAG@
 
+ifneq (@enable_pie_tools@,yes)
 # We don't want to compile the compilers with -fPIE, it make PCH fail.
 COMPILER += $(NO_PIE_CFLAGS)
 
 # Link with -no-pie since we compile the compiler with -fno-PIE.
 LINKER += $(NO_PIE_FLAG)
+endif
 
 # Like LINKER, but use a mutex for serializing front end links.
 ifeq (@DO_LINK_MUTEX@,true)
@@ -407,6 +409,7 @@ ifeq ($(enable_plugin),yes)
 endif
 
 enable_host_shared = @enable_host_shared@
+enable_default_pie = @enable_default_pie@
 
 enable_as_accelerator = @enable_as_accelerator@
 
diff --git a/gcc/config.in b/gcc/config.in
index b5bec3971dc..8bbe6492594 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -224,6 +224,13 @@
 #endif
 
 
+/* Define if you build Position Independent Executables for the compilers and
+   other tools. */
+#ifndef USED_FOR_TARGET
+#undef ENABLE_PIE_TOOLS
+#endif
+
+
 /* Define to enable plugin support. */
 #ifndef USED_FOR_TARGET
 #undef ENABLE_PLUGIN

diff --git a/gcc/configure.ac b/gcc/configure.ac
index 065080a4b39..4940cdcc16f 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -7542,6 +7542,19 @@ if test x$enable_default_pie = xyes ; then
 fi
 AC_SUBST([enable_default_pie])
 
+# Check whether --enable-pie-tools was given; this is passed automatically
+# from the top level where it has already been validated.
+AC_ARG_ENABLE(pie-tools,
+[AS_HELP_STRING([--enable-pie-tools],
+  [build Position Independent Executables for the compilers and other tools])],
+[enable_pie_tools=$enableval],
+[enable_pie_tools=no])
+if test x$enable_pie_tools = xyes ; then
+  AC_DEFINE(ENABLE_PIE_TOOLS, 1,
+      [Define if you build Position Independent Executables for the compilers and other tools.])
+fi
+AC_SUBST([enable_pie_tools])
+
 # Check if -fno-PIE works.
 AC_CACHE_CHECK([for -fno-PIE option],
   [gcc_cv_c_no_fpie],
-- 
2.24.3 (Apple Git-128)


[-- Attachment #3: 0002-configure-Add-top-level-configure-support-for-enable.patch --]
[-- Type: application/octet-stream, Size: 4127 bytes --]

From 1c65df304d264f1472384d1cf76c3de490b5578f Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@sandoe.co.uk>
Date: Fri, 12 Nov 2021 17:06:25 +0000
Subject: [PATCH 2/2] configure: Add top-level configure support for
 --enable-pie-tools.

This recognises and validates the --enable-pie-tools configure
option.  It is done here because the choice can affect the code-
gen decisions for dependent libraries (e.g. in the case of Dariwn
we need to switch PIC support on and, therefore, for 32bit tool-
chains disable mdynamic-no-pic).

The validated option is passed to sub-configures that use it
(currently just gcc/).

Signed-off-by: Iain Sandoe <iain@sandoe.co.uk>

ChangeLog:

	* Makefile.def: Pass enable-pie-tools configure option
	to gcc/ configure.
	* Makefile.in: Regenerated.
	* Makefile.tpl: Export enable_pie_tools value.
	* configure: Regenerate.
	* configure.ac: Add --enable-pie-tools option and
	validate it for Darwin.
---
 Makefile.def |  3 ++-
 Makefile.in  | 32 ++++++++++++++++++++++----------
 Makefile.tpl |  3 +++
 configure    | 42 ++++++++++++++++++++++++++++++++++++++++++
 configure.ac | 34 ++++++++++++++++++++++++++++++++++
 5 files changed, 103 insertions(+), 11 deletions(-)

diff --git a/Makefile.def b/Makefile.def
index a504192e6d7..b9f86938ab3 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -47,7 +47,8 @@ host_modules= { module= fixincludes; bootstrap=true;
 host_modules= { module= flex; no_check_cross= true; };
 host_modules= { module= gas; bootstrap=true; };
 host_modules= { module= gcc; bootstrap=true; 
-		extra_make_flags="$(EXTRA_GCC_FLAGS)"; };
+		extra_make_flags="$(EXTRA_GCC_FLAGS)";
+		extra_configure_flags='--enable-pie-tools=@enable_pie_tools@'; };
 host_modules= { module= gmp; lib_path=.libs; bootstrap=true;
 		// Work around in-tree gmp configure bug with missing flex.
 		extra_configure_flags='--disable-shared LEX="touch lex.yy.c"';

diff --git a/Makefile.tpl b/Makefile.tpl
index 213052f8226..4c402759d36 100644
--- a/Makefile.tpl
+++ b/Makefile.tpl
@@ -115,6 +115,9 @@ GCC_SHLIB_SUBDIR = @GCC_SHLIB_SUBDIR@
 # If the build should make suitable code for shared host resources.
 host_shared = @host_shared@
 
+# If we should build compilers and supporting tools as PIE.
+enable_pie_tools = @enable_pie_tools@
+
 # Build programs are put under this directory.
 BUILD_SUBDIR = @build_subdir@
 # This is set by the configure script to the arguments to use when configuring

diff --git a/configure.ac b/configure.ac
index 550e6993b59..6859d8f950d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1860,7 +1860,41 @@ AC_ARG_ENABLE(host-shared,
 [AS_HELP_STRING([--enable-host-shared],
 		[build host code as shared libraries])],
 [host_shared=$enableval], [host_shared=no])
+
+# Check whether --enable-pie-tools was given.
+# Checked early because it can affect host make fragments.
+AC_ARG_ENABLE(pie-tools,
+[AS_HELP_STRING([--enable-pie-tools],
+  [build Position Independent Executables for the compilers and other tools])],
+[enable_pie_tools=$enableval
+ case $target in
+   aarch64-*-darwin1[[1-9]]*)
+     if test x$enable_pie_tools != xyes ; then
+       echo configure.ac: warning: aarch64-darwin must use PIE, pie-tools setting ignored. 1>&2
+       enable_pie_tools=yes
+       host_shared=yes
+     fi ;;
+    *) ;;
+ esac],
+[case $target in
+  # PIE is the default for macOS 10.7+ so reflect that in the configure.
+  # However, we build 32b toolchains mdynamic-no-pic by default which is
+  # not compatible with PIE.
+  x86_64-*-darwin1[[1-9]]* | *-*-darwin2*) enable_pie_tools=yes ;;
+  *) enable_pie_tools=no ;;
+ esac])
+
+case $target in
+  *-*-darwin*)
+    if test x$enable_pie_tools = xyes && test x$host_shared != xyes ; then
+      echo configure.ac: warning: for Darwin PIE requires PIC code, switching host-shared on 1>&2
+      host_shared=yes
+    fi ;;
+  *) ;;
+esac
+
 AC_SUBST(host_shared)
+AC_SUBST([enable_pie_tools])
 
 # By default, C and C++ are the only stage 1 languages.
 stage1_languages=,c,
-- 
2.24.3 (Apple Git-128)


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch: Add support for PCH for relocatable executables
  2021-11-13 20:32                           ` Iain Sandoe
@ 2021-11-16  8:52                             ` Jakub Jelinek
  0 siblings, 0 replies; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-16  8:52 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: GCC Patches, Richard Biener

On Sat, Nov 13, 2021 at 08:32:41PM +0000, Iain Sandoe wrote:
> IMO both this series
>  - which restores the ability to work with PIE exes but requires a known address for the PCH 
> and the series I posted
>  - which allows a configuration to opt out of PCH anyway
> 
> could be useful - for Darwin I prefer this series.

Yeah, I think we want both and let the users choose.

Finding a hole can be indeed hard on 32-bit VA, but no OS I've seen
randomizes across the whole 44 or 48 or how many bits VA, otherwise e.g.
address sanitizer or thread sanitizer would have no chance to work either.

Having the PCH blob be relocatable would be achievable too, we have all the
information in the GTY for it after all when we are able to relocate it at
PCH saving time, but don't do that currently because it would be more
expensive at PCH restore time.  But perhaps better to do that as a fallback
if we don't manage to get the right slot.

	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH] pch, v2: Add support for PCH for relocatable executables
  2021-11-08 19:48             ` [PATCH] pch: Add support for PCH for relocatable executables Jakub Jelinek
  2021-11-08 21:03               ` John David Anglin
  2021-11-09  7:12               ` Richard Biener
@ 2021-11-18  8:04               ` Jakub Jelinek
  2021-12-02 18:26                 ` Jeff Law
  2021-12-06 10:00                 ` Martin Liška
  2 siblings, 2 replies; 39+ messages in thread
From: Jakub Jelinek @ 2021-11-18  8:04 UTC (permalink / raw)
  To: Iain Sandoe, Richard Biener, Jeff Law; +Cc: gcc-patches

On Mon, Nov 08, 2021 at 08:48:07PM +0100, Jakub Jelinek via Gcc-patches wrote:
> On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
> > So, if we want to make PCH work for PIEs, I'd say we can:
> > 1) add a new GTY option, say callback, which would act like
> >    skip for non-PCH and for PCH would make us skip it but
> >    remember for address bias translation
> > 2) drop the skip for tree_translation_unit_decl::language
> > 3) change get_unnamed_section to have const char * as
> >    last argument instead of const void *, change
> >    unnamed_section::data also to const char * and update
> >    everything related to that
> > 4) maybe add a host hook whether it is ok to support binaries
> >    changing addresses (the only thing I'm worried is if
> >    some host that uses function descriptors allocates them
> >    dynamically instead of having them somewhere in the
> >    executable)
> > 5) maybe add a gengtype warning if it sees in GTY tracked
> >    structure a function pointer without that new callback
> >    option
> 
> So, here is 1), 2), 3) implemented.  With this patch alone,
> g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
> function::x_range_query member, which is set to &global_ranges on
> cfun creation and is:
>   range_query * GTY ((skip)) x_range_query;
> which means when a PIE binary writes PCH and a PIE binary loaded
> at a different address loads it, cfun->x_range_query might be a garbage
> pointer.  We can either apply a patch like the attached one after
> this inline patch, but then probably callback is misnamed and we should
> rename it to relocate_and_skip or something similar.  Or we could
> e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.
> 
> Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
> the second patch, with it a few more, but nothing huge.  And for non-PIEs
> there isn't really any extra work on the load side except freading two scalar
> values and fseek.

Here is an updated version (the previous version doesn't apply any longer
in gt_pch_restore due to the line_maps saving/restoring changes).

Bootstrapped/regtested on x86_64-linux and i686-linux with
--enable-host-shared in addition to normal configure options (and without
Ada which doesn't even with the above options build PIC libgnat.a and links
it) and a hack:
--- gcc/configure.ac.jj	2021-10-28 22:12:31.569299780 +0200
+++ gcc/configure.ac	2021-11-09 11:34:33.453776105 +0100
@@ -7566,7 +7566,7 @@ AC_CACHE_CHECK([for -no-pie option],
      [gcc_cv_no_pie=no])
    LDFLAGS="$saved_LDFLAGS"])
 if test "$gcc_cv_no_pie" = "yes"; then
-  NO_PIE_FLAG="-no-pie"
+  NO_PIE_FLAG="-pie"
 fi
 AC_SUBST([NO_PIE_FLAG])
 
to force binaries be PIE, no regressions against non-PIC/PIE build
without this patch.  Ok for trunk?

2021-11-18  Jakub Jelinek  <jakub@redhat.com>

	PR pch/71934
gcc/
	* ggc.h (gt_pch_note_callback): Declare.
	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
	(callback_type): Declare.
	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
	(callback_type): New variable.
	(process_gc_options): Add CALLBACK argument, handle callback
	option.
	(set_gc_used_type): Adjust process_gc_options caller, if callback,
	set type to &callback_type.
	(output_mangled_typename): Handle TYPE_CALLBACK.
	(walk_type): Likewise.  Handle callback option.
	(write_types_process_field): Handle TYPE_CALLBACK.
	(write_types_local_user_process_field): Likewise.
	(write_types_local_process_field): Likewise.
	(write_root): Likewise.
	(dump_typekind): Likewise.
	(dump_type): Likewise.
	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
	(state_writer::write_state_callback_type): New method.
	(state_writer::write_state_type): Handle TYPE_CALLBACK.
	(read_state_callback_type): New function.
	(read_state_type): Handle TYPE_CALLBACK.
	* ggc-common.c (callback_vec): New variable.
	(gt_pch_note_callback): New function.
	(gt_pch_save): Stream out gt_pch_save function address and relocation
	table.
	(gt_pch_restore): Stream in saved gt_pch_save function address and
	relocation table and apply relocations if needed.
	* doc/gty.texi (callback): Document new GTY option.
	* varasm.c (get_unnamed_section): Change callback argument's type and
	last argument's type from const void * to const char *.
	(output_section_asm_op): Change argument's type from const void *
	to const char *, remove unnecessary cast.
	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
	from language member.
	* output.h (unnamed_section_callback): Change argument type from
	const void * to const char *.
	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
	for callback member.  Change data member type from const void *
	to const char *.
	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
	for callback member.
	(get_unnamed_section): Change callback argument's type and
	last argument's type from const void * to const char *.
	(output_section_asm_op): Change argument's type from const void *
	to const char *.
	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
	Remove unneeded cast.
	* config/darwin.c (output_objc_section_asm_op): Change argument's type
	from const void * to const char *.
	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
	(som_output_comdat_data_section_asm_op): Likewise.
	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
	Likewise.
	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
	of dereferencing directive hardcode variable names and decide based on
	whether directive is NULL or not.
	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
	from const void * to const char *.
	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
	of dereferencing directive hardcode variable names and decide based on
	whether directive is NULL or not.
	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
	from const void * to const char *.
	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
gcc/c-family/
	* c-pch.c (struct c_pch_validity): Remove pch_init member.
	(pch_init): Don't initialize v.pch_init.
	(c_common_valid_pch): Don't warn and punt if .text addresses change.
libcpp/
	* include/line-map.h (class line_maps): Add GTY((callback)) to
	reallocator and round_alloc_size members.

--- gcc/ggc.h.jj	2021-08-19 11:42:27.366422386 +0200
+++ gcc/ggc.h	2021-11-08 16:46:02.604618109 +0100
@@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void
 /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
 extern int gt_pch_note_object (void *, void *, gt_note_pointers);
 
+/* Used by the gt_pch_p_* routines.  Register address of a callback
+   pointer.  */
+extern void gt_pch_note_callback (void *, void *);
+
 /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
    function.  */
 extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
--- gcc/gengtype.h.jj	2021-07-20 10:08:09.892687719 +0200
+++ gcc/gengtype.h	2021-11-08 15:19:59.194210185 +0100
@@ -154,6 +154,9 @@ enum typekind {
   TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
   TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
   TYPE_ARRAY,           /* Array of GTY-ed types.  */
+  TYPE_CALLBACK,	/* A function pointer that needs relocation if
+			   the executable has been loaded at a different
+			   address.  */
   TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
                            Various languages may have homonymous but
                            different structs.  */
@@ -331,6 +334,9 @@ extern struct type string_type;
 extern struct type scalar_nonchar;
 extern struct type scalar_char;
 
+/* The one and only TYPE_CALLBACK.  */
+extern struct type callback_type;
+
 /* Test if a type is a union, either a plain one or a language
    specific one.  */
 #define UNION_P(x)					\
--- gcc/gengtype.c.jj	2021-10-04 10:16:10.885140187 +0200
+++ gcc/gengtype.c	2021-11-08 16:30:41.981750183 +0100
@@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil,
   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
   int nb_lang_struct = 0;
   int nb_user_struct = 0, nb_undefined = 0;
+  int nb_callback = 0;
   type_p p = NULL;
   for (p = t; p; p = p->next)
     {
@@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil,
 	case TYPE_ARRAY:
 	  nb_array++;
 	  break;
+	case TYPE_CALLBACK:
+	  nb_callback++;
+	  break;
 	case TYPE_LANG_STRUCT:
 	  nb_lang_struct++;
 	  break;
@@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil,
     fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
   if (nb_pointer > 0 || nb_array > 0)
     fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
+  if (nb_callback > 0)
+    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
   if (nb_lang_struct > 0)
     fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
   if (nb_user_struct > 0)
@@ -495,6 +501,10 @@ struct type scalar_char = {
   TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
 };
 
+struct type callback_type = {
+  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
+};
+
 /* Lists of various things.  */
 
 pair_p typedefs = NULL;
@@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
 
 static void
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
-		    int *length, int *skip, type_p *nested_ptr)
+		    int *length, int *skip, int *callback, type_p *nested_ptr)
 {
   options_p o;
   for (o = opt; o; o = o->next)
@@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum
       *length = 1;
     else if (strcmp (o->name, "skip") == 0)
       *skip = 1;
+    else if (strcmp (o->name, "callback") == 0)
+      *callback = 1;
     else if (strcmp (o->name, "nested_ptr") == 0
 	     && o->kind == OPTION_NESTED)
       *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
@@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used
 	type_p dummy2;
 	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
 
-	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
+	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
 			    &dummy2);
 
 	if (t->u.s.base_class)
@@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used
 	    int maybe_undef = 0;
 	    int length = 0;
 	    int skip = 0;
+	    int callback = 0;
 	    type_p nested_ptr = NULL;
 	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
-				&nested_ptr);
+				&callback, &nested_ptr);
 
 	    if (nested_ptr && f->type->kind == TYPE_POINTER)
 	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
@@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used
 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
 	    else if (skip)
 	      ;			/* target type is not used through this field */
+	    else if (callback)
+	      f->type = &callback_type;
 	    else
 	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
 	  }
@@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, cons
       {
       case TYPE_NONE:
       case TYPE_UNDEFINED:
+      case TYPE_CALLBACK:
 	gcc_unreachable ();
 	break;
       case TYPE_POINTER:
@@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_da
       ;
     else if (strcmp (oo->name, "for_user") == 0)
       ;
+    else if (strcmp (oo->name, "callback") == 0)
+      ;
     else
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
 
@@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_da
     {
     case TYPE_SCALAR:
     case TYPE_STRING:
+    case TYPE_CALLBACK:
       d->process_field (t, d);
       break;
 
@@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, con
       break;
 
     case TYPE_SCALAR:
+    case TYPE_CALLBACK:
       break;
 
     case TYPE_ARRAY:
@@ -3820,6 +3840,7 @@ write_types_local_user_process_field (ty
       break;
 
     case TYPE_SCALAR:
+    case TYPE_CALLBACK:
       break;
 
     case TYPE_ARRAY:
@@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p
     case TYPE_SCALAR:
       break;
 
+    case TYPE_CALLBACK:
+      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
+	       d->prev_val[3]);
+      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
+	       d->indent, "", d->val);
+      break;
+
     case TYPE_ARRAY:
     case TYPE_NONE:
     case TYPE_UNDEFINED:
@@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p t
     case TYPE_UNDEFINED:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
+    case TYPE_CALLBACK:
       error_at_line (line, "global `%s' is unimplemented type", name);
     }
 }
@@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind
     case TYPE_ARRAY:
       printf ("TYPE_ARRAY");
       break;
+    case TYPE_CALLBACK:
+      printf ("TYPE_CALLBACK");
+      break;
     case TYPE_LANG_STRUCT:
       printf ("TYPE_LANG_STRUCT");
       break;
@@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
 	      t->u.scalar_is_char ? "true" : "false");
       break;
     case TYPE_STRING:
+    case TYPE_CALLBACK:
       break;
     case TYPE_STRUCT:
     case TYPE_UNION:
--- gcc/varasm.c.jj	2021-09-28 11:34:29.343147261 +0200
+++ gcc/varasm.c	2021-11-08 13:26:15.032606040 +0100
@@ -250,8 +250,8 @@ object_block_hasher::hash (object_block
 /* Return a new unnamed section with the given fields.  */
 
 section *
-get_unnamed_section (unsigned int flags, void (*callback) (const void *),
-		     const void *data)
+get_unnamed_section (unsigned int flags, void (*callback) (const char *),
+		     const char *data)
 {
   section *sect;
 
@@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
    a get_unnamed_section callback.  */
 
 void
-output_section_asm_op (const void *directive)
+output_section_asm_op (const char *directive)
 {
-  fprintf (asm_out_file, "%s\n", (const char *) directive);
+  fprintf (asm_out_file, "%s\n", directive);
 }
 
 /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
--- gcc/ggc-common.c.jj	2021-11-08 11:09:50.280318624 +0100
+++ gcc/ggc-common.c	2021-11-17 20:10:07.088187637 +0100
@@ -246,6 +246,7 @@ saving_hasher::equal (const ptr_data *p1
 }
 
 static hash_table<saving_hasher> *saving_htab;
+static vec<void *> callback_vec;
 
 /* Register an object in the hash table.  */
 
@@ -278,6 +279,23 @@ gt_pch_note_object (void *obj, void *not
   return 1;
 }
 
+/* Register address of a callback pointer.  */
+void
+gt_pch_note_callback (void *obj, void *base)
+{
+  void *ptr;
+  memcpy (&ptr, obj, sizeof (void *));
+  if (ptr != NULL)
+    {
+      struct ptr_data *data
+	= (struct ptr_data *)
+	  saving_htab->find_with_hash (base, POINTER_HASH (base));
+      gcc_assert (data);
+      callback_vec.safe_push ((char *) data->new_addr
+			      + ((char *) obj - (char *) base));
+    }
+}
+
 /* Register an object in the hash table.  */
 
 void
@@ -576,10 +594,20 @@ gt_pch_save (FILE *f)
   ggc_pch_finish (state.d, state.f);
   gt_pch_fixup_stringpool ();
 
+  unsigned num_callbacks = callback_vec.length ();
+  void (*pch_save) (FILE *) = &gt_pch_save;
+  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
+      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
+      || (num_callbacks
+	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
+		     f) != num_callbacks))
+    fatal_error (input_location, "cannot write PCH file: %m");
+
   XDELETE (state.ptrs);
   XDELETE (this_object);
   delete saving_htab;
   saving_htab = NULL;
+  callback_vec.release ();
 }
 
 /* Read the state of the compiler back in from F.  */
@@ -661,6 +689,30 @@ gt_pch_restore (FILE *f)
 
   gt_pch_restore_stringpool ();
 
+  void (*pch_save) (FILE *);
+  unsigned num_callbacks;
+  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
+      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
+    fatal_error (input_location, "cannot read PCH file: %m");
+  if (pch_save != &gt_pch_save)
+    {
+      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
+      void **ptrs = XNEWVEC (void *, num_callbacks);
+      unsigned i;
+
+      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
+	fatal_error (input_location, "cannot read PCH file: %m");
+      for (i = 0; i < num_callbacks; ++i)
+	{
+	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
+	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
+	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
+	}
+      XDELETE (ptrs);
+    }
+  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
+    fatal_error (input_location, "cannot read PCH file: %m");
+
   /* Barring corruption of the PCH file, the restored line table should be
      complete and usable.  */
   line_table = new_line_table;
--- gcc/doc/gty.texi.jj	2021-08-19 11:42:27.363422428 +0200
+++ gcc/doc/gty.texi	2021-11-08 17:13:46.613882767 +0100
@@ -197,6 +197,15 @@ If @code{skip} is applied to a field, th
 This is somewhat dangerous; the only safe use is in a union when one
 field really isn't ever used.
 
+@findex callback
+@item callback
+
+@code{callback} should be applied to fields with pointer to function type
+and causes the field to be ignored similarly to @code{skip}, except when
+writing PCH and the field is non-NULL it will remember the field's address
+for relocation purposes if the process writing PCH has different load base
+from a process reading PCH.
+
 @findex for_user
 @item for_user
 
--- gcc/tree-core.h.jj	2021-11-04 12:27:02.377298411 +0100
+++ gcc/tree-core.h	2021-11-08 13:24:04.496465555 +0100
@@ -1964,7 +1964,7 @@ struct GTY(()) tree_function_decl {
 struct GTY(()) tree_translation_unit_decl {
   struct tree_decl_common common;
   /* Source language of this translation unit.  Used for DWARF output.  */
-  const char * GTY((skip(""))) language;
+  const char *language;
   /* TODO: Non-optimization used to build this translation unit.  */
   /* TODO: Root of a partial DWARF tree for global types and decls.  */
 };
--- gcc/gengtype-state.c.jj	2021-07-20 10:08:09.891687732 +0200
+++ gcc/gengtype-state.c	2021-11-08 15:19:16.157824146 +0100
@@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
     case TYPE_STRING:
     case TYPE_POINTER:
     case TYPE_ARRAY:
+    case TYPE_CALLBACK:
       return NULL;
     default:
       gcc_unreachable ();
@@ -171,6 +172,7 @@ private:
   void write_state_version (const char *version);
   void write_state_scalar_type (type_p current);
   void write_state_string_type (type_p current);
+  void write_state_callback_type (type_p current);
   void write_state_undefined_type (type_p current);
   void write_state_struct_union_type (type_p current, const char *kindstr);
   void write_state_struct_type (type_p current);
@@ -898,6 +900,20 @@ state_writer::write_state_string_type (t
     fatal ("Unexpected type in write_state_string_type");
 }
 
+/* Write the callback type.  There is only one such thing! */
+void
+state_writer::write_state_callback_type (type_p current)
+{
+  if (current == &callback_type)
+    {
+      write_any_indent (0);
+      fprintf (state_file, "callback ");
+      write_state_common_type_content (current);
+    }
+  else
+    fatal ("Unexpected type in write_state_callback_type");
+}
+
 /* Write an undefined type.  */
 void
 state_writer::write_state_undefined_type (type_p current)
@@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p c
 	case TYPE_STRING:
 	  write_state_string_type (current);
 	  break;
+	case TYPE_CALLBACK:
+	  write_state_callback_type (current);
+	  break;
 	}
     }
 
@@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
   read_state_common_type_content (*type);
 }
 
+/* Read the callback_type.  */
+static void
+read_state_callback_type (type_p *type)
+{
+  *type = &callback_type;
+  read_state_common_type_content (*type);
+}
+
 
 /* Read a lang_bitmap representing a set of GCC front-end languages.  */
 static void
@@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
 	      next_state_tokens (1);
 	      read_state_string_type (current);
 	    }
+	  else if (state_token_is_name (t0, "callback"))
+	    {
+	      next_state_tokens (1);
+	      read_state_callback_type (current);
+	    }
 	  else if (state_token_is_name (t0, "undefined"))
 	    {
 	      *current = XCNEW (struct type);
--- gcc/output.h.jj	2021-09-28 11:34:29.235148754 +0200
+++ gcc/output.h	2021-11-08 16:26:01.172755377 +0100
@@ -470,7 +470,7 @@ struct GTY(()) named_section {
 
 /* A callback that writes the assembly code for switching to an unnamed
    section.  The argument provides callback-specific data.  */
-typedef void (*unnamed_section_callback) (const void *);
+typedef void (*unnamed_section_callback) (const char *);
 
 /* Information about a SECTION_UNNAMED section.  */
 struct GTY(()) unnamed_section {
@@ -478,8 +478,8 @@ struct GTY(()) unnamed_section {
 
   /* The callback used to switch to the section, and the data that
      should be passed to the callback.  */
-  unnamed_section_callback GTY ((skip)) callback;
-  const void *GTY ((skip)) data;
+  unnamed_section_callback GTY ((callback)) callback;
+  const char *data;
 
   /* The next entry in the chain of unnamed sections.  */
   section *next;
@@ -503,7 +503,7 @@ struct GTY(()) noswitch_section {
   struct section_common common;
 
   /* The callback used to assemble decls in this section.  */
-  noswitch_section_callback GTY ((skip)) callback;
+  noswitch_section_callback GTY ((callback)) callback;
 };
 
 /* Information about a section, which may be named or unnamed.  */
@@ -538,8 +538,8 @@ extern GTY(()) section *bss_noswitch_sec
 extern GTY(()) section *in_section;
 extern GTY(()) bool in_cold_section_p;
 
-extern section *get_unnamed_section (unsigned int, void (*) (const void *),
-				     const void *);
+extern section *get_unnamed_section (unsigned int, void (*) (const char *),
+				     const char *);
 extern section *get_section (const char *, unsigned int, tree,
 			     bool not_existing = false);
 extern section *get_named_section (tree, const char *, int);
@@ -561,7 +561,7 @@ extern section *get_cdtor_priority_secti
 
 extern bool unlikely_text_section_p (section *);
 extern void switch_to_section (section *, tree = nullptr);
-extern void output_section_asm_op (const void *);
+extern void output_section_asm_op (const char *);
 
 extern void record_tm_clone_pair (tree, tree);
 extern void finish_tm_clone_pairs (void);
--- gcc/config/avr/avr.c.jj	2021-07-15 10:16:12.873583249 +0200
+++ gcc/config/avr/avr.c	2021-11-08 13:28:30.215676387 +0100
@@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const voi
 /* Unnamed section callback for progmem*.data sections.  */
 
 static void
-avr_output_progmem_section_asm_op (const void *data)
+avr_output_progmem_section_asm_op (const char *data)
 {
-  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
-           (const char*) data);
+  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
 }
 
 
--- gcc/config/darwin.c.jj	2021-10-21 10:23:27.450834602 +0200
+++ gcc/config/darwin.c	2021-11-08 13:27:19.106691421 +0100
@@ -134,7 +134,7 @@ int emit_aligned_common = false;
    DIRECTIVE is as for output_section_asm_op.  */
 
 static void
-output_objc_section_asm_op (const void *directive)
+output_objc_section_asm_op (const char *directive)
 {
   static bool been_here = false;
 
--- gcc/config/pa/pa.c.jj	2021-10-27 09:00:28.762277456 +0200
+++ gcc/config/pa/pa.c	2021-11-08 13:29:41.935652629 +0100
@@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t
    to the default text subspace.  */
 
 static void
-som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
 {
   gcc_assert (TARGET_SOM);
   if (TARGET_GAS)
@@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const vo
    sections.  This function is only used with SOM.  */
 
 static void
-som_output_comdat_data_section_asm_op (const void *data)
+som_output_comdat_data_section_asm_op (const char *data)
 {
   in_section = NULL;
   output_section_asm_op (data);
--- gcc/config/rs6000/rs6000.c.jj	2021-11-05 00:43:22.476626062 +0100
+++ gcc/config/rs6000/rs6000.c	2021-11-08 13:43:22.415940789 +0100
@@ -20597,7 +20597,7 @@ rs6000_ms_bitfield_layout_p (const_tree
 /* A get_unnamed_section callback, used for switching to toc_section.  */
 
 static void
-rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
 {
   if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
       && TARGET_MINIMAL_TOC)
@@ -21301,35 +21301,39 @@ rs6000_xcoff_asm_globalize_label (FILE *
    points to the section string variable.  */
 
 static void
-rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
+rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
 {
   fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
-	   *(const char *const *) directive,
+	   directive
+	   ? xcoff_private_rodata_section_name
+	   : xcoff_read_only_section_name,
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 /* Likewise for read-write sections.  */
 
 static void
-rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
+rs6000_xcoff_output_readwrite_section_asm_op (const char *)
 {
   fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
-	   *(const char *const *) directive,
+	   xcoff_private_data_section_name,
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 static void
-rs6000_xcoff_output_tls_section_asm_op (const void *directive)
+rs6000_xcoff_output_tls_section_asm_op (const char *directive)
 {
   fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
-	   *(const char *const *) directive,
+	   directive
+	   ? xcoff_private_data_section_name
+	   : xcoff_tls_data_section_name,
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 /* A get_unnamed_section callback, used for switching to toc_section.  */
 
 static void
-rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
 {
   if (TARGET_MINIMAL_TOC)
     {
@@ -21356,26 +21360,26 @@ rs6000_xcoff_asm_init_sections (void)
 {
   read_only_data_section
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
-			   &xcoff_read_only_section_name);
+			   NULL);
 
   private_data_section
     = get_unnamed_section (SECTION_WRITE,
 			   rs6000_xcoff_output_readwrite_section_asm_op,
-			   &xcoff_private_data_section_name);
+			   NULL);
 
   read_only_private_data_section
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
-			   &xcoff_private_rodata_section_name);
+			   "");
 
   tls_data_section
     = get_unnamed_section (SECTION_TLS,
 			   rs6000_xcoff_output_tls_section_asm_op,
-			   &xcoff_tls_data_section_name);
+			   NULL);
 
   tls_private_data_section
     = get_unnamed_section (SECTION_TLS,
 			   rs6000_xcoff_output_tls_section_asm_op,
-			   &xcoff_private_data_section_name);
+			   "");
 
   toc_section
     = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
--- gcc/c-family/c-pch.c.jj	2021-06-02 10:08:14.149450407 +0200
+++ gcc/c-family/c-pch.c	2021-11-08 17:34:17.302343697 +0100
@@ -54,7 +54,6 @@ struct c_pch_validity
 {
   uint32_t pch_write_symbols;
   signed char match[MATCH_SIZE];
-  void (*pch_init) (void);
   size_t target_data_length;
 };
 
@@ -117,7 +116,6 @@ pch_init (void)
 	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
       }
   }
-  v.pch_init = &pch_init;
   target_validity = targetm.get_pch_validity (&v.target_data_length);
 
   if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
@@ -278,19 +276,6 @@ c_common_valid_pch (cpp_reader *pfile, c
 	}
   }
 
-  /* If the text segment was not loaded at the same address as it was
-     when the PCH file was created, function pointers loaded from the
-     PCH will not be valid.  We could in theory remap all the function
-     pointers, but no support for that exists at present.
-     Since we have the same executable, it should only be necessary to
-     check one function.  */
-  if (v.pch_init != &pch_init)
-    {
-      cpp_warning (pfile, CPP_W_INVALID_PCH,
-		   "%s: had text segment at different address", name);
-      return 2;
-    }
-
   /* Check the target-specific validity data.  */
   {
     void *this_file_data = xmalloc (v.target_data_length);
--- libcpp/include/line-map.h.jj	2021-11-01 14:37:06.697853154 +0100
+++ libcpp/include/line-map.h	2021-11-08 16:16:34.562837006 +0100
@@ -803,11 +803,11 @@ public:
   unsigned int max_column_hint;
 
   /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
-  line_map_realloc reallocator;
+  line_map_realloc GTY((callback)) reallocator;
 
   /* The allocators' function used to know the actual size it
      allocated, for a certain allocation size requested.  */
-  line_map_round_alloc_size_func round_alloc_size;
+  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
 
   struct location_adhoc_data_map location_adhoc_data_map;
 


	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch, v2: Add support for PCH for relocatable executables
  2021-11-18  8:04               ` [PATCH] pch, v2: Add support for PCH for relocatable executables Jakub Jelinek
@ 2021-12-02 18:26                 ` Jeff Law
  2021-12-06 10:00                 ` Martin Liška
  1 sibling, 0 replies; 39+ messages in thread
From: Jeff Law @ 2021-12-02 18:26 UTC (permalink / raw)
  To: Jakub Jelinek, Iain Sandoe, Richard Biener; +Cc: gcc-patches



On 11/18/2021 1:04 AM, Jakub Jelinek wrote:
> On Mon, Nov 08, 2021 at 08:48:07PM +0100, Jakub Jelinek via Gcc-patches wrote:
>> On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
>>> So, if we want to make PCH work for PIEs, I'd say we can:
>>> 1) add a new GTY option, say callback, which would act like
>>>     skip for non-PCH and for PCH would make us skip it but
>>>     remember for address bias translation
>>> 2) drop the skip for tree_translation_unit_decl::language
>>> 3) change get_unnamed_section to have const char * as
>>>     last argument instead of const void *, change
>>>     unnamed_section::data also to const char * and update
>>>     everything related to that
>>> 4) maybe add a host hook whether it is ok to support binaries
>>>     changing addresses (the only thing I'm worried is if
>>>     some host that uses function descriptors allocates them
>>>     dynamically instead of having them somewhere in the
>>>     executable)
>>> 5) maybe add a gengtype warning if it sees in GTY tracked
>>>     structure a function pointer without that new callback
>>>     option
>> So, here is 1), 2), 3) implemented.  With this patch alone,
>> g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
>> function::x_range_query member, which is set to &global_ranges on
>> cfun creation and is:
>>    range_query * GTY ((skip)) x_range_query;
>> which means when a PIE binary writes PCH and a PIE binary loaded
>> at a different address loads it, cfun->x_range_query might be a garbage
>> pointer.  We can either apply a patch like the attached one after
>> this inline patch, but then probably callback is misnamed and we should
>> rename it to relocate_and_skip or something similar.  Or we could
>> e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
>> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.
>>
>> Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
>> the second patch, with it a few more, but nothing huge.  And for non-PIEs
>> there isn't really any extra work on the load side except freading two scalar
>> values and fseek.
> Here is an updated version (the previous version doesn't apply any longer
> in gt_pch_restore due to the line_maps saving/restoring changes).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux with
> --enable-host-shared in addition to normal configure options (and without
> Ada which doesn't even with the above options build PIC libgnat.a and links
> it) and a hack:
> --- gcc/configure.ac.jj	2021-10-28 22:12:31.569299780 +0200
> +++ gcc/configure.ac	2021-11-09 11:34:33.453776105 +0100
> @@ -7566,7 +7566,7 @@ AC_CACHE_CHECK([for -no-pie option],
>        [gcc_cv_no_pie=no])
>      LDFLAGS="$saved_LDFLAGS"])
>   if test "$gcc_cv_no_pie" = "yes"; then
> -  NO_PIE_FLAG="-no-pie"
> +  NO_PIE_FLAG="-pie"
>   fi
>   AC_SUBST([NO_PIE_FLAG])
>   
> to force binaries be PIE, no regressions against non-PIC/PIE build
> without this patch.  Ok for trunk?
>
> 2021-11-18  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR pch/71934
> gcc/
> 	* ggc.h (gt_pch_note_callback): Declare.
> 	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
> 	(callback_type): Declare.
> 	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
> 	(callback_type): New variable.
> 	(process_gc_options): Add CALLBACK argument, handle callback
> 	option.
> 	(set_gc_used_type): Adjust process_gc_options caller, if callback,
> 	set type to &callback_type.
> 	(output_mangled_typename): Handle TYPE_CALLBACK.
> 	(walk_type): Likewise.  Handle callback option.
> 	(write_types_process_field): Handle TYPE_CALLBACK.
> 	(write_types_local_user_process_field): Likewise.
> 	(write_types_local_process_field): Likewise.
> 	(write_root): Likewise.
> 	(dump_typekind): Likewise.
> 	(dump_type): Likewise.
> 	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
> 	(state_writer::write_state_callback_type): New method.
> 	(state_writer::write_state_type): Handle TYPE_CALLBACK.
> 	(read_state_callback_type): New function.
> 	(read_state_type): Handle TYPE_CALLBACK.
> 	* ggc-common.c (callback_vec): New variable.
> 	(gt_pch_note_callback): New function.
> 	(gt_pch_save): Stream out gt_pch_save function address and relocation
> 	table.
> 	(gt_pch_restore): Stream in saved gt_pch_save function address and
> 	relocation table and apply relocations if needed.
> 	* doc/gty.texi (callback): Document new GTY option.
> 	* varasm.c (get_unnamed_section): Change callback argument's type and
> 	last argument's type from const void * to const char *.
> 	(output_section_asm_op): Change argument's type from const void *
> 	to const char *, remove unnecessary cast.
> 	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
> 	from language member.
> 	* output.h (unnamed_section_callback): Change argument type from
> 	const void * to const char *.
> 	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
> 	for callback member.  Change data member type from const void *
> 	to const char *.
> 	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
> 	for callback member.
> 	(get_unnamed_section): Change callback argument's type and
> 	last argument's type from const void * to const char *.
> 	(output_section_asm_op): Change argument's type from const void *
> 	to const char *.
> 	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
> 	Remove unneeded cast.
> 	* config/darwin.c (output_objc_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
> 	(som_output_comdat_data_section_asm_op): Likewise.
> 	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
> 	Likewise.
> 	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
> 	of dereferencing directive hardcode variable names and decide based on
> 	whether directive is NULL or not.
> 	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
> 	of dereferencing directive hardcode variable names and decide based on
> 	whether directive is NULL or not.
> 	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
> gcc/c-family/
> 	* c-pch.c (struct c_pch_validity): Remove pch_init member.
> 	(pch_init): Don't initialize v.pch_init.
> 	(c_common_valid_pch): Don't warn and punt if .text addresses change.
> libcpp/
> 	* include/line-map.h (class line_maps): Add GTY((callback)) to
> 	reallocator and round_alloc_size members.
You know this code better than anyone I suspect.  If it's working and 
you're confortable with it, I suggest going forward with it.

Jeff

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH] pch, v2: Add support for PCH for relocatable executables
  2021-11-18  8:04               ` [PATCH] pch, v2: Add support for PCH for relocatable executables Jakub Jelinek
  2021-12-02 18:26                 ` Jeff Law
@ 2021-12-06 10:00                 ` Martin Liška
  2021-12-06 10:23                   ` [committed] avr: Fix AVR build [PR71934] Jakub Jelinek
  1 sibling, 1 reply; 39+ messages in thread
From: Martin Liška @ 2021-12-06 10:00 UTC (permalink / raw)
  To: Jakub Jelinek, Iain Sandoe, Richard Biener, Jeff Law; +Cc: gcc-patches

On 11/18/21 09:04, Jakub Jelinek via Gcc-patches wrote:
> On Mon, Nov 08, 2021 at 08:48:07PM +0100, Jakub Jelinek via Gcc-patches wrote:
>> On Mon, Nov 08, 2021 at 12:46:04PM +0100, Jakub Jelinek via Gcc-patches wrote:
>>> So, if we want to make PCH work for PIEs, I'd say we can:
>>> 1) add a new GTY option, say callback, which would act like
>>>     skip for non-PCH and for PCH would make us skip it but
>>>     remember for address bias translation
>>> 2) drop the skip for tree_translation_unit_decl::language
>>> 3) change get_unnamed_section to have const char * as
>>>     last argument instead of const void *, change
>>>     unnamed_section::data also to const char * and update
>>>     everything related to that
>>> 4) maybe add a host hook whether it is ok to support binaries
>>>     changing addresses (the only thing I'm worried is if
>>>     some host that uses function descriptors allocates them
>>>     dynamically instead of having them somewhere in the
>>>     executable)
>>> 5) maybe add a gengtype warning if it sees in GTY tracked
>>>     structure a function pointer without that new callback
>>>     option
>>
>> So, here is 1), 2), 3) implemented.  With this patch alone,
>> g++.dg/pch/system-2.C test ICEs.  This is because GCC 12 has added
>> function::x_range_query member, which is set to &global_ranges on
>> cfun creation and is:
>>    range_query * GTY ((skip)) x_range_query;
>> which means when a PIE binary writes PCH and a PIE binary loaded
>> at a different address loads it, cfun->x_range_query might be a garbage
>> pointer.  We can either apply a patch like the attached one after
>> this inline patch, but then probably callback is misnamed and we should
>> rename it to relocate_and_skip or something similar.  Or we could
>> e.g. during gimplification overwrite cfun->x_range_query = &global_ranges.
>> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp.
>>
>> Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
>> the second patch, with it a few more, but nothing huge.  And for non-PIEs
>> there isn't really any extra work on the load side except freading two scalar
>> values and fseek.
> 
> Here is an updated version (the previous version doesn't apply any longer
> in gt_pch_restore due to the line_maps saving/restoring changes).
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux with
> --enable-host-shared in addition to normal configure options (and without
> Ada which doesn't even with the above options build PIC libgnat.a and links
> it) and a hack:
> --- gcc/configure.ac.jj	2021-10-28 22:12:31.569299780 +0200
> +++ gcc/configure.ac	2021-11-09 11:34:33.453776105 +0100
> @@ -7566,7 +7566,7 @@ AC_CACHE_CHECK([for -no-pie option],
>        [gcc_cv_no_pie=no])
>      LDFLAGS="$saved_LDFLAGS"])
>   if test "$gcc_cv_no_pie" = "yes"; then
> -  NO_PIE_FLAG="-no-pie"
> +  NO_PIE_FLAG="-pie"
>   fi
>   AC_SUBST([NO_PIE_FLAG])
>   
> to force binaries be PIE, no regressions against non-PIC/PIE build
> without this patch.  Ok for trunk?
> 
> 2021-11-18  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR pch/71934
> gcc/
> 	* ggc.h (gt_pch_note_callback): Declare.
> 	* gengtype.h (enum typekind): Add TYPE_CALLBACK.
> 	(callback_type): Declare.
> 	* gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
> 	(callback_type): New variable.
> 	(process_gc_options): Add CALLBACK argument, handle callback
> 	option.
> 	(set_gc_used_type): Adjust process_gc_options caller, if callback,
> 	set type to &callback_type.
> 	(output_mangled_typename): Handle TYPE_CALLBACK.
> 	(walk_type): Likewise.  Handle callback option.
> 	(write_types_process_field): Handle TYPE_CALLBACK.
> 	(write_types_local_user_process_field): Likewise.
> 	(write_types_local_process_field): Likewise.
> 	(write_root): Likewise.
> 	(dump_typekind): Likewise.
> 	(dump_type): Likewise.
> 	* gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
> 	(state_writer::write_state_callback_type): New method.
> 	(state_writer::write_state_type): Handle TYPE_CALLBACK.
> 	(read_state_callback_type): New function.
> 	(read_state_type): Handle TYPE_CALLBACK.
> 	* ggc-common.c (callback_vec): New variable.
> 	(gt_pch_note_callback): New function.
> 	(gt_pch_save): Stream out gt_pch_save function address and relocation
> 	table.
> 	(gt_pch_restore): Stream in saved gt_pch_save function address and
> 	relocation table and apply relocations if needed.
> 	* doc/gty.texi (callback): Document new GTY option.
> 	* varasm.c (get_unnamed_section): Change callback argument's type and
> 	last argument's type from const void * to const char *.
> 	(output_section_asm_op): Change argument's type from const void *
> 	to const char *, remove unnecessary cast.
> 	* tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
> 	from language member.
> 	* output.h (unnamed_section_callback): Change argument type from
> 	const void * to const char *.
> 	(struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
> 	for callback member.  Change data member type from const void *
> 	to const char *.
> 	(struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
> 	for callback member.
> 	(get_unnamed_section): Change callback argument's type and
> 	last argument's type from const void * to const char *.
> 	(output_section_asm_op): Change argument's type from const void *
> 	to const char *.
> 	* config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
> 	Remove unneeded cast.
> 	* config/darwin.c (output_objc_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	* config/pa/pa.c (som_output_text_section_asm_op): Likewise.
> 	(som_output_comdat_data_section_asm_op): Likewise.
> 	* config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
> 	Likewise.
> 	(rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
> 	of dereferencing directive hardcode variable names and decide based on
> 	whether directive is NULL or not.
> 	(rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	(rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
> 	of dereferencing directive hardcode variable names and decide based on
> 	whether directive is NULL or not.
> 	(rs6000_xcoff_output_toc_section_asm_op): Change argument's type
> 	from const void * to const char *.
> 	(rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
> gcc/c-family/
> 	* c-pch.c (struct c_pch_validity): Remove pch_init member.
> 	(pch_init): Don't initialize v.pch_init.
> 	(c_common_valid_pch): Don't warn and punt if .text addresses change.
> libcpp/
> 	* include/line-map.h (class line_maps): Add GTY((callback)) to
> 	reallocator and round_alloc_size members.
> 
> --- gcc/ggc.h.jj	2021-08-19 11:42:27.366422386 +0200
> +++ gcc/ggc.h	2021-11-08 16:46:02.604618109 +0100
> @@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void
>   /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
>   extern int gt_pch_note_object (void *, void *, gt_note_pointers);
>   
> +/* Used by the gt_pch_p_* routines.  Register address of a callback
> +   pointer.  */
> +extern void gt_pch_note_callback (void *, void *);
> +
>   /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
>      function.  */
>   extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
> --- gcc/gengtype.h.jj	2021-07-20 10:08:09.892687719 +0200
> +++ gcc/gengtype.h	2021-11-08 15:19:59.194210185 +0100
> @@ -154,6 +154,9 @@ enum typekind {
>     TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
>     TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
>     TYPE_ARRAY,           /* Array of GTY-ed types.  */
> +  TYPE_CALLBACK,	/* A function pointer that needs relocation if
> +			   the executable has been loaded at a different
> +			   address.  */
>     TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
>                              Various languages may have homonymous but
>                              different structs.  */
> @@ -331,6 +334,9 @@ extern struct type string_type;
>   extern struct type scalar_nonchar;
>   extern struct type scalar_char;
>   
> +/* The one and only TYPE_CALLBACK.  */
> +extern struct type callback_type;
> +
>   /* Test if a type is a union, either a plain one or a language
>      specific one.  */
>   #define UNION_P(x)					\
> --- gcc/gengtype.c.jj	2021-10-04 10:16:10.885140187 +0200
> +++ gcc/gengtype.c	2021-11-08 16:30:41.981750183 +0100
> @@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil,
>     int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
>     int nb_lang_struct = 0;
>     int nb_user_struct = 0, nb_undefined = 0;
> +  int nb_callback = 0;
>     type_p p = NULL;
>     for (p = t; p; p = p->next)
>       {
> @@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil,
>   	case TYPE_ARRAY:
>   	  nb_array++;
>   	  break;
> +	case TYPE_CALLBACK:
> +	  nb_callback++;
> +	  break;
>   	case TYPE_LANG_STRUCT:
>   	  nb_lang_struct++;
>   	  break;
> @@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil,
>       fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
>     if (nb_pointer > 0 || nb_array > 0)
>       fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
> +  if (nb_callback > 0)
> +    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
>     if (nb_lang_struct > 0)
>       fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
>     if (nb_user_struct > 0)
> @@ -495,6 +501,10 @@ struct type scalar_char = {
>     TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
>   };
>   
> +struct type callback_type = {
> +  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
> +};
> +
>   /* Lists of various things.  */
>   
>   pair_p typedefs = NULL;
> @@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
>   
>   static void
>   process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
> -		    int *length, int *skip, type_p *nested_ptr)
> +		    int *length, int *skip, int *callback, type_p *nested_ptr)
>   {
>     options_p o;
>     for (o = opt; o; o = o->next)
> @@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum
>         *length = 1;
>       else if (strcmp (o->name, "skip") == 0)
>         *skip = 1;
> +    else if (strcmp (o->name, "callback") == 0)
> +      *callback = 1;
>       else if (strcmp (o->name, "nested_ptr") == 0
>   	     && o->kind == OPTION_NESTED)
>         *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
> @@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used
>   	type_p dummy2;
>   	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
>   
> -	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
> +	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
>   			    &dummy2);
>   
>   	if (t->u.s.base_class)
> @@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used
>   	    int maybe_undef = 0;
>   	    int length = 0;
>   	    int skip = 0;
> +	    int callback = 0;
>   	    type_p nested_ptr = NULL;
>   	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
> -				&nested_ptr);
> +				&callback, &nested_ptr);
>   
>   	    if (nested_ptr && f->type->kind == TYPE_POINTER)
>   	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
> @@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used
>   	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
>   	    else if (skip)
>   	      ;			/* target type is not used through this field */
> +	    else if (callback)
> +	      f->type = &callback_type;
>   	    else
>   	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
>   	  }
> @@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, cons
>         {
>         case TYPE_NONE:
>         case TYPE_UNDEFINED:
> +      case TYPE_CALLBACK:
>   	gcc_unreachable ();
>   	break;
>         case TYPE_POINTER:
> @@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_da
>         ;
>       else if (strcmp (oo->name, "for_user") == 0)
>         ;
> +    else if (strcmp (oo->name, "callback") == 0)
> +      ;
>       else
>         error_at_line (d->line, "unknown option `%s'\n", oo->name);
>   
> @@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_da
>       {
>       case TYPE_SCALAR:
>       case TYPE_STRING:
> +    case TYPE_CALLBACK:
>         d->process_field (t, d);
>         break;
>   
> @@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, con
>         break;
>   
>       case TYPE_SCALAR:
> +    case TYPE_CALLBACK:
>         break;
>   
>       case TYPE_ARRAY:
> @@ -3820,6 +3840,7 @@ write_types_local_user_process_field (ty
>         break;
>   
>       case TYPE_SCALAR:
> +    case TYPE_CALLBACK:
>         break;
>   
>       case TYPE_ARRAY:
> @@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p
>       case TYPE_SCALAR:
>         break;
>   
> +    case TYPE_CALLBACK:
> +      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
> +	       d->prev_val[3]);
> +      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
> +	       d->indent, "", d->val);
> +      break;
> +
>       case TYPE_ARRAY:
>       case TYPE_NONE:
>       case TYPE_UNDEFINED:
> @@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p t
>       case TYPE_UNDEFINED:
>       case TYPE_UNION:
>       case TYPE_LANG_STRUCT:
> +    case TYPE_CALLBACK:
>         error_at_line (line, "global `%s' is unimplemented type", name);
>       }
>   }
> @@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind
>       case TYPE_ARRAY:
>         printf ("TYPE_ARRAY");
>         break;
> +    case TYPE_CALLBACK:
> +      printf ("TYPE_CALLBACK");
> +      break;
>       case TYPE_LANG_STRUCT:
>         printf ("TYPE_LANG_STRUCT");
>         break;
> @@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
>   	      t->u.scalar_is_char ? "true" : "false");
>         break;
>       case TYPE_STRING:
> +    case TYPE_CALLBACK:
>         break;
>       case TYPE_STRUCT:
>       case TYPE_UNION:
> --- gcc/varasm.c.jj	2021-09-28 11:34:29.343147261 +0200
> +++ gcc/varasm.c	2021-11-08 13:26:15.032606040 +0100
> @@ -250,8 +250,8 @@ object_block_hasher::hash (object_block
>   /* Return a new unnamed section with the given fields.  */
>   
>   section *
> -get_unnamed_section (unsigned int flags, void (*callback) (const void *),
> -		     const void *data)
> +get_unnamed_section (unsigned int flags, void (*callback) (const char *),
> +		     const char *data)
>   {
>     section *sect;
>   
> @@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
>      a get_unnamed_section callback.  */
>   
>   void
> -output_section_asm_op (const void *directive)
> +output_section_asm_op (const char *directive)
>   {
> -  fprintf (asm_out_file, "%s\n", (const char *) directive);
> +  fprintf (asm_out_file, "%s\n", directive);
>   }
>   
>   /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
> --- gcc/ggc-common.c.jj	2021-11-08 11:09:50.280318624 +0100
> +++ gcc/ggc-common.c	2021-11-17 20:10:07.088187637 +0100
> @@ -246,6 +246,7 @@ saving_hasher::equal (const ptr_data *p1
>   }
>   
>   static hash_table<saving_hasher> *saving_htab;
> +static vec<void *> callback_vec;
>   
>   /* Register an object in the hash table.  */
>   
> @@ -278,6 +279,23 @@ gt_pch_note_object (void *obj, void *not
>     return 1;
>   }
>   
> +/* Register address of a callback pointer.  */
> +void
> +gt_pch_note_callback (void *obj, void *base)
> +{
> +  void *ptr;
> +  memcpy (&ptr, obj, sizeof (void *));
> +  if (ptr != NULL)
> +    {
> +      struct ptr_data *data
> +	= (struct ptr_data *)
> +	  saving_htab->find_with_hash (base, POINTER_HASH (base));
> +      gcc_assert (data);
> +      callback_vec.safe_push ((char *) data->new_addr
> +			      + ((char *) obj - (char *) base));
> +    }
> +}
> +
>   /* Register an object in the hash table.  */
>   
>   void
> @@ -576,10 +594,20 @@ gt_pch_save (FILE *f)
>     ggc_pch_finish (state.d, state.f);
>     gt_pch_fixup_stringpool ();
>   
> +  unsigned num_callbacks = callback_vec.length ();
> +  void (*pch_save) (FILE *) = &gt_pch_save;
> +  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
> +      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
> +      || (num_callbacks
> +	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
> +		     f) != num_callbacks))
> +    fatal_error (input_location, "cannot write PCH file: %m");
> +
>     XDELETE (state.ptrs);
>     XDELETE (this_object);
>     delete saving_htab;
>     saving_htab = NULL;
> +  callback_vec.release ();
>   }
>   
>   /* Read the state of the compiler back in from F.  */
> @@ -661,6 +689,30 @@ gt_pch_restore (FILE *f)
>   
>     gt_pch_restore_stringpool ();
>   
> +  void (*pch_save) (FILE *);
> +  unsigned num_callbacks;
> +  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
> +      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
> +    fatal_error (input_location, "cannot read PCH file: %m");
> +  if (pch_save != &gt_pch_save)
> +    {
> +      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
> +      void **ptrs = XNEWVEC (void *, num_callbacks);
> +      unsigned i;
> +
> +      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
> +	fatal_error (input_location, "cannot read PCH file: %m");
> +      for (i = 0; i < num_callbacks; ++i)
> +	{
> +	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
> +	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
> +	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
> +	}
> +      XDELETE (ptrs);
> +    }
> +  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
> +    fatal_error (input_location, "cannot read PCH file: %m");
> +
>     /* Barring corruption of the PCH file, the restored line table should be
>        complete and usable.  */
>     line_table = new_line_table;
> --- gcc/doc/gty.texi.jj	2021-08-19 11:42:27.363422428 +0200
> +++ gcc/doc/gty.texi	2021-11-08 17:13:46.613882767 +0100
> @@ -197,6 +197,15 @@ If @code{skip} is applied to a field, th
>   This is somewhat dangerous; the only safe use is in a union when one
>   field really isn't ever used.
>   
> +@findex callback
> +@item callback
> +
> +@code{callback} should be applied to fields with pointer to function type
> +and causes the field to be ignored similarly to @code{skip}, except when
> +writing PCH and the field is non-NULL it will remember the field's address
> +for relocation purposes if the process writing PCH has different load base
> +from a process reading PCH.
> +
>   @findex for_user
>   @item for_user
>   
> --- gcc/tree-core.h.jj	2021-11-04 12:27:02.377298411 +0100
> +++ gcc/tree-core.h	2021-11-08 13:24:04.496465555 +0100
> @@ -1964,7 +1964,7 @@ struct GTY(()) tree_function_decl {
>   struct GTY(()) tree_translation_unit_decl {
>     struct tree_decl_common common;
>     /* Source language of this translation unit.  Used for DWARF output.  */
> -  const char * GTY((skip(""))) language;
> +  const char *language;
>     /* TODO: Non-optimization used to build this translation unit.  */
>     /* TODO: Root of a partial DWARF tree for global types and decls.  */
>   };
> --- gcc/gengtype-state.c.jj	2021-07-20 10:08:09.891687732 +0200
> +++ gcc/gengtype-state.c	2021-11-08 15:19:16.157824146 +0100
> @@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
>       case TYPE_STRING:
>       case TYPE_POINTER:
>       case TYPE_ARRAY:
> +    case TYPE_CALLBACK:
>         return NULL;
>       default:
>         gcc_unreachable ();
> @@ -171,6 +172,7 @@ private:
>     void write_state_version (const char *version);
>     void write_state_scalar_type (type_p current);
>     void write_state_string_type (type_p current);
> +  void write_state_callback_type (type_p current);
>     void write_state_undefined_type (type_p current);
>     void write_state_struct_union_type (type_p current, const char *kindstr);
>     void write_state_struct_type (type_p current);
> @@ -898,6 +900,20 @@ state_writer::write_state_string_type (t
>       fatal ("Unexpected type in write_state_string_type");
>   }
>   
> +/* Write the callback type.  There is only one such thing! */
> +void
> +state_writer::write_state_callback_type (type_p current)
> +{
> +  if (current == &callback_type)
> +    {
> +      write_any_indent (0);
> +      fprintf (state_file, "callback ");
> +      write_state_common_type_content (current);
> +    }
> +  else
> +    fatal ("Unexpected type in write_state_callback_type");
> +}
> +
>   /* Write an undefined type.  */
>   void
>   state_writer::write_state_undefined_type (type_p current)
> @@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p c
>   	case TYPE_STRING:
>   	  write_state_string_type (current);
>   	  break;
> +	case TYPE_CALLBACK:
> +	  write_state_callback_type (current);
> +	  break;
>   	}
>       }
>   
> @@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
>     read_state_common_type_content (*type);
>   }
>   
> +/* Read the callback_type.  */
> +static void
> +read_state_callback_type (type_p *type)
> +{
> +  *type = &callback_type;
> +  read_state_common_type_content (*type);
> +}
> +
>   
>   /* Read a lang_bitmap representing a set of GCC front-end languages.  */
>   static void
> @@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
>   	      next_state_tokens (1);
>   	      read_state_string_type (current);
>   	    }
> +	  else if (state_token_is_name (t0, "callback"))
> +	    {
> +	      next_state_tokens (1);
> +	      read_state_callback_type (current);
> +	    }
>   	  else if (state_token_is_name (t0, "undefined"))
>   	    {
>   	      *current = XCNEW (struct type);
> --- gcc/output.h.jj	2021-09-28 11:34:29.235148754 +0200
> +++ gcc/output.h	2021-11-08 16:26:01.172755377 +0100
> @@ -470,7 +470,7 @@ struct GTY(()) named_section {
>   
>   /* A callback that writes the assembly code for switching to an unnamed
>      section.  The argument provides callback-specific data.  */
> -typedef void (*unnamed_section_callback) (const void *);
> +typedef void (*unnamed_section_callback) (const char *);
>   
>   /* Information about a SECTION_UNNAMED section.  */
>   struct GTY(()) unnamed_section {
> @@ -478,8 +478,8 @@ struct GTY(()) unnamed_section {
>   
>     /* The callback used to switch to the section, and the data that
>        should be passed to the callback.  */
> -  unnamed_section_callback GTY ((skip)) callback;
> -  const void *GTY ((skip)) data;
> +  unnamed_section_callback GTY ((callback)) callback;
> +  const char *data;
>   
>     /* The next entry in the chain of unnamed sections.  */
>     section *next;
> @@ -503,7 +503,7 @@ struct GTY(()) noswitch_section {
>     struct section_common common;
>   
>     /* The callback used to assemble decls in this section.  */
> -  noswitch_section_callback GTY ((skip)) callback;
> +  noswitch_section_callback GTY ((callback)) callback;
>   };
>   
>   /* Information about a section, which may be named or unnamed.  */
> @@ -538,8 +538,8 @@ extern GTY(()) section *bss_noswitch_sec
>   extern GTY(()) section *in_section;
>   extern GTY(()) bool in_cold_section_p;
>   
> -extern section *get_unnamed_section (unsigned int, void (*) (const void *),
> -				     const void *);
> +extern section *get_unnamed_section (unsigned int, void (*) (const char *),
> +				     const char *);
>   extern section *get_section (const char *, unsigned int, tree,
>   			     bool not_existing = false);
>   extern section *get_named_section (tree, const char *, int);
> @@ -561,7 +561,7 @@ extern section *get_cdtor_priority_secti
>   
>   extern bool unlikely_text_section_p (section *);
>   extern void switch_to_section (section *, tree = nullptr);
> -extern void output_section_asm_op (const void *);
> +extern void output_section_asm_op (const char *);
>   
>   extern void record_tm_clone_pair (tree, tree);
>   extern void finish_tm_clone_pairs (void);
> --- gcc/config/avr/avr.c.jj	2021-07-15 10:16:12.873583249 +0200
> +++ gcc/config/avr/avr.c	2021-11-08 13:28:30.215676387 +0100
> @@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const voi
>   /* Unnamed section callback for progmem*.data sections.  */
>   
>   static void
> -avr_output_progmem_section_asm_op (const void *data)
> +avr_output_progmem_section_asm_op (const char *data)
>   {
> -  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
> -           (const char*) data);
> +  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
>   }
>   
>   
> --- gcc/config/darwin.c.jj	2021-10-21 10:23:27.450834602 +0200
> +++ gcc/config/darwin.c	2021-11-08 13:27:19.106691421 +0100
> @@ -134,7 +134,7 @@ int emit_aligned_common = false;
>      DIRECTIVE is as for output_section_asm_op.  */
>   
>   static void
> -output_objc_section_asm_op (const void *directive)
> +output_objc_section_asm_op (const char *directive)
>   {
>     static bool been_here = false;
>   
> --- gcc/config/pa/pa.c.jj	2021-10-27 09:00:28.762277456 +0200
> +++ gcc/config/pa/pa.c	2021-11-08 13:29:41.935652629 +0100
> @@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t
>      to the default text subspace.  */
>   
>   static void
> -som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
> +som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>   {
>     gcc_assert (TARGET_SOM);
>     if (TARGET_GAS)
> @@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const vo
>      sections.  This function is only used with SOM.  */
>   
>   static void
> -som_output_comdat_data_section_asm_op (const void *data)
> +som_output_comdat_data_section_asm_op (const char *data)
>   {
>     in_section = NULL;
>     output_section_asm_op (data);
> --- gcc/config/rs6000/rs6000.c.jj	2021-11-05 00:43:22.476626062 +0100
> +++ gcc/config/rs6000/rs6000.c	2021-11-08 13:43:22.415940789 +0100
> @@ -20597,7 +20597,7 @@ rs6000_ms_bitfield_layout_p (const_tree
>   /* A get_unnamed_section callback, used for switching to toc_section.  */
>   
>   static void
> -rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
> +rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>   {
>     if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
>         && TARGET_MINIMAL_TOC)
> @@ -21301,35 +21301,39 @@ rs6000_xcoff_asm_globalize_label (FILE *
>      points to the section string variable.  */
>   
>   static void
> -rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
> +rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
>   {
>     fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
> -	   *(const char *const *) directive,
> +	   directive
> +	   ? xcoff_private_rodata_section_name
> +	   : xcoff_read_only_section_name,
>   	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>   }
>   
>   /* Likewise for read-write sections.  */
>   
>   static void
> -rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
> +rs6000_xcoff_output_readwrite_section_asm_op (const char *)
>   {
>     fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
> -	   *(const char *const *) directive,
> +	   xcoff_private_data_section_name,
>   	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>   }
>   
>   static void
> -rs6000_xcoff_output_tls_section_asm_op (const void *directive)
> +rs6000_xcoff_output_tls_section_asm_op (const char *directive)
>   {
>     fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
> -	   *(const char *const *) directive,
> +	   directive
> +	   ? xcoff_private_data_section_name
> +	   : xcoff_tls_data_section_name,
>   	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
>   }
>   
>   /* A get_unnamed_section callback, used for switching to toc_section.  */
>   
>   static void
> -rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
> +rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
>   {
>     if (TARGET_MINIMAL_TOC)
>       {
> @@ -21356,26 +21360,26 @@ rs6000_xcoff_asm_init_sections (void)
>   {
>     read_only_data_section
>       = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
> -			   &xcoff_read_only_section_name);
> +			   NULL);
>   
>     private_data_section
>       = get_unnamed_section (SECTION_WRITE,
>   			   rs6000_xcoff_output_readwrite_section_asm_op,
> -			   &xcoff_private_data_section_name);
> +			   NULL);
>   
>     read_only_private_data_section
>       = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
> -			   &xcoff_private_rodata_section_name);
> +			   "");
>   
>     tls_data_section
>       = get_unnamed_section (SECTION_TLS,
>   			   rs6000_xcoff_output_tls_section_asm_op,
> -			   &xcoff_tls_data_section_name);
> +			   NULL);
>   
>     tls_private_data_section
>       = get_unnamed_section (SECTION_TLS,
>   			   rs6000_xcoff_output_tls_section_asm_op,
> -			   &xcoff_private_data_section_name);
> +			   "");
>   
>     toc_section
>       = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
> --- gcc/c-family/c-pch.c.jj	2021-06-02 10:08:14.149450407 +0200
> +++ gcc/c-family/c-pch.c	2021-11-08 17:34:17.302343697 +0100
> @@ -54,7 +54,6 @@ struct c_pch_validity
>   {
>     uint32_t pch_write_symbols;
>     signed char match[MATCH_SIZE];
> -  void (*pch_init) (void);
>     size_t target_data_length;
>   };
>   
> @@ -117,7 +116,6 @@ pch_init (void)
>   	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
>         }
>     }
> -  v.pch_init = &pch_init;
>     target_validity = targetm.get_pch_validity (&v.target_data_length);
>   
>     if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
> @@ -278,19 +276,6 @@ c_common_valid_pch (cpp_reader *pfile, c
>   	}
>     }
>   
> -  /* If the text segment was not loaded at the same address as it was
> -     when the PCH file was created, function pointers loaded from the
> -     PCH will not be valid.  We could in theory remap all the function
> -     pointers, but no support for that exists at present.
> -     Since we have the same executable, it should only be necessary to
> -     check one function.  */
> -  if (v.pch_init != &pch_init)
> -    {
> -      cpp_warning (pfile, CPP_W_INVALID_PCH,
> -		   "%s: had text segment at different address", name);
> -      return 2;
> -    }
> -
>     /* Check the target-specific validity data.  */
>     {
>       void *this_file_data = xmalloc (v.target_data_length);
> --- libcpp/include/line-map.h.jj	2021-11-01 14:37:06.697853154 +0100
> +++ libcpp/include/line-map.h	2021-11-08 16:16:34.562837006 +0100
> @@ -803,11 +803,11 @@ public:
>     unsigned int max_column_hint;
>   
>     /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
> -  line_map_realloc reallocator;
> +  line_map_realloc GTY((callback)) reallocator;
>   
>     /* The allocators' function used to know the actual size it
>        allocated, for a certain allocation size requested.  */
> -  line_map_round_alloc_size_func round_alloc_size;
> +  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
>   
>     struct location_adhoc_data_map location_adhoc_data_map;
>   
> 
> 
> 	Jakub
> 

Jakub, I think the patch broke avr-linux target:

g++  -fno-PIE -c   -g   -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE   -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wno-error=format-diag -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fno-common  -DHAVE_CONFIG_H -I. -I. -I/home/marxin/Programming/gcc/gcc -I/home/marxin/Programming/gcc/gcc/. -I/home/marxin/Programming/gcc/gcc/../include -I/home/marxin/Programming/gcc/gcc/../libcpp/include -I/home/marxin/Programming/gcc/gcc/../libcody  -I/home/marxin/Programming/gcc/gcc/../libdecnumber -I/home/marxin/Programming/gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I/home/marxin/Programming/gcc/gcc/../libbacktrace   -o avr.o -MT avr.o -MMD -MP -MF ./.deps/avr.TPo /home/marxin/Programming/gcc/gcc/config/avr/avr.c
/home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_output_data_section_asm_op(const void*)’:
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:10097:26: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]
10097 |   output_section_asm_op (data);
       |                          ^~~~
       |                          |
       |                          const void*
In file included from /home/marxin/Programming/gcc/gcc/config/avr/avr.c:49:
/home/marxin/Programming/gcc/gcc/output.h:564:36: note:   initializing argument 1 of ‘void output_section_asm_op(const char*)’
   564 | extern void output_section_asm_op (const char *);
       |                                    ^~~~~~~~~~~~
/home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_output_bss_section_asm_op(const void*)’:
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:10110:26: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]
10110 |   output_section_asm_op (data);
       |                          ^~~~
       |                          |
       |                          const void*
In file included from /home/marxin/Programming/gcc/gcc/config/avr/avr.c:49:
/home/marxin/Programming/gcc/gcc/output.h:564:36: note:   initializing argument 1 of ‘void output_section_asm_op(const char*)’
   564 | extern void output_section_asm_op (const char *);
       |                                    ^~~~~~~~~~~~
/home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_asm_init_sections()’:
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:10135:47: error: invalid conversion from ‘void (*)(const void*)’ to ‘unnamed_section_callback’ {aka ‘void (*)(const char*)’} [-fpermissive]
10135 |     readonly_data_section->unnamed.callback = avr_output_data_section_asm_op;
       |                                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       |                                               |
       |                                               void (*)(const void*)
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:10136:36: error: invalid conversion from ‘void (*)(const void*)’ to ‘unnamed_section_callback’ {aka ‘void (*)(const char*)’} [-fpermissive]
10136 |   data_section->unnamed.callback = avr_output_data_section_asm_op;
       |                                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       |                                    |
       |                                    void (*)(const void*)
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:10137:35: error: invalid conversion from ‘void (*)(const void*)’ to ‘unnamed_section_callback’ {aka ‘void (*)(const char*)’} [-fpermissive]
10137 |   bss_section->unnamed.callback = avr_output_bss_section_asm_op;
       |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       |                                   |
       |                                   void (*)(const void*)
/home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘unsigned int avr_section_type_flags(tree, const char*, int)’:
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:10197:21: warning: space followed by punctuation character ‘.’ [-Wformat-diag]
10197 |         warning (0, "only uninitialized variables can be placed in the "
       |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10198 |                  ".noinit section");
       |                  ~~~~~~~~~~~~~~~~~
/home/marxin/Programming/gcc/gcc/config/avr/avr.c: At global scope:
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:12765:1: warning: ‘void avr_asm_out_dtor(rtx, int)’ defined but not used [-Wunused-function]
12765 | avr_asm_out_dtor (rtx symbol, int priority)
       | ^~~~~~~~~~~~~~~~
/home/marxin/Programming/gcc/gcc/config/avr/avr.c:12755:1: warning: ‘void avr_asm_out_ctor(rtx, int)’ defined but not used [-Wunused-function]
12755 | avr_asm_out_ctor (rtx symbol, int priority)
       | ^~~~~~~~~~~~~~~~
make: *** [Makefile:2413: avr.o] Error 1

Cheers,
Martin

^ permalink raw reply	[flat|nested] 39+ messages in thread

* [committed] avr: Fix AVR build [PR71934]
  2021-12-06 10:00                 ` Martin Liška
@ 2021-12-06 10:23                   ` Jakub Jelinek
  2021-12-06 11:28                     ` Martin Liška
  0 siblings, 1 reply; 39+ messages in thread
From: Jakub Jelinek @ 2021-12-06 10:23 UTC (permalink / raw)
  To: Martin Liška; +Cc: Iain Sandoe, Richard Biener, Jeff Law, gcc-patches

Hi!

On Mon, Dec 06, 2021 at 11:00:30AM +0100, Martin Liška wrote:
> Jakub, I think the patch broke avr-linux target:
>
> g++  -fno-PIE -c   -g   -DIN_GCC  -DCROSS_DIRECTORY_STRUCTURE   -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wno-erro
> /home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_output_data_section_asm_op(const void*)’:
> /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10097:26: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]

This patch fixes that.
Tested with a cross-compiler from x86_64-linux that it builds, committed
as obvious.
I didn't notice that because avr isn't creating those sections
with that hook as argument, but is overriding the hooks in already created
section structure.

2021-12-06  Jakub Jelinek  <jakub@redhat.com>

	PR pch/71934
	* config/avr/avr.c (avr_output_data_section_asm_op,
	avr_output_bss_section_asm_op): Change argument type from const void *
	to const char *.

--- gcc/config/avr/avr.c.jj	2021-12-03 11:03:10.479503638 +0100
+++ gcc/config/avr/avr.c	2021-12-06 11:16:31.102208406 +0100
@@ -10089,7 +10089,7 @@ avr_asm_asm_output_aligned_bss (FILE *fi
    to track need of __do_copy_data.  */
 
 static void
-avr_output_data_section_asm_op (const void *data)
+avr_output_data_section_asm_op (const char *data)
 {
   avr_need_copy_data_p = true;
 
@@ -10102,7 +10102,7 @@ avr_output_data_section_asm_op (const vo
    to track need of __do_clear_bss.  */
 
 static void
-avr_output_bss_section_asm_op (const void *data)
+avr_output_bss_section_asm_op (const char *data)
 {
   avr_need_clear_bss_p = true;
 


	Jakub


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [committed] avr: Fix AVR build [PR71934]
  2021-12-06 10:23                   ` [committed] avr: Fix AVR build [PR71934] Jakub Jelinek
@ 2021-12-06 11:28                     ` Martin Liška
  0 siblings, 0 replies; 39+ messages in thread
From: Martin Liška @ 2021-12-06 11:28 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Iain Sandoe, Richard Biener, Jeff Law, gcc-patches

On 12/6/21 11:23, Jakub Jelinek wrote:
> |This patch fixes that.|

Thanks for the quick fix!

Martin

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2021-12-06 11:28 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-04 20:02 [PATCH 0/4] config: Allow a host to opt out of PCH Iain Sandoe
2021-11-04 20:02 ` [PATCH 1/4] config: Add top-level flag to disable host PCH Iain Sandoe
2021-11-04 20:02   ` [PATCH 2/4] libstdc++: Adjust build of PCH files accounting configured host support Iain Sandoe
2021-11-04 20:02     ` [PATCH 3/4] libcpp: Honour a configuration without host support for PCH Iain Sandoe
2021-11-04 20:02       ` [PATCH 4/4] c-family, gcc: Allow configuring without " Iain Sandoe
     [not found]     ` <EB9AC754-904B-4877-AD17-94886712C10E@gmail.com>
2021-11-05 23:23       ` [PATCH 2/4] libstdc++: Adjust build of PCH files accounting configured host support Jonathan Wakely
2021-11-05  9:42 ` [PATCH 0/4] config: Allow a host to opt out of PCH Richard Biener
2021-11-05  9:54   ` Jakub Jelinek
2021-11-05 10:31     ` Richard Biener
2021-11-05 15:25       ` Jakub Jelinek
2021-11-05 16:37         ` Iain Sandoe
2021-11-08  7:16           ` Richard Biener
2021-11-08  7:43             ` Iain Sandoe
2021-11-08 11:46           ` Jakub Jelinek
2021-11-08 19:48             ` [PATCH] pch: Add support for PCH for relocatable executables Jakub Jelinek
2021-11-08 21:03               ` John David Anglin
2021-11-09  9:50                 ` Jakub Jelinek
2021-11-09  7:12               ` Richard Biener
2021-11-09  8:07                 ` Iain Sandoe
2021-11-09 11:40                   ` Iain Sandoe
2021-11-09 12:18                     ` Jakub Jelinek
2021-11-10  8:14                       ` Iain Sandoe
2021-11-10 20:24                         ` Iain Sandoe
2021-11-13 20:32                           ` Iain Sandoe
2021-11-16  8:52                             ` Jakub Jelinek
2021-11-09  9:44                 ` Jakub Jelinek
2021-11-09 11:32                   ` Jakub Jelinek
2021-11-09 12:03                     ` Richard Biener
2021-11-09 12:29                       ` Jakub Jelinek
2021-11-09 14:41                         ` Andrew MacLeod
2021-11-09 14:58                           ` Jakub Jelinek
2021-11-09 15:23                             ` Andrew MacLeod
2021-11-09 15:28                               ` Jakub Jelinek
2021-11-09 18:29                                 ` [COMMITTED] Keep x_range_query NULL for global ranges Andrew MacLeod
2021-11-18  8:04               ` [PATCH] pch, v2: Add support for PCH for relocatable executables Jakub Jelinek
2021-12-02 18:26                 ` Jeff Law
2021-12-06 10:00                 ` Martin Liška
2021-12-06 10:23                   ` [committed] avr: Fix AVR build [PR71934] Jakub Jelinek
2021-12-06 11:28                     ` Martin Liška

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).