Blame SOURCES/gcc8-pch-tweaks.patch

dc03fd
commit fe7c3ecff1f9c0520090a77fa824d8c5d9dbec12
dc03fd
Author: Jakub Jelinek <jakub@redhat.com>
dc03fd
Date:   Fri Dec 3 11:03:30 2021 +0100
dc03fd
dc03fd
    pch: Add support for PCH for relocatable executables [PR71934]
dc03fd
    
dc03fd
    So, if we want to make PCH work for PIEs, I'd say we can:
dc03fd
    1) add a new GTY option, say callback, which would act like
dc03fd
       skip for non-PCH and for PCH would make us skip it but
dc03fd
       remember for address bias translation
dc03fd
    2) drop the skip for tree_translation_unit_decl::language
dc03fd
    3) change get_unnamed_section to have const char * as
dc03fd
       last argument instead of const void *, change
dc03fd
       unnamed_section::data also to const char * and update
dc03fd
       everything related to that
dc03fd
    4) maybe add a host hook whether it is ok to support binaries
dc03fd
       changing addresses (the only thing I'm worried is if
dc03fd
       some host that uses function descriptors allocates them
dc03fd
       dynamically instead of having them somewhere in the
dc03fd
       executable)
dc03fd
    5) maybe add a gengtype warning if it sees in GTY tracked
dc03fd
       structure a function pointer without that new callback
dc03fd
       option
dc03fd
    
dc03fd
    Here is 1), 2), 3) implemented.
dc03fd
    
dc03fd
    Note, on stdc++.h.gch/O2g.gch there are just those 10 relocations without
dc03fd
    the second patch, with it a few more, but nothing huge.  And for non-PIEs
dc03fd
    there isn't really any extra work on the load side except freading two scalar
dc03fd
    values and fseek.
dc03fd
    
dc03fd
    2021-12-03  Jakub Jelinek  <jakub@redhat.com>
dc03fd
    
dc03fd
            PR pch/71934
dc03fd
    gcc/
dc03fd
            * ggc.h (gt_pch_note_callback): Declare.
dc03fd
            * gengtype.h (enum typekind): Add TYPE_CALLBACK.
dc03fd
            (callback_type): Declare.
dc03fd
            * gengtype.c (dbgprint_count_type_at): Handle TYPE_CALLBACK.
dc03fd
            (callback_type): New variable.
dc03fd
            (process_gc_options): Add CALLBACK argument, handle callback
dc03fd
            option.
dc03fd
            (set_gc_used_type): Adjust process_gc_options caller, if callback,
dc03fd
            set type to &callback_type.
dc03fd
            (output_mangled_typename): Handle TYPE_CALLBACK.
dc03fd
            (walk_type): Likewise.  Handle callback option.
dc03fd
            (write_types_process_field): Handle TYPE_CALLBACK.
dc03fd
            (write_types_local_user_process_field): Likewise.
dc03fd
            (write_types_local_process_field): Likewise.
dc03fd
            (write_root): Likewise.
dc03fd
            (dump_typekind): Likewise.
dc03fd
            (dump_type): Likewise.
dc03fd
            * gengtype-state.c (type_lineloc): Handle TYPE_CALLBACK.
dc03fd
            (state_writer::write_state_callback_type): New method.
dc03fd
            (state_writer::write_state_type): Handle TYPE_CALLBACK.
dc03fd
            (read_state_callback_type): New function.
dc03fd
            (read_state_type): Handle TYPE_CALLBACK.
dc03fd
            * ggc-common.c (callback_vec): New variable.
dc03fd
            (gt_pch_note_callback): New function.
dc03fd
            (gt_pch_save): Stream out gt_pch_save function address and relocation
dc03fd
            table.
dc03fd
            (gt_pch_restore): Stream in saved gt_pch_save function address and
dc03fd
            relocation table and apply relocations if needed.
dc03fd
            * doc/gty.texi (callback): Document new GTY option.
dc03fd
            * varasm.c (get_unnamed_section): Change callback argument's type and
dc03fd
            last argument's type from const void * to const char *.
dc03fd
            (output_section_asm_op): Change argument's type from const void *
dc03fd
            to const char *, remove unnecessary cast.
dc03fd
            * tree-core.h (struct tree_translation_unit_decl): Drop GTY((skip))
dc03fd
            from language member.
dc03fd
            * output.h (unnamed_section_callback): Change argument type from
dc03fd
            const void * to const char *.
dc03fd
            (struct unnamed_section): Use GTY((callback)) instead of GTY((skip))
dc03fd
            for callback member.  Change data member type from const void *
dc03fd
            to const char *.
dc03fd
            (struct noswitch_section): Use GTY((callback)) instead of GTY((skip))
dc03fd
            for callback member.
dc03fd
            (get_unnamed_section): Change callback argument's type and
dc03fd
            last argument's type from const void * to const char *.
dc03fd
            (output_section_asm_op): Change argument's type from const void *
dc03fd
            to const char *.
dc03fd
            * config/avr/avr.c (avr_output_progmem_section_asm_op): Likewise.
dc03fd
            Remove unneeded cast.
dc03fd
            * config/darwin.c (output_objc_section_asm_op): Change argument's type
dc03fd
            from const void * to const char *.
dc03fd
            * config/pa/pa.c (som_output_text_section_asm_op): Likewise.
dc03fd
            (som_output_comdat_data_section_asm_op): Likewise.
dc03fd
            * config/rs6000/rs6000.c (rs6000_elf_output_toc_section_asm_op):
dc03fd
            Likewise.
dc03fd
            (rs6000_xcoff_output_readonly_section_asm_op): Likewise.  Instead
