e7fd42
This patch backports support for PCH with PIE from upstream trunk.
e7fd42
e7fd42
It squashes two commits:
e7fd42
e7fd42
commit e4641191287ca613529d78a906afe4f029c1c3cd
e7fd42
Author: Iain Sandoe <iain@sandoe.co.uk>
e7fd42
Date:   Sat Nov 13 12:26:16 2021 +0000
e7fd42
e7fd42
    PCH: Make the save and restore diagnostics more robust.
e7fd42
    
e7fd42
    When saving, if we cannot obtain a suitable memory segment there
e7fd42
    is no point in continuing, so exit with an error.
e7fd42
    
e7fd42
    When reading in the PCH, we have a situation that the read-in
e7fd42
    data will replace the line tables used by the diagnostics output.
e7fd42
    However, the state of the read-oin line tables is indeterminate
e7fd42
    at some points where diagnostics might be needed.
e7fd42
    
e7fd42
    To make this more robust, we save the existing line tables at
e7fd42
    the start and, once we have read in the pointer to the new one,
e7fd42
    put that to one side and restore the original table.  This
e7fd42
    avoids compiler hangs if the read or memory acquisition code
e7fd42
    issues an assert, fatal_error, segv etc.
e7fd42
    
e7fd42
    Once the read is complete, we swap in the new line table that
e7fd42
    came from the PCH.
e7fd42
    
e7fd42
    If the read-in PCH is corrupted then we still have a broken
e7fd42
    compilation w.r.t any future diagnostics - but there is little
e7fd42
    that can be done about that without more careful validation of
e7fd42
    the file.
e7fd42
    
e7fd42
and
e7fd42
e7fd42
commit fe7c3ecff1f9c0520090a77fa824d8c5d9dbec12
e7fd42
Author: Jakub Jelinek <jakub@redhat.com>
e7fd42
Date:   Fri Dec 3 11:03:30 2021 +0100
e7fd42
e7fd42
    pch: Add support for PCH for relocatable executables [PR71934]
e7fd42
e7fd42
    So, if we want to make PCH work for PIEs, I'd say we can:
e7fd42
    1) add a new GTY option, say callback, which would act like
e7fd42
       skip for non-PCH and for PCH would make us skip it but
e7fd42
       remember for address bias translation
e7fd42
    2) drop the skip for tree_translation_unit_decl::language
e7fd42
    3) change get_unnamed_section to have const char * as
e7fd42
       last argument instead of const void *, change
e7fd42
       unnamed_section::data also to const char * and update
e7fd42
       everything related to that
e7fd42
    4) maybe add a host hook whether it is ok to support binaries
e7fd42
       changing addresses (the only thing I'm worried is if
e7fd42
       some host that uses function descriptors allocates them
e7fd42
       dynamically instead of having them somewhere in the
e7fd42
       executable)
e7fd42
    5) maybe add a gengtype warning if it sees in GTY tracked
e7fd42
       structure a function pointer without that new callback
e7fd42
       option
e7fd42
e7fd42
    Here is 1), 2), 3) implemented.
e7fd42
e7fd42
    Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
e7fd42
    the second patch, with it a few more, but nothing huge.  And for non-PIEs
e7fd42
    there isn't really any extra work on the load side except freading two scalar
e7fd42
    values and fseek.
e7fd42
e7fd42
diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c
e7fd42
index fd94c3799ac..eebfa1df0bc 100644
e7fd42
--- a/gcc/c-family/c-pch.c
e7fd42
+++ b/gcc/c-family/c-pch.c
e7fd42
@@ -54,7 +54,6 @@ struct c_pch_validity
e7fd42
 {
e7fd42
   unsigned char debug_info_type;
e7fd42
   signed char match[MATCH_SIZE];
e7fd42
-  void (*pch_init) (void);
e7fd42
   size_t target_data_length;
e7fd42
 };
e7fd42
 
e7fd42
@@ -117,7 +116,6 @@ pch_init (void)
e7fd42
 	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
e7fd42
       }
e7fd42
   }
e7fd42
-  v.pch_init = &pch_init;
e7fd42
   target_validity = targetm.get_pch_validity (&v.target_data_length);
e7fd42
 
e7fd42
   if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
e7fd42
@@ -275,19 +273,6 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd)
e7fd42
 	}
e7fd42
   }
e7fd42
 
e7fd42
-  /* If the text segment was not loaded at the same address as it was
e7fd42
-     when the PCH file was created, function pointers loaded from the
e7fd42
-     PCH will not be valid.  We could in theory remap all the function
e7fd42
-     pointers, but no support for that exists at present.
e7fd42
-     Since we have the same executable, it should only be necessary to
e7fd42
-     check one function.  */
e7fd42
-  if (v.pch_init != &pch_init)
e7fd42
-    {
e7fd42
-      cpp_warning (pfile, CPP_W_INVALID_PCH,
e7fd42
-		   "%s: had text segment at different address", name);
e7fd42
-      return 2;
e7fd42
-    }
e7fd42
-
e7fd42
   /* Check the target-specific validity data.  */
