Blame SOURCES/gcc11-relocatable-pch.patch

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