dc03fd
            of dereferencing directive hardcode variable names and decide based on
dc03fd
            whether directive is NULL or not.
dc03fd
            (rs6000_xcoff_output_readwrite_section_asm_op): Change argument's type
dc03fd
            from const void * to const char *.
dc03fd
            (rs6000_xcoff_output_tls_section_asm_op): Likewise.  Instead
dc03fd
            of dereferencing directive hardcode variable names and decide based on
dc03fd
            whether directive is NULL or not.
dc03fd
            (rs6000_xcoff_output_toc_section_asm_op): Change argument's type
dc03fd
            from const void * to const char *.
dc03fd
            (rs6000_xcoff_asm_init_sections): Adjust get_unnamed_section callers.
dc03fd
    gcc/c-family/
dc03fd
            * c-pch.c (struct c_pch_validity): Remove pch_init member.
dc03fd
            (pch_init): Don't initialize v.pch_init.
dc03fd
            (c_common_valid_pch): Don't warn and punt if .text addresses change.
dc03fd
    libcpp/
dc03fd
            * include/line-map.h (class line_maps): Add GTY((callback)) to
dc03fd
            reallocator and round_alloc_size members.
dc03fd
dc03fd
commit 4dc6d19222581c77a174d44d97507d234fb7e39b
dc03fd
Author: Jakub Jelinek <jakub@redhat.com>
dc03fd
Date:   Mon Dec 6 11:18:58 2021 +0100
dc03fd
dc03fd
    avr: Fix AVR build [PR71934]
dc03fd
    
dc03fd
    On Mon, Dec 06, 2021 at 11:00:30AM +0100, Martin Liška wrote:
dc03fd
    > Jakub, I think the patch broke avr-linux target:
dc03fd
    >
dc03fd
    > 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
dc03fd
    > /home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_output_data_section_asm_op(const void*)’:
dc03fd
    > /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10097:26: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive]
dc03fd
    
dc03fd
    This patch fixes that.
dc03fd
    
dc03fd
    2021-12-06  Jakub Jelinek  <jakub@redhat.com>
dc03fd
    
dc03fd
            PR pch/71934
dc03fd
            * config/avr/avr.c (avr_output_data_section_asm_op,
dc03fd
            avr_output_bss_section_asm_op): Change argument type from const void *
dc03fd
            to const char *.
dc03fd
dc03fd
diff --git a/gcc/c-family/c-pch.c b/gcc/c-family/c-pch.c
dc03fd
index 5da60423354..2cafa1387bb 100644
dc03fd
--- a/gcc/c-family/c-pch.c
dc03fd
+++ b/gcc/c-family/c-pch.c
dc03fd
@@ -58,7 +58,6 @@ struct c_pch_validity
dc03fd
 {
dc03fd
   unsigned char debug_info_type;
dc03fd
   signed char match[MATCH_SIZE];
dc03fd
-  void (*pch_init) (void);
dc03fd
   size_t target_data_length;
dc03fd
 };
dc03fd
 
dc03fd
@@ -123,7 +122,6 @@ pch_init (void)
dc03fd
 	gcc_assert (v.match[i] == *pch_matching[i].flag_var);
dc03fd
       }
dc03fd
   }
dc03fd
-  v.pch_init = &pch_init;
dc03fd
   target_validity = targetm.get_pch_validity (&v.target_data_length);
dc03fd
 
dc03fd
   if (fwrite (partial_pch, IDENT_LENGTH, 1, f) != 1
dc03fd
@@ -287,20 +285,6 @@ c_common_valid_pch (cpp_reader *pfile, c
dc03fd
 	}
dc03fd
   }
dc03fd
 
dc03fd
-  /* If the text segment was not loaded at the same address as it was
dc03fd
-     when the PCH file was created, function pointers loaded from the
dc03fd
-     PCH will not be valid.  We could in theory remap all the function
dc03fd
-     pointers, but no support for that exists at present.
dc03fd
-     Since we have the same executable, it should only be necessary to
dc03fd
-     check one function.  */
dc03fd
-  if (v.pch_init != &pch_init)
dc03fd
-    {
dc03fd
-      if (cpp_get_options (pfile)->warn_invalid_pch)
dc03fd
-	cpp_error (pfile, CPP_DL_WARNING,
dc03fd
-		   "%s: had text segment at different address", name);
dc03fd
-      return 2;
dc03fd
-    }
dc03fd
-
dc03fd
   /* Check the target-specific validity data.  */
dc03fd
   {
dc03fd
     void *this_file_data = xmalloc (v.target_data_length);
dc03fd
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
dc03fd
index 200701a583c..6ba038881d6 100644
dc03fd
--- a/gcc/config/avr/avr.c
dc03fd
+++ b/gcc/config/avr/avr.c
dc03fd
@@ -10114,10 +10114,9 @@ avr_output_bss_section_asm_op (const void *data)
dc03fd
 /* Unnamed section callback for progmem*.data sections.  */
dc03fd
 
dc03fd
 static void
dc03fd
-avr_output_progmem_section_asm_op (const void *data)
dc03fd
+avr_output_progmem_section_asm_op (const char *data)
dc03fd
 {
dc03fd
-  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n",
dc03fd
-           (const char*) data);
dc03fd
+  fprintf (asm_out_file, "\t.section\t%s,\"a\",@progbits\n", data);
dc03fd
 }
dc03fd
 
dc03fd
 
dc03fd
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
dc03fd
index c5ba7927ce1..8ad5b26c980 100644
dc03fd
--- a/gcc/config/darwin.c
dc03fd
+++ b/gcc/config/darwin.c
dc03fd
@@ -134,7 +134,7 @@ int emit_aligned_common = false;
dc03fd
    DIRECTIVE is as for output_section_asm_op.  */