e7fd42
   {
e7fd42
     void *this_file_data = xmalloc (v.target_data_length);
e7fd42
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
e7fd42
index 3a250dfb960..4d29e80dcc9 100644
e7fd42
--- a/gcc/config/avr/avr.c
e7fd42
+++ b/gcc/config/avr/avr.c
e7fd42
@@ -10221,10 +10221,9 @@ avr_output_bss_section_asm_op (const void *data)
e7fd42
 /* Unnamed section callback for progmem*.data sections.  */
e7fd42
 
e7fd42
 static void
e7fd42
-avr_output_progmem_section_asm_op (const void *data)
e7fd42
+avr_output_progmem_section_asm_op (const char *data)
e7fd42
 {
e7fd42
-  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
e7fd42
-           (const char*) data);
e7fd42
+  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
e7fd42
 }
e7fd42
 
e7fd42
 
e7fd42
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
e7fd42
index 5d173919ee0..0c8aea148dc 100644
e7fd42
--- a/gcc/config/darwin.c
e7fd42
+++ b/gcc/config/darwin.c
e7fd42
@@ -128,7 +128,7 @@ int emit_aligned_common = false;
e7fd42
    DIRECTIVE is as for output_section_asm_op.  */
e7fd42
 
e7fd42
 static void
e7fd42
-output_objc_section_asm_op (const void *directive)
e7fd42
+output_objc_section_asm_op (const char *directive)
e7fd42
 {
e7fd42
   static bool been_here = false;
e7fd42
 
e7fd42
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
e7fd42
index 341c5f0d765..8ac9c4b3a44 100644
e7fd42
--- a/gcc/config/pa/pa.c
e7fd42
+++ b/gcc/config/pa/pa.c
e7fd42
@@ -10011,7 +10011,7 @@ pa_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg)
e7fd42
    to the default text subspace.  */
e7fd42
 
e7fd42
 static void
e7fd42
-som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
e7fd42
+som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
e7fd42
 {
e7fd42
   gcc_assert (TARGET_SOM);
e7fd42
   if (TARGET_GAS)
e7fd42
@@ -10055,7 +10055,7 @@ som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
e7fd42
    sections.  This function is only used with SOM.  */
e7fd42
 
e7fd42
 static void
e7fd42
-som_output_comdat_data_section_asm_op (const void *data)
e7fd42
+som_output_comdat_data_section_asm_op (const char *data)
e7fd42
 {
e7fd42
   in_section = NULL;
e7fd42
   output_section_asm_op (data);
e7fd42
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
e7fd42
index 9b1c3a8b5ea..fa245a8714c 100644
e7fd42
--- a/gcc/config/rs6000/rs6000.c
e7fd42
+++ b/gcc/config/rs6000/rs6000.c
e7fd42
@@ -20232,7 +20232,7 @@ rs6000_ms_bitfield_layout_p (const_tree record_type)
e7fd42
 /* A get_unnamed_section callback, used for switching to toc_section.  */
e7fd42
 
e7fd42
 static void
e7fd42
-rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
e7fd42
+rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
e7fd42
 {
e7fd42
   if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
e7fd42
       && TARGET_MINIMAL_TOC)
e7fd42
@@ -20936,35 +20936,39 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
e7fd42
    points to the section string variable.  */
e7fd42
 
e7fd42
 static void
e7fd42
-rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
e7fd42
+rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
e7fd42
 {
e7fd42
   fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
e7fd42
-	   *(const char *const *) directive,
e7fd42
+	   directive
e7fd42
+	   ? xcoff_private_rodata_section_name
e7fd42
+	   : xcoff_read_only_section_name,
e7fd42
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
e7fd42
 }
e7fd42
 
e7fd42
 /* Likewise for read-write sections.  */
e7fd42
 
e7fd42
 static void
e7fd42
-rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
e7fd42
+rs6000_xcoff_output_readwrite_section_asm_op (const char *)
e7fd42
 {
e7fd42
   fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
e7fd42
-	   *(const char *const *) directive,
e7fd42
+	   xcoff_private_data_section_name,
e7fd42
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
e7fd42
 }
e7fd42
 
e7fd42
 static void
e7fd42
-rs6000_xcoff_output_tls_section_asm_op (const void *directive)
e7fd42
+rs6000_xcoff_output_tls_section_asm_op (const char *directive)
e7fd42
 {
e7fd42
   fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
e7fd42
-	   *(const char *const *) directive,
e7fd42
+	   directive
e7fd42
+	   ? xcoff_private_data_section_name
e7fd42
+	   : xcoff_tls_data_section_name,
e7fd42
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
e7fd42
 }
e7fd42
 
e7fd42
 /* A get_unnamed_section callback, used for switching to toc_section.  */
e7fd42
 
e7fd42
 static void
e7fd42
-rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
e7fd42
+rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
e7fd42
 {
e7fd42
   if (TARGET_MINIMAL_TOC)
e7fd42
     {
e7fd42
@@ -20991,26 +20995,26 @@ rs6000_xcoff_asm_init_sections (void)
e7fd42
 {
e7fd42
   read_only_data_section
e7fd42
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
e7fd42
-			   &xcoff_read_only_section_name);
e7fd42
+			   NULL);
e7fd42
 
e7fd42
   private_data_section
e7fd42
     = get_unnamed_section (SECTION_WRITE,
e7fd42
 			   rs6000_xcoff_output_readwrite_section_asm_op,
e7fd42
-			   &xcoff_private_data_section_name);
e7fd42
+			   NULL);
e7fd42
 
e7fd42
   read_only_private_data_section
e7fd42
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
e7fd42
-			   &xcoff_private_rodata_section_name);
e7fd42
+			   "");
e7fd42
 
