pch: Add support for PCH for relocatable executables

Message ID 20211108194807.GJ2710@tucnak
State Superseded
Headers
Series pch: Add support for PCH for relocatable executables |

Commit Message

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

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

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

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

Thoughts on this?

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

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



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

Comments

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

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

Dave
  
Richard Biener Nov. 9, 2021, 7:12 a.m. UTC | #2
On Mon, 8 Nov 2021, Jakub Jelinek wrote:

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

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

Hopefully PCH happens before init_tree_ssa.

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

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

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

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

Richard.

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

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

- This would be a fix for PR 71934

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

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

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

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

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

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

Agreed, Andrew/Aldy, what do you think?

> Hopefully PCH happens before init_tree_ssa.

I think it does.

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

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

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

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

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

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

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

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

I was trying:

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

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

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

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

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

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

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

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

2. This problem remains.

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

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

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

Iain

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

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

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

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

Yeah, certainly.

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

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

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

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

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

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

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

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

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

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

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

Andrew
  
Jakub Jelinek Nov. 9, 2021, 2:58 p.m. UTC | #12
On Tue, Nov 09, 2021 at 09:41:08AM -0500, Andrew MacLeod wrote:
> Yeah, Im not particular about how we do this...  I think thats perfectly
> reasonable.   Would something like the following solve this issue?

Yes, but see below.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Iain


> 
> 	Jakub
>
  
Iain Sandoe Nov. 10, 2021, 8:24 p.m. UTC | #16
Hi Folks,

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

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

>>> 2. This problem remains.

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

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

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

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

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

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

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

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

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

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

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

thoughts?
Iain
  
Iain Sandoe Nov. 13, 2021, 8:32 p.m. UTC | #17
Hi Folks,

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

could be useful - for Darwin I prefer this series.

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

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

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


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

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

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


===

To add to Jakub's two patches that do the heavy lifting - two configure changes (I have also
darwin-local changes which are under test at the moment with the intention to apply them
anyway).
  
Jakub Jelinek Nov. 16, 2021, 8:52 a.m. UTC | #18
On Sat, Nov 13, 2021 at 08:32:41PM +0000, Iain Sandoe wrote:
> IMO both this series
>  - which restores the ability to work with PIE exes but requires a known address for the PCH 
> and the series I posted
>  - which allows a configuration to opt out of PCH anyway
> 
> could be useful - for Darwin I prefer this series.

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

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

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

	Jakub
  

Patch

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