dc03fd
 
dc03fd
 static void
dc03fd
-output_objc_section_asm_op (const void *directive)
dc03fd
+output_objc_section_asm_op (const char *directive)
dc03fd
 {
dc03fd
   static bool been_here = false;
dc03fd
 
dc03fd
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
dc03fd
index f22d25a4066..2b10ef34061 100644
dc03fd
--- a/gcc/config/pa/pa.c
dc03fd
+++ b/gcc/config/pa/pa.c
dc03fd
@@ -10009,7 +10009,7 @@ pa_arg_partial_bytes (cumulative_args_t cum_v, const function_arg_info &arg)
dc03fd
    to the default text subspace.  */
dc03fd
 
dc03fd
 static void
dc03fd
-som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
dc03fd
+som_output_text_section_asm_op (const char *data ATTRIBUTE_UNUSED)
dc03fd
 {
dc03fd
   gcc_assert (TARGET_SOM);
dc03fd
   if (TARGET_GAS)
dc03fd
@@ -10053,7 +10053,7 @@ som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
dc03fd
    sections.  This function is only used with SOM.  */
dc03fd
 
dc03fd
 static void
dc03fd
-som_output_comdat_data_section_asm_op (const void *data)
dc03fd
+som_output_comdat_data_section_asm_op (const char *data)
dc03fd
 {
dc03fd
   in_section = NULL;
dc03fd
   output_section_asm_op (data);
dc03fd
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
dc03fd
index 945157b1c1a..34089743759 100644
dc03fd
--- a/gcc/config/rs6000/rs6000.c
dc03fd
+++ b/gcc/config/rs6000/rs6000.c
dc03fd
@@ -20599,7 +20599,7 @@ rs6000_ms_bitfield_layout_p (const_tree record_type)
dc03fd
 /* A get_unnamed_section callback, used for switching to toc_section.  */
dc03fd
 
dc03fd
 static void
dc03fd
-rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
dc03fd
+rs6000_elf_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
dc03fd
 {
dc03fd
   if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_ELFv2)
dc03fd
       && TARGET_MINIMAL_TOC)
dc03fd
@@ -21303,35 +21303,39 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
dc03fd
    points to the section string variable.  */
dc03fd
 
dc03fd
 static void
dc03fd
-rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
dc03fd
+rs6000_xcoff_output_readonly_section_asm_op (const char *directive)
dc03fd
 {
dc03fd
   fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
dc03fd
-	   *(const char *const *) directive,
dc03fd
+	   directive
dc03fd
+	   ? xcoff_private_rodata_section_name
dc03fd
+	   : xcoff_read_only_section_name,
dc03fd
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
dc03fd
 }
dc03fd
 
dc03fd
 /* Likewise for read-write sections.  */
dc03fd
 
dc03fd
 static void
dc03fd
-rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
dc03fd
+rs6000_xcoff_output_readwrite_section_asm_op (const char *)
dc03fd
 {
dc03fd
   fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
dc03fd
-	   *(const char *const *) directive,
dc03fd
+	   xcoff_private_data_section_name,
dc03fd
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
dc03fd
 }
dc03fd
 
dc03fd
 static void
dc03fd
-rs6000_xcoff_output_tls_section_asm_op (const void *directive)
dc03fd
+rs6000_xcoff_output_tls_section_asm_op (const char *directive)
dc03fd
 {
dc03fd
   fprintf (asm_out_file, "\t.csect %s[TL],%s\n",
dc03fd
-	   *(const char *const *) directive,
dc03fd
+	   directive
dc03fd
+	   ? xcoff_private_data_section_name
dc03fd
+	   : xcoff_tls_data_section_name,
dc03fd
 	   XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
dc03fd
 }
dc03fd
 
dc03fd
 /* A get_unnamed_section callback, used for switching to toc_section.  */
dc03fd
 
dc03fd
 static void
dc03fd
-rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
dc03fd
+rs6000_xcoff_output_toc_section_asm_op (const char *data ATTRIBUTE_UNUSED)
dc03fd
 {
dc03fd
   if (TARGET_MINIMAL_TOC)
dc03fd
     {
dc03fd
@@ -21358,26 +21362,26 @@ rs6000_xcoff_asm_init_sections (void)
dc03fd
 {
dc03fd
   read_only_data_section
dc03fd
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
dc03fd
-			   &xcoff_read_only_section_name);
dc03fd
+			   NULL);
dc03fd
 
dc03fd
   private_data_section
dc03fd
     = get_unnamed_section (SECTION_WRITE,
dc03fd
 			   rs6000_xcoff_output_readwrite_section_asm_op,
dc03fd
-			   &xcoff_private_data_section_name);
dc03fd
+			   NULL);
dc03fd
 
dc03fd
   read_only_private_data_section
dc03fd
     = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
dc03fd
-			   &xcoff_private_rodata_section_name);
dc03fd
+			   "");
dc03fd
 
dc03fd
   tls_data_section
dc03fd
     = get_unnamed_section (SECTION_TLS,
dc03fd
 			   rs6000_xcoff_output_tls_section_asm_op,
dc03fd
-			   &xcoff_tls_data_section_name);
dc03fd
+			   NULL);
dc03fd
 
dc03fd
   tls_private_data_section
dc03fd
     = get_unnamed_section (SECTION_TLS,
dc03fd
 			   rs6000_xcoff_output_tls_section_asm_op,
dc03fd
-			   &xcoff_private_data_section_name);
dc03fd
+			   "");
dc03fd
 
dc03fd
   toc_section