e7fd42
   tls_data_section
e7fd42
     = get_unnamed_section (SECTION_TLS,
e7fd42
 			   rs6000_xcoff_output_tls_section_asm_op,
e7fd42
-			   &xcoff_tls_data_section_name);
e7fd42
+			   NULL);
e7fd42
 
e7fd42
   tls_private_data_section
e7fd42
     = get_unnamed_section (SECTION_TLS,
e7fd42
 			   rs6000_xcoff_output_tls_section_asm_op,
e7fd42
-			   &xcoff_private_data_section_name);
e7fd42
+			   "");
e7fd42
 
e7fd42
   toc_section
e7fd42
     = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
e7fd42
diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi
e7fd42
index aaf97ae9ad5..0154bd86fe9 100644
e7fd42
--- a/gcc/doc/gty.texi
e7fd42
+++ b/gcc/doc/gty.texi
e7fd42
@@ -197,6 +197,15 @@ If @code{skip} is applied to a field, the type machinery will ignore it.
e7fd42
 This is somewhat dangerous; the only safe use is in a union when one
e7fd42
 field really isn't ever used.
e7fd42
 
e7fd42
+@findex callback
e7fd42
+@item callback
e7fd42
+
e7fd42
+@code{callback} should be applied to fields with pointer to function type
e7fd42
+and causes the field to be ignored similarly to @code{skip}, except when
e7fd42
+writing PCH and the field is non-NULL it will remember the field's address
e7fd42
+for relocation purposes if the process writing PCH has different load base
e7fd42
+from a process reading PCH.
e7fd42
+
e7fd42
 @findex for_user
e7fd42
 @item for_user
e7fd42
 
e7fd42
diff --git a/gcc/gengtype-state.c b/gcc/gengtype-state.c
e7fd42
index 891f2e18a61..fb99729bc0e 100644
e7fd42
--- a/gcc/gengtype-state.c
e7fd42
+++ b/gcc/gengtype-state.c
e7fd42
@@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
e7fd42
     case TYPE_STRING:
e7fd42
     case TYPE_POINTER:
e7fd42
     case TYPE_ARRAY:
e7fd42
+    case TYPE_CALLBACK:
e7fd42
       return NULL;
e7fd42
     default:
e7fd42
       gcc_unreachable ();
e7fd42
@@ -171,6 +172,7 @@ private:
e7fd42
   void write_state_version (const char *version);
e7fd42
   void write_state_scalar_type (type_p current);
e7fd42
   void write_state_string_type (type_p current);
e7fd42
+  void write_state_callback_type (type_p current);
e7fd42
   void write_state_undefined_type (type_p current);
e7fd42
   void write_state_struct_union_type (type_p current, const char *kindstr);
e7fd42
   void write_state_struct_type (type_p current);
e7fd42
@@ -898,6 +900,20 @@ state_writer::write_state_string_type (type_p current)
e7fd42
     fatal ("Unexpected type in write_state_string_type");
e7fd42
 }
e7fd42
 
e7fd42
+/* Write the callback type.  There is only one such thing! */
e7fd42
+void
e7fd42
+state_writer::write_state_callback_type (type_p current)
e7fd42
+{
e7fd42
+  if (current == &callback_type)
e7fd42
+    {
e7fd42
+      write_any_indent (0);
e7fd42
+      fprintf (state_file, "callback ");
e7fd42
+      write_state_common_type_content (current);
e7fd42
+    }
e7fd42
+  else
e7fd42
+    fatal ("Unexpected type in write_state_callback_type");
e7fd42
+}
e7fd42
+
e7fd42
 /* Write an undefined type.  */
e7fd42
 void
e7fd42
 state_writer::write_state_undefined_type (type_p current)
e7fd42
@@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p current)
e7fd42
 	case TYPE_STRING:
e7fd42
 	  write_state_string_type (current);
e7fd42
 	  break;
e7fd42
+	case TYPE_CALLBACK:
e7fd42
+	  write_state_callback_type (current);
e7fd42
+	  break;
e7fd42
 	}
e7fd42
     }
e7fd42
 
e7fd42
@@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
e7fd42
   read_state_common_type_content (*type);
e7fd42
 }
