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