dc03fd
     = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
dc03fd
diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi
dc03fd
index b996ff2c44e..ca2c8404894 100644
dc03fd
--- a/gcc/doc/gty.texi
dc03fd
+++ b/gcc/doc/gty.texi
dc03fd
@@ -205,6 +205,15 @@ If @code{skip} is applied to a field, the type machinery will ignore it.
dc03fd
 This is somewhat dangerous; the only safe use is in a union when one
dc03fd
 field really isn't ever used.
dc03fd
 
dc03fd
+@findex callback
dc03fd
+@item callback
dc03fd
+
dc03fd
+@code{callback} should be applied to fields with pointer to function type
dc03fd
+and causes the field to be ignored similarly to @code{skip}, except when
dc03fd
+writing PCH and the field is non-NULL it will remember the field's address
dc03fd
+for relocation purposes if the process writing PCH has different load base
dc03fd
+from a process reading PCH.
dc03fd
+
dc03fd
 @findex for_user
dc03fd
 @item for_user
dc03fd
 
dc03fd
diff --git a/gcc/gengtype-state.c b/gcc/gengtype-state.c
dc03fd
index ac9d536963f..36a96e84574 100644
dc03fd
--- a/gcc/gengtype-state.c
dc03fd
+++ b/gcc/gengtype-state.c
dc03fd
@@ -57,6 +57,7 @@ type_lineloc (const_type_p ty)
dc03fd
     case TYPE_STRING:
dc03fd
     case TYPE_POINTER:
dc03fd
     case TYPE_ARRAY:
dc03fd
+    case TYPE_CALLBACK:
dc03fd
       return NULL;
dc03fd
     default:
dc03fd
       gcc_unreachable ();
dc03fd
@@ -171,6 +172,7 @@ private:
dc03fd
   void write_state_version (const char *version);
dc03fd
   void write_state_scalar_type (type_p current);
dc03fd
   void write_state_string_type (type_p current);
dc03fd
+  void write_state_callback_type (type_p current);
dc03fd
   void write_state_undefined_type (type_p current);
dc03fd
   void write_state_struct_union_type (type_p current, const char *kindstr);
dc03fd
   void write_state_struct_type (type_p current);
dc03fd
@@ -898,6 +900,20 @@ state_writer::write_state_string_type (type_p current)
dc03fd
     fatal ("Unexpected type in write_state_string_type");
dc03fd
 }
dc03fd
 
dc03fd
+/* Write the callback type.  There is only one such thing! */
dc03fd
+void
dc03fd
+state_writer::write_state_callback_type (type_p current)
dc03fd
+{
dc03fd
+  if (current == &callback_type)
dc03fd
+    {
dc03fd
+      write_any_indent (0);
dc03fd
+      fprintf (state_file, "callback ");
dc03fd
+      write_state_common_type_content (current);
dc03fd
+    }
dc03fd
+  else
dc03fd
+    fatal ("Unexpected type in write_state_callback_type");
dc03fd
+}
dc03fd
+
dc03fd
 /* Write an undefined type.  */
dc03fd
 void
dc03fd
 state_writer::write_state_undefined_type (type_p current)
dc03fd
@@ -1143,6 +1159,9 @@ state_writer::write_state_type (type_p current)
dc03fd
 	case TYPE_STRING:
dc03fd
 	  write_state_string_type (current);
dc03fd
 	  break;
dc03fd
+	case TYPE_CALLBACK:
dc03fd
+	  write_state_callback_type (current);
dc03fd
+	  break;
dc03fd
 	}
dc03fd
     }
dc03fd
 
dc03fd
@@ -1477,6 +1496,14 @@ read_state_string_type (type_p *type)
dc03fd
   read_state_common_type_content (*type);
dc03fd
 }
dc03fd
 
dc03fd
+/* Read the callback_type.  */
dc03fd
+static void
dc03fd
+read_state_callback_type (type_p *type)
dc03fd
+{
dc03fd
+  *type = &callback_type;
dc03fd
+  read_state_common_type_content (*type);
dc03fd
+}
dc03fd
+
dc03fd
 
dc03fd
 /* Read a lang_bitmap representing a set of GCC front-end languages.  */
dc03fd
 static void
dc03fd
@@ -1834,6 +1861,11 @@ read_state_type (type_p *current)
dc03fd
 	      next_state_tokens (1);
dc03fd
 	      read_state_string_type (current);
dc03fd
 	    }
dc03fd
+	  else if (state_token_is_name (t0, "callback"))
dc03fd
+	    {
dc03fd
+	      next_state_tokens (1);
dc03fd
+	      read_state_callback_type (current);
dc03fd
+	    }
dc03fd
 	  else if (state_token_is_name (t0, "undefined"))
dc03fd
 	    {
dc03fd
 	      *current = XCNEW (struct type);
dc03fd
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
dc03fd
index a77cfd92bfa..b9daaa43689 100644
dc03fd
--- a/gcc/gengtype.c
dc03fd
+++ b/gcc/gengtype.c
dc03fd
@@ -172,6 +172,7 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
dc03fd
   int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0;
dc03fd
   int nb_lang_struct = 0;
dc03fd
   int nb_user_struct = 0, nb_undefined = 0;
dc03fd
+  int nb_callback = 0;
dc03fd
   type_p p = NULL;
dc03fd
   for (p = t; p; p = p->next)
dc03fd
     {
dc03fd
@@ -202,6 +203,9 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
dc03fd
 	case TYPE_ARRAY:
dc03fd
 	  nb_array++;
dc03fd
 	  break;
dc03fd
+	case TYPE_CALLBACK:
dc03fd
+	  nb_callback++;
dc03fd
+	  break;
dc03fd
 	case TYPE_LANG_STRUCT:
dc03fd
 	  nb_lang_struct++;
dc03fd
 	  break;
dc03fd
@@ -217,6 +221,8 @@ dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
dc03fd
     fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union);
dc03fd
   if (nb_pointer > 0 || nb_array > 0)
dc03fd
     fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array);