e7fd42
 
e7fd42
+/* Read the callback_type.  */
e7fd42
+static void
e7fd42
+read_state_callback_type (type_p *type)
e7fd42
+{
e7fd42
+  *type = &callback_type;
e7fd42
+  read_state_common_type_content (*type);
e7fd42
+}
e7fd42
+
e7fd42
 
e7fd42
 /* Read a lang_bitmap representing a set of GCC front-end languages.  */
e7fd42
 static void
e7fd42
@@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
e7fd42
 	      next_state_tokens (1);
e7fd42
 	      read_state_string_type (current);
e7fd42
 	    }
e7fd42
+	  else if (state_token_is_name (t0, "callback"))
e7fd42
+	    {
e7fd42
+	      next_state_tokens (1);
e7fd42
+	      read_state_callback_type (current);
e7fd42
+	    }
e7fd42
 	  else if (state_token_is_name (t0, "undefined"))
e7fd42
 	    {
e7fd42
 	      *current = XCNEW (struct type);
e7fd42
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
e7fd42
index 98d4626f87e..91eacc26932 100644
e7fd42
--- a/gcc/gengtype.c
e7fd42
+++ b/gcc/gengtype.c
e7fd42
@@ -167,6 +167,7 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
e7fd42
   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
e7fd42
   int nb_lang_struct = 0;
e7fd42
   int nb_user_struct = 0, nb_undefined = 0;
e7fd42
+  int nb_callback = 0;
e7fd42
   type_p p = NULL;
e7fd42
   for (p = t; p; p = p->next)
e7fd42
     {
e7fd42
@@ -197,6 +198,9 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
e7fd42
 	case TYPE_ARRAY:
e7fd42
 	  nb_array++;
e7fd42
 	  break;
e7fd42
+	case TYPE_CALLBACK:
e7fd42
+	  nb_callback++;
e7fd42
+	  break;
e7fd42
 	case TYPE_LANG_STRUCT:
e7fd42
 	  nb_lang_struct++;
e7fd42
 	  break;
e7fd42
@@ -212,6 +216,8 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
e7fd42
     fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
e7fd42
   if (nb_pointer > 0 || nb_array > 0)
e7fd42
     fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
e7fd42
+  if (nb_callback > 0)
e7fd42
+    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
e7fd42
   if (nb_lang_struct > 0)
e7fd42
     fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
e7fd42
   if (nb_user_struct > 0)
e7fd42
@@ -490,6 +496,10 @@ struct type scalar_char = {
e7fd42
   TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
e7fd42
 };
e7fd42
 
e7fd42
+struct type callback_type = {
e7fd42
+  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
e7fd42
+};
e7fd42
+
e7fd42
 /* Lists of various things.  */
e7fd42
 
e7fd42
 pair_p typedefs = NULL;
e7fd42
@@ -1459,7 +1469,7 @@ static void set_gc_used (pair_p);
e7fd42
 
e7fd42
 static void
e7fd42
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
e7fd42
-		    int *length, int *skip, type_p *nested_ptr)
e7fd42
+		    int *length, int *skip, int *callback, type_p *nested_ptr)
e7fd42
 {
e7fd42
   options_p o;
e7fd42
   for (o = opt; o; o = o->next)
e7fd42
@@ -1473,6 +1483,8 @@ process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
e7fd42
       *length = 1;
e7fd42
     else if (strcmp (o->name, "skip") == 0)
e7fd42
       *skip = 1;
e7fd42
+    else if (strcmp (o->name, "callback") == 0)
e7fd42
+      *callback = 1;
e7fd42
     else if (strcmp (o->name, "nested_ptr") == 0
e7fd42
 	     && o->kind == OPTION_NESTED)
e7fd42
       *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
e7fd42
@@ -1521,7 +1533,7 @@ set_gc_used_type (type_p t, enum gc_used_enum level,
e7fd42
 	type_p dummy2;
e7fd42
 	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
e7fd42
 
e7fd42
-	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
e7fd42
+	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
e7fd42
 			    &dummy2);
e7fd42
 
e7fd42
 	if (t->u.s.base_class)
e7fd42
@@ -1537,9 +1549,10 @@ set_gc_used_type (type_p t, enum gc_used_enum level,
e7fd42
 	    int maybe_undef = 0;
e7fd42
 	    int length = 0;
e7fd42
 	    int skip = 0;
e7fd42
+	    int callback = 0;
e7fd42
 	    type_p nested_ptr = NULL;
e7fd42
 	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
e7fd42
-				&nested_ptr);
e7fd42
+				&callback, &nested_ptr);
e7fd42
 
e7fd42
 	    if (nested_ptr && f->type->kind == TYPE_POINTER)
e7fd42
 	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
e7fd42
@@ -1549,6 +1562,8 @@ set_gc_used_type (type_p t, enum gc_used_enum level,
e7fd42
 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
e7fd42
 	    else if (skip)
e7fd42
 	      ;			/* target type is not used through this field */
e7fd42
+	    else if (callback)
e7fd42
+	      f->type = &callback_type;
e7fd42
 	    else
e7fd42
 	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
e7fd42
 	  }
