Message ID | 20211118080459.GO2710@tucnak |
---|---|
State | New |
Headers | show |
Series | pch, v2: Add support for PCH for relocatable executables | expand |
On 11/18/2021 1:04 AM, Jakub Jelinek wrote: > On Mon, Nov 08, 2021 at 08:48:07PM +0100, Jakub Jelinek via Gcc-patches 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. >> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp. >> >> 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. > Here is an updated version (the previous version doesn't apply any longer > in gt_pch_restore due to the line_maps saving/restoring changes). > > Bootstrapped/regtested on x86_64-linux and i686-linux with > --enable-host-shared in addition to normal configure options (and without > Ada which doesn't even with the above options build PIC libgnat.a and links > it) and a hack: > --- gcc/configure.ac.jj 2021-10-28 22:12:31.569299780 +0200 > +++ gcc/configure.ac 2021-11-09 11:34:33.453776105 +0100 > @@ -7566,7 +7566,7 @@ AC_CACHE_CHECK([for -no-pie option], > [gcc_cv_no_pie=no]) > LDFLAGS="$saved_LDFLAGS"]) > if test "$gcc_cv_no_pie" = "yes"; then > - NO_PIE_FLAG="-no-pie" > + NO_PIE_FLAG="-pie" > fi > AC_SUBST([NO_PIE_FLAG]) > > to force binaries be PIE, no regressions against non-PIC/PIE build > without this patch. Ok for trunk? > > 2021-11-18 Jakub Jelinek <jakub@redhat.com> > > PR pch/71934 > 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. You know this code better than anyone I suspect. If it's working and you're confortable with it, I suggest going forward with it. Jeff
On 11/18/21 09:04, Jakub Jelinek via Gcc-patches wrote: > On Mon, Nov 08, 2021 at 08:48:07PM +0100, Jakub Jelinek via Gcc-patches 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. >> Other than that make check-gcc check-g++ passes RUNTESTFLAGS=pch.exp. >> >> 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. > > Here is an updated version (the previous version doesn't apply any longer > in gt_pch_restore due to the line_maps saving/restoring changes). > > Bootstrapped/regtested on x86_64-linux and i686-linux with > --enable-host-shared in addition to normal configure options (and without > Ada which doesn't even with the above options build PIC libgnat.a and links > it) and a hack: > --- gcc/configure.ac.jj 2021-10-28 22:12:31.569299780 +0200 > +++ gcc/configure.ac 2021-11-09 11:34:33.453776105 +0100 > @@ -7566,7 +7566,7 @@ AC_CACHE_CHECK([for -no-pie option], > [gcc_cv_no_pie=no]) > LDFLAGS="$saved_LDFLAGS"]) > if test "$gcc_cv_no_pie" = "yes"; then > - NO_PIE_FLAG="-no-pie" > + NO_PIE_FLAG="-pie" > fi > AC_SUBST([NO_PIE_FLAG]) > > to force binaries be PIE, no regressions against non-PIC/PIE build > without this patch. Ok for trunk? > > 2021-11-18 Jakub Jelinek <jakub@redhat.com> > > PR pch/71934 > 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-17 20:10:07.088187637 +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 > @@ -576,10 +594,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 *) = >_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. */ > @@ -661,6 +689,30 @@ gt_pch_restore (FILE *f) > > 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 != >_pch_save) > + { > + uintptr_t bias = (uintptr_t) >_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"); > + > /* Barring corruption of the PCH file, the restored line table should be > complete and usable. */ > line_table = new_line_table; > --- 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 > Jakub, I think the patch broke avr-linux target: g++ -fno-PIE -c -g -DIN_GCC -DCROSS_DIRECTORY_STRUCTURE -fno-exceptions -fno-rtti -fasynchronous-unwind-tables -W -Wall -Wno-narrowing -Wwrite-strings -Wcast-qual -Wno-error=format-diag -Wmissing-format-attribute -Woverloaded-virtual -pedantic -Wno-long-long -Wno-variadic-macros -Wno-overlength-strings -fno-common -DHAVE_CONFIG_H -I. -I. -I/home/marxin/Programming/gcc/gcc -I/home/marxin/Programming/gcc/gcc/. -I/home/marxin/Programming/gcc/gcc/../include -I/home/marxin/Programming/gcc/gcc/../libcpp/include -I/home/marxin/Programming/gcc/gcc/../libcody -I/home/marxin/Programming/gcc/gcc/../libdecnumber -I/home/marxin/Programming/gcc/gcc/../libdecnumber/dpd -I../libdecnumber -I/home/marxin/Programming/gcc/gcc/../libbacktrace -o avr.o -MT avr.o -MMD -MP -MF ./.deps/avr.TPo /home/marxin/Programming/gcc/gcc/config/avr/avr.c /home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_output_data_section_asm_op(const void*)’: /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10097:26: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive] 10097 | output_section_asm_op (data); | ^~~~ | | | const void* In file included from /home/marxin/Programming/gcc/gcc/config/avr/avr.c:49: /home/marxin/Programming/gcc/gcc/output.h:564:36: note: initializing argument 1 of ‘void output_section_asm_op(const char*)’ 564 | extern void output_section_asm_op (const char *); | ^~~~~~~~~~~~ /home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_output_bss_section_asm_op(const void*)’: /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10110:26: error: invalid conversion from ‘const void*’ to ‘const char*’ [-fpermissive] 10110 | output_section_asm_op (data); | ^~~~ | | | const void* In file included from /home/marxin/Programming/gcc/gcc/config/avr/avr.c:49: /home/marxin/Programming/gcc/gcc/output.h:564:36: note: initializing argument 1 of ‘void output_section_asm_op(const char*)’ 564 | extern void output_section_asm_op (const char *); | ^~~~~~~~~~~~ /home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘void avr_asm_init_sections()’: /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10135:47: error: invalid conversion from ‘void (*)(const void*)’ to ‘unnamed_section_callback’ {aka ‘void (*)(const char*)’} [-fpermissive] 10135 | readonly_data_section->unnamed.callback = avr_output_data_section_asm_op; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | void (*)(const void*) /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10136:36: error: invalid conversion from ‘void (*)(const void*)’ to ‘unnamed_section_callback’ {aka ‘void (*)(const char*)’} [-fpermissive] 10136 | data_section->unnamed.callback = avr_output_data_section_asm_op; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | void (*)(const void*) /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10137:35: error: invalid conversion from ‘void (*)(const void*)’ to ‘unnamed_section_callback’ {aka ‘void (*)(const char*)’} [-fpermissive] 10137 | bss_section->unnamed.callback = avr_output_bss_section_asm_op; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | | void (*)(const void*) /home/marxin/Programming/gcc/gcc/config/avr/avr.c: In function ‘unsigned int avr_section_type_flags(tree, const char*, int)’: /home/marxin/Programming/gcc/gcc/config/avr/avr.c:10197:21: warning: space followed by punctuation character ‘.’ [-Wformat-diag] 10197 | warning (0, "only uninitialized variables can be placed in the " | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10198 | ".noinit section"); | ~~~~~~~~~~~~~~~~~ /home/marxin/Programming/gcc/gcc/config/avr/avr.c: At global scope: /home/marxin/Programming/gcc/gcc/config/avr/avr.c:12765:1: warning: ‘void avr_asm_out_dtor(rtx, int)’ defined but not used [-Wunused-function] 12765 | avr_asm_out_dtor (rtx symbol, int priority) | ^~~~~~~~~~~~~~~~ /home/marxin/Programming/gcc/gcc/config/avr/avr.c:12755:1: warning: ‘void avr_asm_out_ctor(rtx, int)’ defined but not used [-Wunused-function] 12755 | avr_asm_out_ctor (rtx symbol, int priority) | ^~~~~~~~~~~~~~~~ make: *** [Makefile:2413: avr.o] Error 1 Cheers, Martin
--- gcc/configure.ac.jj 2021-10-28 22:12:31.569299780 +0200 +++ gcc/configure.ac 2021-11-09 11:34:33.453776105 +0100 @@ -7566,7 +7566,7 @@ AC_CACHE_CHECK([for -no-pie option], [gcc_cv_no_pie=no]) LDFLAGS="$saved_LDFLAGS"]) if test "$gcc_cv_no_pie" = "yes"; then - NO_PIE_FLAG="-no-pie" + NO_PIE_FLAG="-pie" fi AC_SUBST([NO_PIE_FLAG]) to force binaries be PIE, no regressions against non-PIC/PIE build without this patch. Ok for trunk? 2021-11-18 Jakub Jelinek <jakub@redhat.com> PR pch/71934 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-17 20:10:07.088187637 +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 @@ -576,10 +594,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 *) = >_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. */ @@ -661,6 +689,30 @@ gt_pch_restore (FILE *f) 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 != >_pch_save) + { + uintptr_t bias = (uintptr_t) >_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"); + /* Barring corruption of the PCH file, the restored line table should be complete and usable. */ line_table = new_line_table; --- 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;