dc03fd
+  if (nb_callback > 0)
dc03fd
+    fprintf (stderr, "@@%%@@ %d callbacks\n", nb_callback);
dc03fd
   if (nb_lang_struct > 0)
dc03fd
     fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct);
dc03fd
   if (nb_user_struct > 0)
dc03fd
@@ -495,6 +501,10 @@ struct type scalar_char = {
dc03fd
   TYPE_SCALAR, 0, 0, 0, GC_USED, {0}
dc03fd
 };
dc03fd
 
dc03fd
+struct type callback_type = {
dc03fd
+  TYPE_CALLBACK, 0, 0, 0, GC_USED, {0}
dc03fd
+};
dc03fd
+
dc03fd
 /* Lists of various things.  */
dc03fd
 
dc03fd
 pair_p typedefs = NULL;
dc03fd
@@ -1464,7 +1474,7 @@ static void set_gc_used (pair_p);
dc03fd
 
dc03fd
 static void
dc03fd
 process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
dc03fd
-		    int *length, int *skip, type_p *nested_ptr)
dc03fd
+		    int *length, int *skip, int *callback, type_p *nested_ptr)
dc03fd
 {
dc03fd
   options_p o;
dc03fd
   for (o = opt; o; o = o->next)
dc03fd
@@ -1478,6 +1488,8 @@ process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
dc03fd
       *length = 1;
dc03fd
     else if (strcmp (o->name, "skip") == 0)
dc03fd
       *skip = 1;
dc03fd
+    else if (strcmp (o->name, "callback") == 0)
dc03fd
+      *callback = 1;
dc03fd
     else if (strcmp (o->name, "nested_ptr") == 0
dc03fd
 	     && o->kind == OPTION_NESTED)
dc03fd
       *nested_ptr = ((const struct nested_ptr_data *) o->info.nested)->type;
dc03fd
@@ -1526,7 +1538,7 @@ set_gc_used_type (type_p t, enum gc_used_enum level,
dc03fd
 	type_p dummy2;
dc03fd
 	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
dc03fd
 
dc03fd
-	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy,
dc03fd
+	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
dc03fd
 			    &dummy2);
dc03fd
 
dc03fd
 	if (t->u.s.base_class)
dc03fd
@@ -1542,9 +1554,10 @@ set_gc_used_type (type_p t, enum gc_used_enum level,
dc03fd
 	    int maybe_undef = 0;
dc03fd
 	    int length = 0;
dc03fd
 	    int skip = 0;
dc03fd
+	    int callback = 0;
dc03fd
 	    type_p nested_ptr = NULL;
dc03fd
 	    process_gc_options (f->opt, level, &maybe_undef, &length, &skip,
dc03fd
-				&nested_ptr);
dc03fd
+				&callback, &nested_ptr);
dc03fd
 
dc03fd
 	    if (nested_ptr && f->type->kind == TYPE_POINTER)
dc03fd
 	      set_gc_used_type (nested_ptr, GC_POINTED_TO);
dc03fd
@@ -1554,6 +1567,8 @@ set_gc_used_type (type_p t, enum gc_used_enum level,
dc03fd
 	      set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO);
dc03fd
 	    else if (skip)
dc03fd
 	      ;			/* target type is not used through this field */
dc03fd
+	    else if (callback)
dc03fd
+	      f->type = &callback_type;
dc03fd
 	    else
dc03fd
 	      set_gc_used_type (f->type, GC_USED, allow_undefined_field_types);
dc03fd
 	  }
dc03fd
@@ -2519,6 +2534,7 @@ output_mangled_typename (outf_p of, const_type_p t)
dc03fd
       {
dc03fd
       case TYPE_NONE:
dc03fd
       case TYPE_UNDEFINED:
dc03fd
+      case TYPE_CALLBACK:
dc03fd
 	gcc_unreachable ();
dc03fd
 	break;
dc03fd
       case TYPE_POINTER:
dc03fd
@@ -2719,6 +2735,8 @@ walk_type (type_p t, struct walk_type_data *d)
dc03fd
       ;
dc03fd
     else if (strcmp (oo->name, "for_user") == 0)
dc03fd
       ;
dc03fd
+    else if (strcmp (oo->name, "callback") == 0)
dc03fd
+      ;
dc03fd
     else
dc03fd
       error_at_line (d->line, "unknown option `%s'\n", oo->name);
dc03fd
 
dc03fd
@@ -2744,6 +2762,7 @@ walk_type (type_p t, struct walk_type_data *d)
dc03fd
     {
dc03fd
     case TYPE_SCALAR:
dc03fd
     case TYPE_STRING:
dc03fd
+    case TYPE_CALLBACK:
dc03fd
       d->process_field (t, d);
dc03fd
       break;
dc03fd
 
dc03fd
@@ -3275,6 +3294,7 @@ write_types_process_field (type_p f, const struct walk_type_data *d)
dc03fd
       break;
dc03fd
 
dc03fd
     case TYPE_SCALAR:
dc03fd
+    case TYPE_CALLBACK:
dc03fd
       break;
dc03fd
 
dc03fd
     case TYPE_ARRAY:
dc03fd
@@ -3820,6 +3840,7 @@ write_types_local_user_process_field (type_p f, const struct walk_type_data *d)
dc03fd
       break;
dc03fd
 
dc03fd
     case TYPE_SCALAR:
dc03fd
+    case TYPE_CALLBACK:
dc03fd
       break;
dc03fd
 
dc03fd
     case TYPE_ARRAY:
dc03fd
@@ -3906,6 +3927,13 @@ write_types_local_process_field (type_p f, const struct walk_type_data *d)
dc03fd
     case TYPE_SCALAR:
dc03fd
       break;
dc03fd
 
dc03fd
+    case TYPE_CALLBACK:
dc03fd
+      oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
dc03fd
+	       d->prev_val[3]);
dc03fd
+      oprintf (d->of, "%*s  gt_pch_note_callback (&(%s), this_obj);\n",
dc03fd
+	       d->indent, "", d->val);
dc03fd
+      break;
dc03fd
+
dc03fd
     case TYPE_ARRAY:
dc03fd
     case TYPE_NONE:
dc03fd
     case TYPE_UNDEFINED:
dc03fd
@@ -4434,6 +4462,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
dc03fd
     case TYPE_UNDEFINED:
dc03fd
     case TYPE_UNION:
dc03fd
     case TYPE_LANG_STRUCT:
dc03fd
+    case TYPE_CALLBACK:
dc03fd
       error_at_line (line, "global `%s' is unimplemented type", name);
dc03fd
     }