e7fd42
@@ -2512,6 +2527,7 @@ output_mangled_typename (outf_p of, const_type_p t)
e7fd42
       {
e7fd42
       case TYPE_NONE:
e7fd42
       case TYPE_UNDEFINED:
e7fd42
+      case TYPE_CALLBACK:
e7fd42
 	gcc_unreachable ();
e7fd42
 	break;
e7fd42
       case TYPE_POINTER:
e7fd42
@@ -2712,6 +2728,8 @@ walk_type (type_p t, struct walk_type_data *d)
e7fd42
       ;
e7fd42
     else if (strcmp (oo->name, "for_user") == 0)
e7fd42
       ;
e7fd42
+    else if (strcmp (oo->name, "callback") == 0)
e7fd42
+      ;
e7fd42
     else
e7fd42
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
e7fd42
 
e7fd42
@@ -2737,6 +2755,7 @@ walk_type (type_p t, struct walk_type_data *d)
e7fd42
     {
e7fd42
     case TYPE_SCALAR:
e7fd42
     case TYPE_STRING:
e7fd42
+    case TYPE_CALLBACK:
e7fd42
       d->process_field (t, d);
e7fd42
       break;
e7fd42
 
e7fd42
@@ -3268,6 +3287,7 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
e7fd42
       break;
e7fd42
 
e7fd42
     case TYPE_SCALAR:
e7fd42
+    case TYPE_CALLBACK:
e7fd42
       break;
e7fd42
 
e7fd42
     case TYPE_ARRAY:
e7fd42
@@ -3813,6 +3833,7 @@ write_types_local_user_process_field (type_p f, const struct walk_type_data *d)
e7fd42
       break;
e7fd42
 
e7fd42
     case TYPE_SCALAR:
e7fd42
+    case TYPE_CALLBACK:
e7fd42
       break;
e7fd42
 
e7fd42
     case TYPE_ARRAY:
e7fd42
@@ -3899,6 +3920,13 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d)
e7fd42
     case TYPE_SCALAR:
e7fd42
       break;
e7fd42
 
e7fd42
+    case TYPE_CALLBACK:
e7fd42
+      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
e7fd42
+	       d->prev_val[3]);
e7fd42
+      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
e7fd42
+	       d->indent, "", d->val);
e7fd42
+      break;
e7fd42
+
e7fd42
     case TYPE_ARRAY:
e7fd42
     case TYPE_NONE:
e7fd42
     case TYPE_UNDEFINED:
e7fd42
@@ -4427,6 +4455,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
e7fd42
     case TYPE_UNDEFINED:
e7fd42
     case TYPE_UNION:
e7fd42
     case TYPE_LANG_STRUCT:
e7fd42
+    case TYPE_CALLBACK:
e7fd42
       error_at_line (line, "global `%s' is unimplemented type", name);
e7fd42
     }
e7fd42
 }
e7fd42
@@ -4721,6 +4750,9 @@ dump_typekind (int indent, enum typekind kind)
e7fd42
     case TYPE_ARRAY:
e7fd42
       printf ("TYPE_ARRAY");
e7fd42
       break;
e7fd42
+    case TYPE_CALLBACK:
e7fd42
+      printf ("TYPE_CALLBACK");
e7fd42
+      break;
e7fd42
     case TYPE_LANG_STRUCT:
e7fd42
       printf ("TYPE_LANG_STRUCT");
e7fd42
       break;
e7fd42
@@ -4887,6 +4919,7 @@ dump_type (int indent, type_p t)
e7fd42
 	      t->u.scalar_is_char ? "true" : "false");
e7fd42
       break;
e7fd42
     case TYPE_STRING:
e7fd42
+    case TYPE_CALLBACK:
e7fd42
       break;
e7fd42
     case TYPE_STRUCT:
e7fd42
     case TYPE_UNION:
e7fd42
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
e7fd42
index 4fe8f0f7232..c32faba2995 100644
e7fd42
--- a/gcc/gengtype.h
e7fd42
+++ b/gcc/gengtype.h
e7fd42
@@ -149,6 +149,9 @@ enum typekind {
e7fd42
   TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
e7fd42
   TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
e7fd42
   TYPE_ARRAY,           /* Array of GTY-ed types.  */
e7fd42
+  TYPE_CALLBACK,	/* A function pointer that needs relocation if
e7fd42
+			   the executable has been loaded at a different
e7fd42
+			   address.  */
e7fd42
   TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
e7fd42
                            Various languages may have homonymous but
e7fd42
                            different structs.  */
e7fd42
@@ -326,6 +329,9 @@ extern struct type string_type;
e7fd42
 extern struct type scalar_nonchar;
e7fd42
 extern struct type scalar_char;
e7fd42
 
e7fd42
+/* The one and only TYPE_CALLBACK.  */
e7fd42
+extern struct type callback_type;
e7fd42
+
e7fd42
 /* Test if a type is a union, either a plain one or a language
e7fd42
    specific one.  */
e7fd42
 #define UNION_P(x)					\
e7fd42
diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c
e7fd42
index 357bda13f97..88e1af4ba4a 100644
e7fd42
--- a/gcc/ggc-common.c
e7fd42
+++ b/gcc/ggc-common.c
e7fd42
@@ -249,6 +249,7 @@ saving_hasher::equal (const ptr_data *p1, const void *p2)
e7fd42
 }