dc03fd
 }
dc03fd
@@ -4728,6 +4757,9 @@ dump_typekind (int indent, enum typekind kind)
dc03fd
     case TYPE_ARRAY:
dc03fd
       printf ("TYPE_ARRAY");
dc03fd
       break;
dc03fd
+    case TYPE_CALLBACK:
dc03fd
+      printf ("TYPE_CALLBACK");
dc03fd
+      break;
dc03fd
     case TYPE_LANG_STRUCT:
dc03fd
       printf ("TYPE_LANG_STRUCT");
dc03fd
       break;
dc03fd
@@ -4894,6 +4926,7 @@ dump_type (int indent, type_p t)
dc03fd
 	      t->u.scalar_is_char ? "true" : "false");
dc03fd
       break;
dc03fd
     case TYPE_STRING:
dc03fd
+    case TYPE_CALLBACK:
dc03fd
       break;
dc03fd
     case TYPE_STRUCT:
dc03fd
     case TYPE_UNION:
dc03fd
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
dc03fd
index 8a7a54957ea..8fa7064ca85 100644
dc03fd
--- a/gcc/gengtype.h
dc03fd
+++ b/gcc/gengtype.h
dc03fd
@@ -154,6 +154,9 @@ enum typekind {
dc03fd
   TYPE_UNION,           /* Type for GTY-ed discriminated unions.  */
dc03fd
   TYPE_POINTER,         /* Pointer type to GTY-ed type.  */
dc03fd
   TYPE_ARRAY,           /* Array of GTY-ed types.  */
dc03fd
+  TYPE_CALLBACK,	/* A function pointer that needs relocation if
dc03fd
+			   the executable has been loaded at a different
dc03fd
+			   address.  */
dc03fd
   TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
dc03fd
                            Various languages may have homonymous but
dc03fd
                            different structs.  */
dc03fd
@@ -331,6 +334,9 @@ extern struct type string_type;
dc03fd
 extern struct type scalar_nonchar;
dc03fd
 extern struct type scalar_char;
dc03fd
 
dc03fd
+/* The one and only TYPE_CALLBACK.  */
dc03fd
+extern struct type callback_type;
dc03fd
+
dc03fd
 /* Test if a type is a union, either a plain one or a language
dc03fd
    specific one.  */
dc03fd
 #define UNION_P(x)					\
dc03fd
diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c
dc03fd
index b6abed1d9a2..7c998e95473 100644
dc03fd
--- a/gcc/ggc-common.c
dc03fd
+++ b/gcc/ggc-common.c
dc03fd
@@ -256,6 +256,7 @@ saving_hasher::equal (const ptr_data *p1
dc03fd
 }
dc03fd
 
dc03fd
 static hash_table<saving_hasher> *saving_htab;
dc03fd
+static vec<void *> callback_vec;
dc03fd
 
dc03fd
 /* Register an object in the hash table.  */
dc03fd
 
dc03fd
@@ -288,6 +289,23 @@ gt_pch_note_object (void *obj, void *not
dc03fd
   return 1;
dc03fd
 }
dc03fd
 
dc03fd
+/* Register address of a callback pointer.  */
dc03fd
+void
dc03fd
+gt_pch_note_callback (void *obj, void *base)
dc03fd
+{
dc03fd
+  void *ptr;
dc03fd
+  memcpy (&ptr, obj, sizeof (void *));
dc03fd
+  if (ptr != NULL)
dc03fd
+    {
dc03fd
+      struct ptr_data *data
dc03fd
+	= (struct ptr_data *)
dc03fd
+	  saving_htab->find_with_hash (base, POINTER_HASH (base));
dc03fd
+      gcc_assert (data);
dc03fd
+      callback_vec.safe_push ((char *) data->new_addr
dc03fd
+			      + ((char *) obj - (char *) base));
dc03fd
+    }
dc03fd
+}
dc03fd
+
dc03fd
 /* Register an object in the hash table.  */
dc03fd
 
dc03fd
 void
dc03fd
@@ -582,10 +600,20 @@ gt_pch_save (FILE *f)
dc03fd
   ggc_pch_finish (state.d, state.f);
dc03fd
   gt_pch_fixup_stringpool ();
dc03fd
 
dc03fd
+  unsigned num_callbacks = callback_vec.length ();
dc03fd
+  void (*pch_save) (FILE *) = &gt_pch_save;
dc03fd
+  if (fwrite (&pch_save, sizeof (pch_save), 1, f) != 1
dc03fd
+      || fwrite (&num_callbacks, sizeof (num_callbacks), 1, f) != 1
dc03fd
+      || (num_callbacks
dc03fd
+	  && fwrite (callback_vec.address (), sizeof (void *), num_callbacks,
dc03fd
+		     f) != num_callbacks))
dc03fd
+    fatal_error (input_location, "cannot write PCH file: %m");
dc03fd
+
dc03fd
   XDELETE (state.ptrs);
dc03fd
   XDELETE (this_object);
dc03fd
   delete saving_htab;
dc03fd
   saving_htab = NULL;
dc03fd
+  callback_vec.release ();
dc03fd
 }