e7fd42
 
e7fd42
 static hash_table<saving_hasher> *saving_htab;
e7fd42
+static vec<void *> callback_vec;
e7fd42
 
e7fd42
 /* Register an object in the hash table.  */
e7fd42
 
e7fd42
@@ -281,6 +282,23 @@ gt_pch_note_object (void *obj, void *note_ptr_cookie,
e7fd42
   return 1;
e7fd42
 }
e7fd42
 
e7fd42
+/* Register address of a callback pointer.  */
e7fd42
+void
e7fd42
+gt_pch_note_callback (void *obj, void *base)
e7fd42
+{
e7fd42
+  void *ptr;
e7fd42
+  memcpy (&ptr, obj, sizeof (void *));
e7fd42
+  if (ptr != NULL)
e7fd42
+    {
e7fd42
+      struct ptr_data *data
e7fd42
+	= (struct ptr_data *)
e7fd42
+	  saving_htab->find_with_hash (base, POINTER_HASH (base));
e7fd42
+      gcc_assert (data);
e7fd42
+      callback_vec.safe_push ((char *) data->new_addr
e7fd42
+			      + ((char *) obj - (char *) base));
e7fd42
+    }
e7fd42
+}
e7fd42
+
e7fd42
 /* Register an object in the hash table.  */
e7fd42
 
e7fd42
 void
e7fd42
@@ -443,6 +461,10 @@ gt_pch_save (FILE *f)
e7fd42
      (The extra work goes in HOST_HOOKS_GT_PCH_GET_ADDRESS and
e7fd42
      HOST_HOOKS_GT_PCH_USE_ADDRESS.)  */
e7fd42
   mmi.preferred_base = host_hooks.gt_pch_get_address (mmi.size, fileno (f));
e7fd42
+  /* If the host cannot supply any suitable address for this, we are stuck.  */
e7fd42
+  if (mmi.preferred_base == NULL)
e7fd42
+    fatal_error (input_location,
e7fd42
+		 "cannot write PCH file: required memory segment unavailable");
e7fd42
 
e7fd42
   ggc_pch_this_base (state.d, mmi.preferred_base);
e7fd42
 
e7fd42
@@ -575,10 +597,20 @@ gt_pch_save (FILE *f)
e7fd42
   ggc_pch_finish (state.d, state.f);
e7fd42
   gt_pch_fixup_stringpool ();
e7fd42
 
e7fd42
+  unsigned num_callbacks = callback_vec.length ();
e7fd42
+  void (*pch_save) (FILE *) = &gt_pch_save;
e7fd42
+  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
e7fd42
+      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
e7fd42
+      || (num_callbacks
e7fd42
+	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
e7fd42
+		     f) != num_callbacks))
e7fd42
+    fatal_error (input_location, "cannot write PCH file: %m");
e7fd42
+
e7fd42
   XDELETE (state.ptrs);
e7fd42
   XDELETE (this_object);
e7fd42
   delete saving_htab;
e7fd42
   saving_htab = NULL;
e7fd42
+  callback_vec.release ();
e7fd42
 }
e7fd42
 
e7fd42
 /* Read the state of the compiler back in from F.  */
e7fd42
@@ -592,6 +624,13 @@ gt_pch_restore (FILE *f)
e7fd42
   struct mmap_info mmi;
e7fd42
   int result;
e7fd42
 
e7fd42
+  /* We are about to reload the line maps along with the rest of the PCH
e7fd42
+     data, which means that the (loaded) ones cannot be guaranteed to be
e7fd42
+     in any valid state for reporting diagnostics that happen during the
e7fd42
+     load.  Save the current table (and use it during the loading process
e7fd42
+     below).  */
e7fd42
+  class line_maps *save_line_table = line_table;
e7fd42
+
e7fd42
   /* Delete any deletable objects.  This makes ggc_pch_read much
e7fd42
      faster, as it can be sure that no GCable objects remain other
e7fd42
      than the ones just read in.  */
e7fd42
@@ -606,20 +645,40 @@ gt_pch_restore (FILE *f)
e7fd42
 	fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
 
e7fd42
   /* Read in all the global pointers, in 6 easy loops.  */
e7fd42
+  bool error_reading_pointers = false;
e7fd42
   for (rt = gt_ggc_rtab; *rt; rt++)
e7fd42
     for (rti = *rt; rti->base != NULL; rti++)
e7fd42
       for (i = 0; i < rti->nelt; i++)