dc03fd
 
dc03fd
 /* Read the state of the compiler back in from F.  */
dc03fd
@@ -639,6 +667,30 @@ gt_pch_restore (FILE *f)
dc03fd
   ggc_pch_read (f, mmi.preferred_base);
dc03fd
 
dc03fd
   gt_pch_restore_stringpool ();
dc03fd
+
dc03fd
+  void (*pch_save) (FILE *);
dc03fd
+  unsigned num_callbacks;
dc03fd
+  if (fread (&pch_save, sizeof (pch_save), 1, f) != 1
dc03fd
+      || fread (&num_callbacks, sizeof (num_callbacks), 1, f) != 1)
dc03fd
+    fatal_error (input_location, "cannot read PCH file: %m");
dc03fd
+  if (pch_save != &gt_pch_save)
dc03fd
+    {
dc03fd
+      uintptr_t bias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
dc03fd
+      void **ptrs = XNEWVEC (void *, num_callbacks);
dc03fd
+      unsigned i;
dc03fd
+
dc03fd
+      if (fread (ptrs, sizeof (void *), num_callbacks, f) != num_callbacks)
dc03fd
+	fatal_error (input_location, "cannot read PCH file: %m");
dc03fd
+      for (i = 0; i < num_callbacks; ++i)
dc03fd
+	{
dc03fd
+	  memcpy (&pch_save, ptrs[i], sizeof (pch_save));
dc03fd
+	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + bias);
dc03fd
+	  memcpy (ptrs[i], &pch_save, sizeof (pch_save));
dc03fd
+	}
dc03fd
+      XDELETE (ptrs);
dc03fd
+    }
dc03fd
+  else if (fseek (f, num_callbacks * sizeof (void *), SEEK_CUR) != 0)
dc03fd
+    fatal_error (input_location, "cannot read PCH file: %m");
dc03fd
 }
dc03fd
 
dc03fd
 /* Default version of HOST_HOOKS_GT_PCH_GET_ADDRESS when mmap is not present.
dc03fd
diff --git a/gcc/ggc.h b/gcc/ggc.h
dc03fd
index 5e921d957fd..c005f7e0412 100644
dc03fd
--- a/gcc/ggc.h
dc03fd
+++ b/gcc/ggc.h
dc03fd
@@ -46,6 +46,10 @@ typedef void (*gt_handle_reorder) (void *, void *, gt_pointer_operator,
dc03fd
 /* Used by the gt_pch_n_* routines.  Register an object in the hash table.  */
dc03fd
 extern int gt_pch_note_object (void *, void *, gt_note_pointers);
dc03fd
 
dc03fd
+/* Used by the gt_pch_p_* routines.  Register address of a callback
dc03fd
+   pointer.  */
dc03fd
+extern void gt_pch_note_callback (void *, void *);
dc03fd
+
dc03fd
 /* Used by the gt_pch_n_* routines.  Register that an object has a reorder
dc03fd
    function.  */
dc03fd
 extern void gt_pch_note_reorder (void *, void *, gt_handle_reorder);