e7fd42
 	if (fread ((char *)rti->base + rti->stride * i,
e7fd42
 		   sizeof (void *), 1, f) != 1)
e7fd42
-	  fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
+	  error_reading_pointers = true;
e7fd42
+
e7fd42
+  /* Stash the newly read-in line table pointer - it does not point to
e7fd42
+     anything meaningful yet, so swap the old one back in.  */
e7fd42
+  class line_maps *new_line_table = line_table;
e7fd42
+  line_table = save_line_table;
e7fd42
+  if (error_reading_pointers)
e7fd42
+    fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
 
e7fd42
   if (fread (&mmi, sizeof (mmi), 1, f) != 1)
e7fd42
     fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
 
e7fd42
   result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
e7fd42
 					  fileno (f), mmi.offset);
e7fd42
+
e7fd42
+  /* We could not mmap or otherwise allocate the required memory at the
e7fd42
+     address needed.  */
e7fd42
   if (result < 0)
e7fd42
-    fatal_error (input_location, "had to relocate PCH");
e7fd42
+    {
e7fd42
+      sorry_at (input_location, "PCH relocation is not yet supported");
e7fd42
+      /* There is no point in continuing from here, we will only end up
e7fd42
+	 with a crashed (most likely hanging) compiler.  */
e7fd42
+      exit (-1);
e7fd42
+    }
e7fd42
+
e7fd42
+  /* (0) We allocated memory, but did not mmap the file, so we need to read
e7fd42
+     the data in manually.  (>0) Otherwise the mmap succeed for the address
e7fd42
+     we wanted.  */
e7fd42
   if (result == 0)
e7fd42
     {
e7fd42
       if (fseek (f, mmi.offset, SEEK_SET) != 0
e7fd42
@@ -632,6 +691,34 @@ gt_pch_restore (FILE *f)
e7fd42
   ggc_pch_read (f, mmi.preferred_base);
e7fd42
 
e7fd42
   gt_pch_restore_stringpool ();
e7fd42
+
e7fd42
+  void (*pch_save) (FILE *);
e7fd42
+  unsigned num_callbacks;
e7fd42
+  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
e7fd42
+      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
e7fd42
+    fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
+  if (pch_save != &gt_pch_save)
e7fd42
+    {
e7fd42
+      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
e7fd42
+      void **ptrs = XNEWVEC (void *, num_callbacks);
e7fd42
+      unsigned i;
e7fd42
+
e7fd42
+      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
e7fd42
+	fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
+      for (i = 0; i < num_callbacks; ++i)
e7fd42
+	{
e7fd42
+	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
e7fd42
+	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
e7fd42
+	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
e7fd42
+	}
e7fd42
+      XDELETE (ptrs);
e7fd42
+    }
e7fd42
+  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
e7fd42
+    fatal_error (input_location, "cannot read PCH file: %m");
e7fd42
+
e7fd42
+  /* Barring corruption of the PCH file, the restored line table should be
e7fd42
+     complete and usable.  */
e7fd42
+  line_table = new_line_table;
e7fd42
 }
e7fd42
 
e7fd42
 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
e7fd42
diff --git a/gcc/ggc.h b/gcc/ggc.h
e7fd42
index 65f6cb4d19d..3339394b547 100644
e7fd42
--- a/gcc/ggc.h
e7fd42
+++ b/gcc/ggc.h
e7fd42
@@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void *, void *, gt_pointer_operator,
e7fd42
 /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
e7fd42
 extern int gt_pch_note_object (void *, void *, gt_note_pointers);
e7fd42
 
e7fd42
+/* Used by the gt_pch_p_* routines.  Register address of a callback
e7fd42
+   pointer.  */
e7fd42
+extern void gt_pch_note_callback (void *, void *);
e7fd42
+
e7fd42
 /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
e7fd42
    function.  */
e7fd42
 extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
e7fd42
diff --git a/gcc/output.h b/gcc/output.h
e7fd42
index 2bfeed93c56..7412407c2c0 100644
e7fd42
--- a/gcc/output.h
e7fd42
+++ b/gcc/output.h
e7fd42
@@ -458,7 +458,7 @@ struct GTY(()) named_section {
e7fd42
 
e7fd42
 /* A callback that writes the assembly code for switching to an unnamed
e7fd42
    section.  The argument provides callback-specific data.  */
e7fd42
-typedef void (*unnamed_section_callback) (const void *);
e7fd42
+typedef void (*unnamed_section_callback) (const char *);
e7fd42
 
e7fd42
 /* Information about a SECTION_UNNAMED section.  */
e7fd42
 struct GTY(()) unnamed_section {
e7fd42
@@ -466,8 +466,8 @@ struct GTY(()) unnamed_section {
e7fd42
 
e7fd42
   /* The callback used to switch to the section, and the data that
e7fd42
      should be passed to the callback.  */
e7fd42
-  unnamed_section_callback GTY ((skip)) callback;
e7fd42
-  const void *GTY ((skip)) data;
e7fd42
+  unnamed_section_callback GTY ((callback)) callback;
e7fd42
+  const char *data;
e7fd42
 
e7fd42
   /* The next entry in the chain of unnamed sections.  */
e7fd42
   section *next;
e7fd42
@@ -491,7 +491,7 @@ struct GTY(()) noswitch_section {
e7fd42
   struct section_common common;
e7fd42
 
e7fd42
   /* The callback used to assemble decls in this section.  */
e7fd42
-  noswitch_section_callback GTY ((skip)) callback;
e7fd42
+  noswitch_section_callback GTY ((callback)) callback;
e7fd42
 };
e7fd42
 
e7fd42
 /* Information about a section, which may be named or unnamed.  */
e7fd42
@@ -526,8 +526,8 @@ extern GTY(()) section *bss_noswitch_section;
e7fd42
 extern GTY(()) section *in_section;
e7fd42
 extern GTY(()) bool in_cold_section_p;
e7fd42
 
e7fd42
-extern section *get_unnamed_section (unsigned int, void (*) (const void *),
e7fd42
-				     const void *);
e7fd42
+extern section *get_unnamed_section (unsigned int, void (*) (const char *),
e7fd42
+				     const char *);
e7fd42
 extern section *get_section (const char *, unsigned int, tree,
e7fd42
 			     bool not_existing = false);
e7fd42
 extern section *get_named_section (tree, const char *, int);
e7fd42
@@ -549,7 +549,7 @@ extern section *get_cdtor_priority_section (int, bool);
e7fd42
 
e7fd42
 extern bool unlikely_text_section_p (section *);
e7fd42
 extern void switch_to_section (section *, tree = nullptr);
e7fd42
-extern void output_section_asm_op (const void *);
e7fd42
+extern void output_section_asm_op (const char *);
e7fd42
 
e7fd42
 extern void record_tm_clone_pair (tree, tree);
e7fd42
 extern void finish_tm_clone_pairs (void);
e7fd42
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
e7fd42
index c31b8ebf249..e2fd2e67440 100644
e7fd42
--- a/gcc/tree-core.h
e7fd42
+++ b/gcc/tree-core.h
e7fd42
@@ -1927,7 +1927,7 @@ struct GTY(()) tree_function_decl {
e7fd42
 struct GTY(()) tree_translation_unit_decl {
e7fd42
   struct tree_decl_common common;
e7fd42
   /* Source language of this translation unit.  Used for DWARF output.  */
e7fd42
-  const char * GTY((skip(""))) language;
e7fd42
+  const char *language;
e7fd42
   /* TODO: Non-optimization used to build this translation unit.  */
e7fd42
   /* TODO: Root of a partial DWARF tree for global types and decls.  */
e7fd42
 };
e7fd42
diff --git a/gcc/varasm.c b/gcc/varasm.c
e7fd42
index a7ef9b8d9fe..baf9f1ba0e4 100644
e7fd42
--- a/gcc/varasm.c
e7fd42
+++ b/gcc/varasm.c
e7fd42
@@ -250,8 +250,8 @@ object_block_hasher::hash (object_block *old)
e7fd42
 /* Return a new unnamed section with the given fields.  */
e7fd42
 
e7fd42
 section *
e7fd42
-get_unnamed_section (unsigned int flags, void (*callback) (const void *),
e7fd42
-		     const void *data)
e7fd42
+get_unnamed_section (unsigned int flags, void (*callback) (const char *),
e7fd42
+		     const char *data)
e7fd42
 {
e7fd42
   section *sect;
e7fd42
 
e7fd42
@@ -7753,9 +7753,9 @@ file_end_indicate_split_stack (void)
e7fd42
    a get_unnamed_section callback.  */
e7fd42
 
e7fd42
 void
e7fd42
-output_section_asm_op (const void *directive)
e7fd42
+output_section_asm_op (const char *directive)
e7fd42
 {
e7fd42
-  fprintf (asm_out_file, "%s\n", (const char *) directive);
e7fd42
+  fprintf (asm_out_file, "%s\n", directive);
e7fd42
 }
e7fd42
 
e7fd42
 /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
e7fd42
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
e7fd42
index 7d964172469..1073542681d 100644
e7fd42
--- a/libcpp/include/line-map.h
e7fd42
+++ b/libcpp/include/line-map.h
e7fd42
@@ -803,11 +803,11 @@ public:
e7fd42
   unsigned int max_column_hint;
e7fd42
 
e7fd42
   /* The allocator to use when resizing 'maps', defaults to xrealloc.  */
e7fd42
-  line_map_realloc reallocator;
e7fd42
+  line_map_realloc GTY((callback)) reallocator;
e7fd42
 
e7fd42
   /* The allocators' function used to know the actual size it
e7fd42
      allocated, for a certain allocation size requested.  */
e7fd42
-  line_map_round_alloc_size_func round_alloc_size;
e7fd42
+  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
e7fd42
 
e7fd42
   struct location_adhoc_data_map location_adhoc_data_map;
e7fd42