dc03fd
diff --git a/gcc/output.h b/gcc/output.h
dc03fd
index 8f6f15308f4..4a23795bf7e 100644
dc03fd
--- a/gcc/output.h
dc03fd
+++ b/gcc/output.h
dc03fd
@@ -456,7 +456,7 @@ struct GTY(()) named_section {
dc03fd
 
dc03fd
 /* A callback that writes the assembly code for switching to an unnamed
dc03fd
    section.  The argument provides callback-specific data.  */
dc03fd
-typedef void (*unnamed_section_callback) (const void *);
dc03fd
+typedef void (*unnamed_section_callback) (const char *);
dc03fd
 
dc03fd
 /* Information about a SECTION_UNNAMED section.  */
dc03fd
 struct GTY(()) unnamed_section {
dc03fd
@@ -464,8 +464,8 @@ struct GTY(()) unnamed_section {
dc03fd
 
dc03fd
   /* The callback used to switch to the section, and the data that
dc03fd
      should be passed to the callback.  */
dc03fd
-  unnamed_section_callback GTY ((skip)) callback;
dc03fd
-  const void *GTY ((skip)) data;
dc03fd
+  unnamed_section_callback GTY ((callback)) callback;
dc03fd
+  const char *data;
dc03fd
 
dc03fd
   /* The next entry in the chain of unnamed sections.  */
dc03fd
   section *next;
dc03fd
@@ -489,7 +489,7 @@ struct GTY(()) noswitch_section {
dc03fd
   struct section_common common;
dc03fd
 
dc03fd
   /* The callback used to assemble decls in this section.  */
dc03fd
-  noswitch_section_callback GTY ((skip)) callback;
dc03fd
+  noswitch_section_callback GTY ((callback)) callback;
dc03fd
 };
dc03fd
 
dc03fd
 /* Information about a section, which may be named or unnamed.  */
dc03fd
@@ -524,8 +524,8 @@ extern GTY(()) section *bss_noswitch_sec
dc03fd
 extern GTY(()) section *in_section;
dc03fd
 extern GTY(()) bool in_cold_section_p;
dc03fd
 
dc03fd
-extern section *get_unnamed_section (unsigned int, void (*) (const void *),
dc03fd
-				     const void *);
dc03fd
+extern section *get_unnamed_section (unsigned int, void (*) (const char *),
dc03fd
+				     const char *);
dc03fd
 extern section *get_section (const char *, unsigned int, tree);
dc03fd
 extern section *get_named_section (tree, const char *, int);
dc03fd
 extern section *get_variable_section (tree, bool);
dc03fd
@@ -546,7 +546,7 @@ extern section *get_cdtor_priority_secti
dc03fd
 
dc03fd
 extern bool unlikely_text_section_p (section *);
dc03fd
 extern void switch_to_section (section *);
dc03fd
-extern void output_section_asm_op (const void *);
dc03fd
+extern void output_section_asm_op (const char *);
dc03fd
 
dc03fd
 extern void record_tm_clone_pair (tree, tree);
dc03fd
 extern void finish_tm_clone_pairs (void);
dc03fd
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
dc03fd
index 8ab119dc9a2..91ae5237d7e 100644
dc03fd
--- a/gcc/tree-core.h
dc03fd
+++ b/gcc/tree-core.h
dc03fd
@@ -1961,7 +1961,7 @@ struct GTY(()) tree_function_decl {
dc03fd
 struct GTY(()) tree_translation_unit_decl {
dc03fd
   struct tree_decl_common common;
dc03fd
   /* Source language of this translation unit.  Used for DWARF output.  */
dc03fd
-  const char * GTY((skip(""))) language;
dc03fd
+  const char *language;
dc03fd
   /* TODO: Non-optimization used to build this translation unit.  */
dc03fd
   /* TODO: Root of a partial DWARF tree for global types and decls.  */
dc03fd
 };
dc03fd
diff --git a/gcc/varasm.c b/gcc/varasm.c
dc03fd
index 9315e2c6936..aff93ca5de9 100644
dc03fd
--- a/gcc/varasm.c
dc03fd
+++ b/gcc/varasm.c
dc03fd
@@ -250,8 +250,8 @@ object_block_hasher::hash (object_block *old)
dc03fd
 /* Return a new unnamed section with the given fields.  */
dc03fd
 
dc03fd
 section *
dc03fd
-get_unnamed_section (unsigned int flags, void (*callback) (const void *),
dc03fd
-		     const void *data)
dc03fd
+get_unnamed_section (unsigned int flags, void (*callback) (const char *),
dc03fd
+		     const char *data)
dc03fd
 {
dc03fd
   section *sect;
dc03fd
 
dc03fd
@@ -7778,9 +7778,9 @@ file_end_indicate_split_stack (void)
dc03fd
    a get_unnamed_section callback.  */
dc03fd
 
dc03fd
 void
dc03fd
-output_section_asm_op (const void *directive)
dc03fd
+output_section_asm_op (const char *directive)
dc03fd
 {
dc03fd
-  fprintf (asm_out_file, "%s\n", (const char *) directive);
dc03fd
+  fprintf (asm_out_file, "%s\n", directive);
dc03fd
 }
dc03fd
 
dc03fd
 /* Emit assembly code to switch to section NEW_SECTION.  Do nothing if
dc03fd
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
dc03fd
index 8b5e2f82982..bc40e333579 100644
dc03fd
--- a/libcpp/include/line-map.h
dc03fd
+++ b/libcpp/include/line-map.h
dc03fd
@@ -758,11 +758,11 @@ struct GTY(()) line_maps {
dc03fd
 
dc03fd
   /* If non-null, the allocator to use when resizing 'maps'.  If null,
dc03fd
      xrealloc is used.  */
dc03fd
-  line_map_realloc reallocator;
dc03fd
+  line_map_realloc GTY((callback)) reallocator;
dc03fd
 
dc03fd
   /* The allocators' function used to know the actual size it
dc03fd
      allocated, for a certain allocation size requested.  */
dc03fd
-  line_map_round_alloc_size_func round_alloc_size;
dc03fd
+  line_map_round_alloc_size_func GTY((callback)) round_alloc_size;
dc03fd
 
dc03fd
   struct location_adhoc_data_map location_adhoc_data_map;
dc03fd
 
dc03fd
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
dc03fd
index 6ba038881d6..1c2f7d564e7 100644
dc03fd
--- a/gcc/config/avr/avr.c
dc03fd
+++ b/gcc/config/avr/avr.c
dc03fd
@@ -10089,7 +10089,7 @@ avr_asm_asm_output_aligned_bss (FILE *file, tree decl, const char *name,
dc03fd
    to track need of __do_copy_data.  */
dc03fd
 
dc03fd
 static void
dc03fd
-avr_output_data_section_asm_op (const void *data)
dc03fd
+avr_output_data_section_asm_op (const char *data)
dc03fd
 {
dc03fd
   avr_need_copy_data_p = true;
dc03fd
 
dc03fd
@@ -10102,7 +10102,7 @@ avr_output_data_section_asm_op (const void *data)
dc03fd
    to track need of __do_clear_bss.  */
dc03fd
 
dc03fd
 static void
dc03fd
-avr_output_bss_section_asm_op (const void *data)
dc03fd
+avr_output_bss_section_asm_op (const char *data)
dc03fd
 {
dc03fd
   avr_need_clear_bss_p = true;
dc03fd