pch: Add support for relocation of the PCH data [PR71934]

Message ID 20211207095507.GV2646553@tucnak
State Committed
Headers
Series pch: Add support for relocation of the PCH data [PR71934] |

Commit Message

Jakub Jelinek Dec. 7, 2021, 9:55 a.m. UTC
  Hi!

The following patch adds support for relocation of the PCH blob on PCH
restore if we don't manage to get the preferred map slot for it.
The GTY stuff knows where all the pointers are, after all it relocates
it once during PCH save from the addresses where it was initially allocated
to addresses in the preferred map slot.
But, if we were to do it solely using GTY info upon PCH restore, we'd need
another set of GTY functions, which I think would make it less maintainable
and I think it would also be more costly at PCH restore time.  Those
functions would need to call something to add bias to pointers that haven't
been marked yet and make sure not to add bias to any pointer twice.

So, this patch instead builds a relocation table (sorted list of addresses
in the blob which needs relocation) at PCH save time, stores it in a very
compact form into the gch file and upon restore, adjusts pointers in GTY
roots (that is right away in the root structures) and the addresses in the
relocation table.
The cost on stdc++.gch/O2g.gch (previously 85MB large) is about 3% file size
growth, there are 2.5 million pointers that need relocation in the gch blob
and the relocation table uses uleb128 for address deltas and needs ~1.01 bytes
for one address that needs relocation, and about 20% compile time during
PCH save (I think it is mainly because of the need to qsort those 2.5
million pointers).  On PCH restore, if it doesn't need relocation (the usual
case), it is just an extra fread of sizeof (size_t) data and fseek
(in my tests real time on vanilla tree for #include <bits/stdc++.h> CU
was ~0.175s and with the patch but no relocation ~0.173s), while if it needs
relocation it took ~0.193s, i.e. 11.5% slower.

The discovery of the pointers in the blob that need relocation is done
in the relocate_ptrs hook which does the pointer relocation during PCH save.
Unfortunately, I had to make one change to the gengtype stuff due to the
nested_ptr feature of GTY, which some libcpp headers and stringpool.c use.
The relocate_ptrs hook had 2 arguments, pointer to the pointer and a cookie.
When relocate_ptrs is done, in most cases it is called solely on the
subfields of the current object, so e.g.
          if ((void *)(x) == this_obj)
            op (&((*x).u.fld[0].rt_rtx), cookie);
so relocate_ptrs can assert that ptr_p is within the
state->ptrs[state->ptrs_i]->obj ..
state->ptrs[state->ptrs_i]->obj+state->ptrs[state->ptrs_i]->size-sizeof(void*)
range and compute from that the address in the blob which will need
relocation (state->ptrs[state->ptrs_i]->new_addr is the new address
given to it and ptr_p-state->ptrs[state->ptrs_i]->obj is the relative
offset.  Unfortunately, for nested_ptr gengtype emits something like:
      {
        union tree_node * x0 =
          ((*x).val.node.node) ? HT_IDENT_TO_GCC_IDENT (HT_NODE (((*x).val.node.node))) : NULL;
        if ((void *)(x) == this_obj)
          op (&(x0), cookie);
        (*x).val.node.node = (x0) ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT ((x0))) : NULL;
      }
so relocate_ptrs is called with an address of some temporary variable and
so doesn't know where the pointer will finally be.
So, I've added another argument to relocate_ptrs (and to
gt_pointer_operator).  For the most common case I pass NULL as the new middle
argument to that function, first one remains pointer to the pointer that
needs adjustment and last the cookie.  The NULL seems to be cheap to compute
and short in the gt*.[ch] files and stands for ptr_p is an address within
the this_obj's range, remember its address.  For the nested_ptr case, the
new middle argument contains actual address of the pointer that might need
to be relocated, so instead of the above
          op (&(x0), &((*x).val.node.node), cookie);
in there.  And finally, e.g. for the reorder case I need a way to tell
restore_ptrs to ignore a particular address for the relocation purposes
and only treat it the old way.  I've used for that the case when
the first and second arguments are equal.

In order to enable support for mapping PCH as fallback at different
addresses than the preferred ones, a small change is needed to the
host pch_use_address hooks.  One change I've done to all of them is
the change of the type of the first argument from void * to void *&,
such that the actual address can be told to the callers (or shall I
instead use void **?), but another change that still needs to be done
in them if they want the relocation is actually not fail if they couldn't
get a preferred address, but instead modify what the first argument
refers to.  I've done that only for host-linux.c and Iain is testing
similar change for host-darwin.c.  Didn't change hpux, netbsd, openbsd,
solaris, mingw32 or the fallbacks because I can't test those.

Bootstrapped/regtested on x86_64-linux and i686-linux (both as is and with
incremental

	Jakub
  

Comments

Jakub Jelinek Dec. 7, 2021, 2:50 p.m. UTC | #1
On Tue, Dec 07, 2021 at 10:55:07AM +0100, Jakub Jelinek via Gcc-patches wrote:
> So, this patch instead builds a relocation table (sorted list of addresses
> in the blob which needs relocation) at PCH save time, stores it in a very
> compact form into the gch file and upon restore, adjusts pointers in GTY
> roots (that is right away in the root structures) and the addresses in the
> relocation table.
> The cost on stdc++.gch/O2g.gch (previously 85MB large) is about 3% file size
> growth, there are 2.5 million pointers that need relocation in the gch blob
> and the relocation table uses uleb128 for address deltas and needs ~1.01 bytes
> for one address that needs relocation, and about 20% compile time during
> PCH save (I think it is mainly because of the need to qsort those 2.5
> million pointers).  On PCH restore, if it doesn't need relocation (the usual
> case), it is just an extra fread of sizeof (size_t) data and fseek
> (in my tests real time on vanilla tree for #include <bits/stdc++.h> CU
> was ~0.175s and with the patch but no relocation ~0.173s), while if it needs
> relocation it took ~0.193s, i.e. 11.5% slower.

I'll note that without PCH that
#include <bits/stdc++.h>
int i;
testcase compiles with -O2 -g in ~1.199s, i.e. 6.2 times slower than PCH with
relocation and 6.9 times than PCH without relocation.

	Jakub
  
Iain Sandoe Dec. 8, 2021, 8 a.m. UTC | #2
> On 7 Dec 2021, at 14:50, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> On Tue, Dec 07, 2021 at 10:55:07AM +0100, Jakub Jelinek via Gcc-patches wrote:
>> So, this patch instead builds a relocation table (sorted list of addresses
>> in the blob which needs relocation) at PCH save time, stores it in a very
>> compact form into the gch file and upon restore, adjusts pointers in GTY
>> roots (that is right away in the root structures) and the addresses in the
>> relocation table.
>> The cost on stdc++.gch/O2g.gch (previously 85MB large) is about 3% file size
>> growth, there are 2.5 million pointers that need relocation in the gch blob
>> and the relocation table uses uleb128 for address deltas and needs ~1.01 bytes
>> for one address that needs relocation, and about 20% compile time during
>> PCH save (I think it is mainly because of the need to qsort those 2.5
>> million pointers).  On PCH restore, if it doesn't need relocation (the usual
>> case), it is just an extra fread of sizeof (size_t) data and fseek
>> (in my tests real time on vanilla tree for #include <bits/stdc++.h> CU
>> was ~0.175s and with the patch but no relocation ~0.173s), while if it needs
>> relocation it took ~0.193s, i.e. 11.5% slower.
> 
> I'll note that without PCH that
> #include <bits/stdc++.h>
> int i;
> testcase compiles with -O2 -g in ~1.199s, i.e. 6.2 times slower than PCH with
> relocation and 6.9 times than PCH without relocation.

I’ve run tests across the Darwin range, including old and new m32 hosts, and this
seems to be working well.

The attached patch should be applied before (or merged with) the change for
relocation when it is applied - since the operation of the PCH hooks needs some
adjustment on Darwin.

thanks for working on this!
Iain
  
Jeff Law Dec. 8, 2021, 11:09 p.m. UTC | #3
On 12/7/2021 2:55 AM, Jakub Jelinek wrote:
> Hi!
>
> The following patch adds support for relocation of the PCH blob on PCH
> restore if we don't manage to get the preferred map slot for it.
> The GTY stuff knows where all the pointers are, after all it relocates
> it once during PCH save from the addresses where it was initially allocated
> to addresses in the preferred map slot.
> But, if we were to do it solely using GTY info upon PCH restore, we'd need
> another set of GTY functions, which I think would make it less maintainable
> and I think it would also be more costly at PCH restore time.  Those
> functions would need to call something to add bias to pointers that haven't
> been marked yet and make sure not to add bias to any pointer twice.
>
> So, this patch instead builds a relocation table (sorted list of addresses
> in the blob which needs relocation) at PCH save time, stores it in a very
> compact form into the gch file and upon restore, adjusts pointers in GTY
> roots (that is right away in the root structures) and the addresses in the
> relocation table.
> The cost on stdc++.gch/O2g.gch (previously 85MB large) is about 3% file size
> growth, there are 2.5 million pointers that need relocation in the gch blob
> and the relocation table uses uleb128 for address deltas and needs ~1.01 bytes
> for one address that needs relocation, and about 20% compile time during
> PCH save (I think it is mainly because of the need to qsort those 2.5
> million pointers).  On PCH restore, if it doesn't need relocation (the usual
> case), it is just an extra fread of sizeof (size_t) data and fseek
> (in my tests real time on vanilla tree for #include <bits/stdc++.h> CU
> was ~0.175s and with the patch but no relocation ~0.173s), while if it needs
> relocation it took ~0.193s, i.e. 11.5% slower.
>
> The discovery of the pointers in the blob that need relocation is done
> in the relocate_ptrs hook which does the pointer relocation during PCH save.
> Unfortunately, I had to make one change to the gengtype stuff due to the
> nested_ptr feature of GTY, which some libcpp headers and stringpool.c use.
> The relocate_ptrs hook had 2 arguments, pointer to the pointer and a cookie.
> When relocate_ptrs is done, in most cases it is called solely on the
> subfields of the current object, so e.g.
>            if ((void *)(x) == this_obj)
>              op (&((*x).u.fld[0].rt_rtx), cookie);
> so relocate_ptrs can assert that ptr_p is within the
> state->ptrs[state->ptrs_i]->obj ..
> state->ptrs[state->ptrs_i]->obj+state->ptrs[state->ptrs_i]->size-sizeof(void*)
> range and compute from that the address in the blob which will need
> relocation (state->ptrs[state->ptrs_i]->new_addr is the new address
> given to it and ptr_p-state->ptrs[state->ptrs_i]->obj is the relative
> offset.  Unfortunately, for nested_ptr gengtype emits something like:
>        {
>          union tree_node * x0 =
>            ((*x).val.node.node) ? HT_IDENT_TO_GCC_IDENT (HT_NODE (((*x).val.node.node))) : NULL;
>          if ((void *)(x) == this_obj)
>            op (&(x0), cookie);
>          (*x).val.node.node = (x0) ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT ((x0))) : NULL;
>        }
> so relocate_ptrs is called with an address of some temporary variable and
> so doesn't know where the pointer will finally be.
> So, I've added another argument to relocate_ptrs (and to
> gt_pointer_operator).  For the most common case I pass NULL as the new middle
> argument to that function, first one remains pointer to the pointer that
> needs adjustment and last the cookie.  The NULL seems to be cheap to compute
> and short in the gt*.[ch] files and stands for ptr_p is an address within
> the this_obj's range, remember its address.  For the nested_ptr case, the
> new middle argument contains actual address of the pointer that might need
> to be relocated, so instead of the above
>            op (&(x0), &((*x).val.node.node), cookie);
> in there.  And finally, e.g. for the reorder case I need a way to tell
> restore_ptrs to ignore a particular address for the relocation purposes
> and only treat it the old way.  I've used for that the case when
> the first and second arguments are equal.
>
> In order to enable support for mapping PCH as fallback at different
> addresses than the preferred ones, a small change is needed to the
> host pch_use_address hooks.  One change I've done to all of them is
> the change of the type of the first argument from void * to void *&,
> such that the actual address can be told to the callers (or shall I
> instead use void **?), but another change that still needs to be done
> in them if they want the relocation is actually not fail if they couldn't
> get a preferred address, but instead modify what the first argument
> refers to.  I've done that only for host-linux.c and Iain is testing
> similar change for host-darwin.c.  Didn't change hpux, netbsd, openbsd,
> solaris, mingw32 or the fallbacks because I can't test those.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux (both as is and with
> incremental
> --- gcc/config/host-linux.c.jj	2021-12-06 22:22:42.007777367 +0100
> +++ gcc/config/host-linux.c	2021-12-07 00:21:53.052674040 +0100
> @@ -191,6 +191,8 @@ linux_gt_pch_use_address (void *&base, s
>     if (size == 0)
>       return -1;
>   
> +base = (char *) base + ((size + 8191) & (size_t) -4096);
> +
>     /* Try to map the file with MAP_PRIVATE.  */
>     addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset);
>   
> which forces all PCH restores to be relocated.  An earlier version of the
> patch has been also regrest with base = (char *) base + 16384; in that spot,
> so both relocation to a non-overlapping spot and to an overlapping spot have
> been tested.
>
> 2021-12-07  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR pch/71934
> 	* coretypes.h (gt_pointer_operator): Use 3 pointer arguments instead
> 	of two.
> 	* gengtype.c (struct walk_type_data): Add in_nested_ptr argument.
> 	(walk_type): Temporarily set d->in_nested_ptr around nested_ptr
> 	handling.
> 	(write_types_local_user_process_field): Pass a new middle pointer
> 	to gt_pointer_operator op calls, if d->in_nested_ptr pass there
> 	address of d->prev_val[2], otherwise NULL.
> 	(write_types_local_process_field): Likewise.
> 	* ggc-common.c (relocate_ptrs): Add real_ptr_p argument.  If equal
> 	to ptr_p, do nothing, otherwise if NULL remember ptr_p's
> 	or if non-NULL real_ptr_p's corresponding new address in
> 	reloc_addrs_vec.
> 	(reloc_addrs_vec): New variable.
> 	(compare_ptr, read_uleb128, write_uleb128): New functions.
> 	(gt_pch_save): When iterating over objects through relocate_ptrs,
> 	save current i into state.ptrs_i.  Sort reloc_addrs_vec and emit
> 	it as uleb128 of differences between pointer addresses into the
> 	PCH file.
> 	(gt_pch_restore): Allow restoring of PCH to a different address
> 	than the preferred one, in that case adjust global pointers by bias
> 	and also adjust by bias addresses read from the relocation table
> 	as uleb128 differences.  Otherwise fseek over it.  Perform
> 	gt_pch_restore_stringpool only after adjusting callbacks and for
> 	callback adjustments also take into account the bias.
> 	(default_gt_pch_use_address): Change type of first argument from
> 	void * to void *&.
> 	(mmap_gt_pch_use_address): Likewise.
> 	* ggc-tests.c (gt_pch_nx): Pass NULL as new middle argument to op.
> 	* hash-map.h (hash_map::pch_nx_helper): Likewise.
> 	(gt_pch_nx): Likewise.
> 	* hash-set.h (gt_pch_nx): Likewise.
> 	* hash-table.h (gt_pch_nx): Likewise.
> 	* hash-traits.h (ggc_remove::pch_nx): Likewise.
> 	* hosthooks-def.h (default_gt_pch_use_address): Change type of first
> 	argument from void * to void *&.
> 	(mmap_gt_pch_use_address): Likewise.
> 	* hosthooks.h (struct host_hooks): Change type of first argument of
> 	gt_pch_use_address hook from void * to void *&.
> 	* machmode.h (gt_pch_nx): Expect a callback with 3 pointers instead of
> 	two in the middle argument.
> 	* poly-int.h (gt_pch_nx): Likewise.
> 	* stringpool.c (gt_pch_nx): Pass NULL as new middle argument to op.
> 	* tree-cfg.c (gt_pch_nx): Likewise, except for LOCATION_BLOCK pass
> 	the same &(block) twice.
> 	* value-range.h (gt_pch_nx): Pass NULL as new middle argument to op.
> 	* vec.h (gt_pch_nx): Likewise.
> 	* wide-int.h (gt_pch_nx): Likewise.
> 	* config/host-darwin.c (darwin_gt_pch_use_address): Change type of
> 	first argument from void * to void *&.
> 	* config/host-darwin.h (darwin_gt_pch_use_address): Likewise.
> 	* config/host-hpux.c (hpux_gt_pch_use_address): Likewise.
> 	* config/host-linux.c (linux_gt_pch_use_address): Likewise.  If
> 	it couldn't succeed to mmap at the preferred location, set base
> 	to the actual one.  Update addr in the manual reading loop instead of
> 	base.
> 	* config/host-netbsd.c (netbsd_gt_pch_use_address): Change type of
> 	first argument from void * to void *&.
> 	* config/host-openbsd.c (openbsd_gt_pch_use_address): Likewise.
> 	* config/host-solaris.c (sol_gt_pch_use_address): Likewise.
> 	* config/i386/host-mingw32.c (mingw32_gt_pch_use_address): Likewise.
> 	* config/rs6000/rs6000-gen-builtins.c (write_init_file): Pass NULL
> 	as new middle argument to op in the generated code.
> 	* doc/gty.texi: Adjust samples for the addition of middle pointer
> 	to gt_pointer_operator callback.
> gcc/ada/
> 	* gcc-interface/decl.c (gt_pch_nx): Pass NULL as new middle argument
> 	to op.
> gcc/c-family/
> 	* c-pch.c (c_common_no_more_pch): Pass a temporary void * var
> 	with NULL value instead of NULL to host_hooks.gt_pch_use_address.
> gcc/c/
> 	* c-decl.c (resort_field_decl_cmp): Pass the same pointer twice
> 	to resort_data.new_value.
> gcc/cp/
> 	* module.cc (nop): Add another void * argument.
> 	* name-lookup.c (resort_member_name_cmp): Pass the same pointer twice
> 	to resort_data.new_value.
Like the prior patch in this space, you know this better than anyone, so 
if you're comfortable, I think you should commit.

I wonder if this is sufficient for the Ruby team to re-enable GCC PCH 
support.  IIRC the whole problem was we couldn't deal with PIE & PCH and 
I think this fixes that problem, right?  If so, you might want to reach 
out to them.

Jeff
  
Jeff Law Dec. 8, 2021, 11:10 p.m. UTC | #4
On 12/8/2021 1:00 AM, Iain Sandoe wrote:
>
>> On 7 Dec 2021, at 14:50, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>
>> On Tue, Dec 07, 2021 at 10:55:07AM +0100, Jakub Jelinek via Gcc-patches wrote:
>>> So, this patch instead builds a relocation table (sorted list of addresses
>>> in the blob which needs relocation) at PCH save time, stores it in a very
>>> compact form into the gch file and upon restore, adjusts pointers in GTY
>>> roots (that is right away in the root structures) and the addresses in the
>>> relocation table.
>>> The cost on stdc++.gch/O2g.gch (previously 85MB large) is about 3% file size
>>> growth, there are 2.5 million pointers that need relocation in the gch blob
>>> and the relocation table uses uleb128 for address deltas and needs ~1.01 bytes
>>> for one address that needs relocation, and about 20% compile time during
>>> PCH save (I think it is mainly because of the need to qsort those 2.5
>>> million pointers).  On PCH restore, if it doesn't need relocation (the usual
>>> case), it is just an extra fread of sizeof (size_t) data and fseek
>>> (in my tests real time on vanilla tree for #include <bits/stdc++.h> CU
>>> was ~0.175s and with the patch but no relocation ~0.173s), while if it needs
>>> relocation it took ~0.193s, i.e. 11.5% slower.
>> I'll note that without PCH that
>> #include <bits/stdc++.h>
>> int i;
>> testcase compiles with -O2 -g in ~1.199s, i.e. 6.2 times slower than PCH with
>> relocation and 6.9 times than PCH without relocation.
> I’ve run tests across the Darwin range, including old and new m32 hosts, and this
> seems to be working well.
>
> The attached patch should be applied before (or merged with) the change for
> relocation when it is applied - since the operation of the PCH hooks needs some
> adjustment on Darwin.
>
> thanks for working on this!
I think as the Darwin maintainer, you can just commit this once Jakub 
commits his bits.

jeff
  
Jakub Jelinek Dec. 9, 2021, 2:59 p.m. UTC | #5
On Wed, Dec 08, 2021 at 08:00:03AM +0000, Iain Sandoe wrote:
> > On 7 Dec 2021, at 14:50, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> The attached patch should be applied before (or merged with) the change for
> relocation when it is applied - since the operation of the PCH hooks needs some
> adjustment on Darwin.

Oops, didn't do this change and therefore likely broke Darwin and apparently
HP-UX.
Went through other targets and they don't do this reading in there and so
aren't problematic.  Of course, as I said before, to enable relocation
support one has to do minor changes to the hook not to fail on those but
update the reference parameter.

I've committed following which should hopefully unbreak it (untested),
please go ahead with your patch without the last hunk incrementally when
you're ready.

2021-12-09  Jakub Jelinek  <jakub@redhat.com>

	PR pch/71934
	* config/host-darwin.c (darwin_gt_pch_use_address): When reading
	manually the file into mapped area, update mapped_addr as
	an automatic variable rather than addr which is a reference parameter.
	* config/host-hpux.c (hpux_gt_pch_use_address): When reading
	manually the file into mapped area, update addr as
	an automatic variable rather than base which is a reference parameter.

--- gcc/config/host-darwin.c.jj	2021-12-09 15:40:06.232022601 +0100
+++ gcc/config/host-darwin.c	2021-12-09 15:48:51.397467287 +0100
@@ -185,10 +185,10 @@ darwin_gt_pch_use_address (void *&addr,
     {
       ssize_t nbytes;
 
-      nbytes = read (fd, addr, MIN (sz, (size_t) -1 >> 1));
+      nbytes = read (fd, mapped_addr, MIN (sz, (size_t) -1 >> 1));
       if (nbytes <= 0)
 	return -1;
-      addr = (char *) addr + nbytes;
+      mapped_addr = (char *) mapped_addr + nbytes;
       sz -= nbytes;
     }
 
--- gcc/config/host-hpux.c.jj	2021-12-09 15:40:06.251022328 +0100
+++ gcc/config/host-hpux.c	2021-12-09 15:49:25.464977378 +0100
@@ -115,10 +115,10 @@ hpux_gt_pch_use_address (void *&base, si
     {
       ssize_t nbytes;
 
-      nbytes = read (fd, base, MIN (size, SSIZE_MAX));
+      nbytes = read (fd, addr, MIN (size, SSIZE_MAX));
       if (nbytes <= 0)
         return -1;
-      base = (char *) base + nbytes;
+      addr = (char *) addr + nbytes;
       size -= nbytes;
     }
 


	Jakub
  
Iain Sandoe Dec. 9, 2021, 3:03 p.m. UTC | #6
> On 9 Dec 2021, at 14:59, Jakub Jelinek <jakub@redhat.com> wrote:
> 
> On Wed, Dec 08, 2021 at 08:00:03AM +0000, Iain Sandoe wrote:
>>> On 7 Dec 2021, at 14:50, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>> The attached patch should be applied before (or merged with) the change for
>> relocation when it is applied - since the operation of the PCH hooks needs some
>> adjustment on Darwin.
> 
> Oops, didn't do this change and therefore likely broke Darwin and apparently
> HP-UX.
> Went through other targets and they don't do this reading in there and so
> aren't problematic.  Of course, as I said before, to enable relocation
> support one has to do minor changes to the hook not to fail on those but
> update the reference parameter.
> 
> I've committed following which should hopefully unbreak it (untested),
> please go ahead with your patch without the last hunk incrementally when
> you're ready.

I was just retesting my patch on top of master - will merge the two.
thanks
Iain
> 
> 2021-12-09  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR pch/71934
> 	* config/host-darwin.c (darwin_gt_pch_use_address): When reading
> 	manually the file into mapped area, update mapped_addr as
> 	an automatic variable rather than addr which is a reference parameter.
> 	* config/host-hpux.c (hpux_gt_pch_use_address): When reading
> 	manually the file into mapped area, update addr as
> 	an automatic variable rather than base which is a reference parameter.
> 
> --- gcc/config/host-darwin.c.jj	2021-12-09 15:40:06.232022601 +0100
> +++ gcc/config/host-darwin.c	2021-12-09 15:48:51.397467287 +0100
> @@ -185,10 +185,10 @@ darwin_gt_pch_use_address (void *&addr,
>     {
>       ssize_t nbytes;
> 
> -      nbytes = read (fd, addr, MIN (sz, (size_t) -1 >> 1));
> +      nbytes = read (fd, mapped_addr, MIN (sz, (size_t) -1 >> 1));
>       if (nbytes <= 0)
> 	return -1;
> -      addr = (char *) addr + nbytes;
> +      mapped_addr = (char *) mapped_addr + nbytes;
>       sz -= nbytes;
>     }
> 
> --- gcc/config/host-hpux.c.jj	2021-12-09 15:40:06.251022328 +0100
> +++ gcc/config/host-hpux.c	2021-12-09 15:49:25.464977378 +0100
> @@ -115,10 +115,10 @@ hpux_gt_pch_use_address (void *&base, si
>     {
>       ssize_t nbytes;
> 
> -      nbytes = read (fd, base, MIN (size, SSIZE_MAX));
> +      nbytes = read (fd, addr, MIN (size, SSIZE_MAX));
>       if (nbytes <= 0)
>         return -1;
> -      base = (char *) base + nbytes;
> +      addr = (char *) addr + nbytes;
>       size -= nbytes;
>     }
> 
> 
> 
> 	Jakub
>
  
Christophe Lyon Dec. 9, 2021, 4:42 p.m. UTC | #7
Hi Jakub,


On Thu, Dec 9, 2021 at 4:00 PM Jakub Jelinek via Gcc-patches <
gcc-patches@gcc.gnu.org> wrote:

> On Wed, Dec 08, 2021 at 08:00:03AM +0000, Iain Sandoe wrote:
> > > On 7 Dec 2021, at 14:50, Jakub Jelinek via Gcc-patches <
> gcc-patches@gcc.gnu.org> wrote:
> > The attached patch should be applied before (or merged with) the change
> for
> > relocation when it is applied - since the operation of the PCH hooks
> needs some
> > adjustment on Darwin.
>
> Oops, didn't do this change and therefore likely broke Darwin and
> apparently
> HP-UX.
>

This also broke aarch64 I think:
In file included from
/tmp/6140018_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:3920:0:
./gt-aarch64-sve-builtins.h: In function 'void
gt_pch_p_19registered_function(void*, void*, gt_pointer_operator, void*)':
./gt-aarch64-sve-builtins.h:86:44: error: no matching function for call to
'gt_pch_nx(aarch64_sve::function_instance*, void (*&)(void*, void*, void*),
void*&)'
     gt_pch_nx (&((*x).instance), op, cookie);

Can you check?

Thanks

Christophe



> Went through other targets and they don't do this reading in there and so
> aren't problematic.  Of course, as I said before, to enable relocation
> support one has to do minor changes to the hook not to fail on those but
> update the reference parameter.
>
> I've committed following which should hopefully unbreak it (untested),
> please go ahead with your patch without the last hunk incrementally when
> you're ready.
>
> 2021-12-09  Jakub Jelinek  <jakub@redhat.com>
>
>         PR pch/71934
>         * config/host-darwin.c (darwin_gt_pch_use_address): When reading
>         manually the file into mapped area, update mapped_addr as
>         an automatic variable rather than addr which is a reference
> parameter.
>         * config/host-hpux.c (hpux_gt_pch_use_address): When reading
>         manually the file into mapped area, update addr as
>         an automatic variable rather than base which is a reference
> parameter.
>
> --- gcc/config/host-darwin.c.jj 2021-12-09 15:40:06.232022601 +0100
> +++ gcc/config/host-darwin.c    2021-12-09 15:48:51.397467287 +0100
> @@ -185,10 +185,10 @@ darwin_gt_pch_use_address (void *&addr,
>      {
>        ssize_t nbytes;
>
> -      nbytes = read (fd, addr, MIN (sz, (size_t) -1 >> 1));
> +      nbytes = read (fd, mapped_addr, MIN (sz, (size_t) -1 >> 1));
>        if (nbytes <= 0)
>         return -1;
> -      addr = (char *) addr + nbytes;
> +      mapped_addr = (char *) mapped_addr + nbytes;
>        sz -= nbytes;
>      }
>
> --- gcc/config/host-hpux.c.jj   2021-12-09 15:40:06.251022328 +0100
> +++ gcc/config/host-hpux.c      2021-12-09 15:49:25.464977378 +0100
> @@ -115,10 +115,10 @@ hpux_gt_pch_use_address (void *&base, si
>      {
>        ssize_t nbytes;
>
> -      nbytes = read (fd, base, MIN (size, SSIZE_MAX));
> +      nbytes = read (fd, addr, MIN (size, SSIZE_MAX));
>        if (nbytes <= 0)
>          return -1;
> -      base = (char *) base + nbytes;
> +      addr = (char *) addr + nbytes;
>        size -= nbytes;
>      }
>
>
>
>         Jakub
>
>
  
Jeff Law Dec. 9, 2021, 4:52 p.m. UTC | #8
On 12/9/2021 9:42 AM, Christophe Lyon via Gcc-patches wrote:
> Hi Jakub,
>
>
> On Thu, Dec 9, 2021 at 4:00 PM Jakub Jelinek via Gcc-patches <
> gcc-patches@gcc.gnu.org> wrote:
>
>> On Wed, Dec 08, 2021 at 08:00:03AM +0000, Iain Sandoe wrote:
>>>> On 7 Dec 2021, at 14:50, Jakub Jelinek via Gcc-patches <
>> gcc-patches@gcc.gnu.org> wrote:
>>> The attached patch should be applied before (or merged with) the change
>> for
>>> relocation when it is applied - since the operation of the PCH hooks
>> needs some
>>> adjustment on Darwin.
>> Oops, didn't do this change and therefore likely broke Darwin and
>> apparently
>> HP-UX.
>>
> This also broke aarch64 I think:
> In file included from
> /tmp/6140018_6.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/config/aarch64/aarch64-sve-builtins.cc:3920:0:
> ./gt-aarch64-sve-builtins.h: In function 'void
> gt_pch_p_19registered_function(void*, void*, gt_pointer_operator, void*)':
> ./gt-aarch64-sve-builtins.h:86:44: error: no matching function for call to
> 'gt_pch_nx(aarch64_sve::function_instance*, void (*&)(void*, void*, void*),
> void*&)'
>       gt_pch_nx (&((*x).instance), op, cookie);
I saw similar failures for my latest aarch64 build.

Jakub, if you need an aarch64 system let me know, I've still got AWS 
credits we can use.

jeff
  
Eric Gallager Dec. 10, 2021, 1:20 a.m. UTC | #9
On Wed, Dec 8, 2021 at 6:10 PM Jeff Law via Gcc-patches
<gcc-patches@gcc.gnu.org> wrote:
>
>
>
> On 12/7/2021 2:55 AM, Jakub Jelinek wrote:
> > Hi!
> >
> > The following patch adds support for relocation of the PCH blob on PCH
> > restore if we don't manage to get the preferred map slot for it.
> > The GTY stuff knows where all the pointers are, after all it relocates
> > it once during PCH save from the addresses where it was initially allocated
> > to addresses in the preferred map slot.
> > But, if we were to do it solely using GTY info upon PCH restore, we'd need
> > another set of GTY functions, which I think would make it less maintainable
> > and I think it would also be more costly at PCH restore time.  Those
> > functions would need to call something to add bias to pointers that haven't
> > been marked yet and make sure not to add bias to any pointer twice.
> >
> > So, this patch instead builds a relocation table (sorted list of addresses
> > in the blob which needs relocation) at PCH save time, stores it in a very
> > compact form into the gch file and upon restore, adjusts pointers in GTY
> > roots (that is right away in the root structures) and the addresses in the
> > relocation table.
> > The cost on stdc++.gch/O2g.gch (previously 85MB large) is about 3% file size
> > growth, there are 2.5 million pointers that need relocation in the gch blob
> > and the relocation table uses uleb128 for address deltas and needs ~1.01 bytes
> > for one address that needs relocation, and about 20% compile time during
> > PCH save (I think it is mainly because of the need to qsort those 2.5
> > million pointers).  On PCH restore, if it doesn't need relocation (the usual
> > case), it is just an extra fread of sizeof (size_t) data and fseek
> > (in my tests real time on vanilla tree for #include <bits/stdc++.h> CU
> > was ~0.175s and with the patch but no relocation ~0.173s), while if it needs
> > relocation it took ~0.193s, i.e. 11.5% slower.
> >
> > The discovery of the pointers in the blob that need relocation is done
> > in the relocate_ptrs hook which does the pointer relocation during PCH save.
> > Unfortunately, I had to make one change to the gengtype stuff due to the
> > nested_ptr feature of GTY, which some libcpp headers and stringpool.c use.
> > The relocate_ptrs hook had 2 arguments, pointer to the pointer and a cookie.
> > When relocate_ptrs is done, in most cases it is called solely on the
> > subfields of the current object, so e.g.
> >            if ((void *)(x) == this_obj)
> >              op (&((*x).u.fld[0].rt_rtx), cookie);
> > so relocate_ptrs can assert that ptr_p is within the
> > state->ptrs[state->ptrs_i]->obj ..
> > state->ptrs[state->ptrs_i]->obj+state->ptrs[state->ptrs_i]->size-sizeof(void*)
> > range and compute from that the address in the blob which will need
> > relocation (state->ptrs[state->ptrs_i]->new_addr is the new address
> > given to it and ptr_p-state->ptrs[state->ptrs_i]->obj is the relative
> > offset.  Unfortunately, for nested_ptr gengtype emits something like:
> >        {
> >          union tree_node * x0 =
> >            ((*x).val.node.node) ? HT_IDENT_TO_GCC_IDENT (HT_NODE (((*x).val.node.node))) : NULL;
> >          if ((void *)(x) == this_obj)
> >            op (&(x0), cookie);
> >          (*x).val.node.node = (x0) ? CPP_HASHNODE (GCC_IDENT_TO_HT_IDENT ((x0))) : NULL;
> >        }
> > so relocate_ptrs is called with an address of some temporary variable and
> > so doesn't know where the pointer will finally be.
> > So, I've added another argument to relocate_ptrs (and to
> > gt_pointer_operator).  For the most common case I pass NULL as the new middle
> > argument to that function, first one remains pointer to the pointer that
> > needs adjustment and last the cookie.  The NULL seems to be cheap to compute
> > and short in the gt*.[ch] files and stands for ptr_p is an address within
> > the this_obj's range, remember its address.  For the nested_ptr case, the
> > new middle argument contains actual address of the pointer that might need
> > to be relocated, so instead of the above
> >            op (&(x0), &((*x).val.node.node), cookie);
> > in there.  And finally, e.g. for the reorder case I need a way to tell
> > restore_ptrs to ignore a particular address for the relocation purposes
> > and only treat it the old way.  I've used for that the case when
> > the first and second arguments are equal.
> >
> > In order to enable support for mapping PCH as fallback at different
> > addresses than the preferred ones, a small change is needed to the
> > host pch_use_address hooks.  One change I've done to all of them is
> > the change of the type of the first argument from void * to void *&,
> > such that the actual address can be told to the callers (or shall I
> > instead use void **?), but another change that still needs to be done
> > in them if they want the relocation is actually not fail if they couldn't
> > get a preferred address, but instead modify what the first argument
> > refers to.  I've done that only for host-linux.c and Iain is testing
> > similar change for host-darwin.c.  Didn't change hpux, netbsd, openbsd,
> > solaris, mingw32 or the fallbacks because I can't test those.
> >
> > Bootstrapped/regtested on x86_64-linux and i686-linux (both as is and with
> > incremental
> > --- gcc/config/host-linux.c.jj        2021-12-06 22:22:42.007777367 +0100
> > +++ gcc/config/host-linux.c   2021-12-07 00:21:53.052674040 +0100
> > @@ -191,6 +191,8 @@ linux_gt_pch_use_address (void *&base, s
> >     if (size == 0)
> >       return -1;
> >
> > +base = (char *) base + ((size + 8191) & (size_t) -4096);
> > +
> >     /* Try to map the file with MAP_PRIVATE.  */
> >     addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset);
> >
> > which forces all PCH restores to be relocated.  An earlier version of the
> > patch has been also regrest with base = (char *) base + 16384; in that spot,
> > so both relocation to a non-overlapping spot and to an overlapping spot have
> > been tested.
> >
> > 2021-12-07  Jakub Jelinek  <jakub@redhat.com>
> >
> >       PR pch/71934
> >       * coretypes.h (gt_pointer_operator): Use 3 pointer arguments instead
> >       of two.
> >       * gengtype.c (struct walk_type_data): Add in_nested_ptr argument.
> >       (walk_type): Temporarily set d->in_nested_ptr around nested_ptr
> >       handling.
> >       (write_types_local_user_process_field): Pass a new middle pointer
> >       to gt_pointer_operator op calls, if d->in_nested_ptr pass there
> >       address of d->prev_val[2], otherwise NULL.
> >       (write_types_local_process_field): Likewise.
> >       * ggc-common.c (relocate_ptrs): Add real_ptr_p argument.  If equal
> >       to ptr_p, do nothing, otherwise if NULL remember ptr_p's
> >       or if non-NULL real_ptr_p's corresponding new address in
> >       reloc_addrs_vec.
> >       (reloc_addrs_vec): New variable.
> >       (compare_ptr, read_uleb128, write_uleb128): New functions.
> >       (gt_pch_save): When iterating over objects through relocate_ptrs,
> >       save current i into state.ptrs_i.  Sort reloc_addrs_vec and emit
> >       it as uleb128 of differences between pointer addresses into the
> >       PCH file.
> >       (gt_pch_restore): Allow restoring of PCH to a different address
> >       than the preferred one, in that case adjust global pointers by bias
> >       and also adjust by bias addresses read from the relocation table
> >       as uleb128 differences.  Otherwise fseek over it.  Perform
> >       gt_pch_restore_stringpool only after adjusting callbacks and for
> >       callback adjustments also take into account the bias.
> >       (default_gt_pch_use_address): Change type of first argument from
> >       void * to void *&.
> >       (mmap_gt_pch_use_address): Likewise.
> >       * ggc-tests.c (gt_pch_nx): Pass NULL as new middle argument to op.
> >       * hash-map.h (hash_map::pch_nx_helper): Likewise.
> >       (gt_pch_nx): Likewise.
> >       * hash-set.h (gt_pch_nx): Likewise.
> >       * hash-table.h (gt_pch_nx): Likewise.
> >       * hash-traits.h (ggc_remove::pch_nx): Likewise.
> >       * hosthooks-def.h (default_gt_pch_use_address): Change type of first
> >       argument from void * to void *&.
> >       (mmap_gt_pch_use_address): Likewise.
> >       * hosthooks.h (struct host_hooks): Change type of first argument of
> >       gt_pch_use_address hook from void * to void *&.
> >       * machmode.h (gt_pch_nx): Expect a callback with 3 pointers instead of
> >       two in the middle argument.
> >       * poly-int.h (gt_pch_nx): Likewise.
> >       * stringpool.c (gt_pch_nx): Pass NULL as new middle argument to op.
> >       * tree-cfg.c (gt_pch_nx): Likewise, except for LOCATION_BLOCK pass
> >       the same &(block) twice.
> >       * value-range.h (gt_pch_nx): Pass NULL as new middle argument to op.
> >       * vec.h (gt_pch_nx): Likewise.
> >       * wide-int.h (gt_pch_nx): Likewise.
> >       * config/host-darwin.c (darwin_gt_pch_use_address): Change type of
> >       first argument from void * to void *&.
> >       * config/host-darwin.h (darwin_gt_pch_use_address): Likewise.
> >       * config/host-hpux.c (hpux_gt_pch_use_address): Likewise.
> >       * config/host-linux.c (linux_gt_pch_use_address): Likewise.  If
> >       it couldn't succeed to mmap at the preferred location, set base
> >       to the actual one.  Update addr in the manual reading loop instead of
> >       base.
> >       * config/host-netbsd.c (netbsd_gt_pch_use_address): Change type of
> >       first argument from void * to void *&.
> >       * config/host-openbsd.c (openbsd_gt_pch_use_address): Likewise.
> >       * config/host-solaris.c (sol_gt_pch_use_address): Likewise.
> >       * config/i386/host-mingw32.c (mingw32_gt_pch_use_address): Likewise.
> >       * config/rs6000/rs6000-gen-builtins.c (write_init_file): Pass NULL
> >       as new middle argument to op in the generated code.
> >       * doc/gty.texi: Adjust samples for the addition of middle pointer
> >       to gt_pointer_operator callback.
> > gcc/ada/
> >       * gcc-interface/decl.c (gt_pch_nx): Pass NULL as new middle argument
> >       to op.
> > gcc/c-family/
> >       * c-pch.c (c_common_no_more_pch): Pass a temporary void * var
> >       with NULL value instead of NULL to host_hooks.gt_pch_use_address.
> > gcc/c/
> >       * c-decl.c (resort_field_decl_cmp): Pass the same pointer twice
> >       to resort_data.new_value.
> > gcc/cp/
> >       * module.cc (nop): Add another void * argument.
> >       * name-lookup.c (resort_member_name_cmp): Pass the same pointer twice
> >       to resort_data.new_value.
> Like the prior patch in this space, you know this better than anyone, so
> if you're comfortable, I think you should commit.
>
> I wonder if this is sufficient for the Ruby team to re-enable GCC PCH
> support.  IIRC the whole problem was we couldn't deal with PIE & PCH and
> I think this fixes that problem, right?  If so, you might want to reach
> out to them.
>
> Jeff

Having a note in changes.html would be helpful to point to for those purposes.

Eric
  

Patch

--- gcc/config/host-linux.c.jj	2021-12-06 22:22:42.007777367 +0100
+++ gcc/config/host-linux.c	2021-12-07 00:21:53.052674040 +0100
@@ -191,6 +191,8 @@  linux_gt_pch_use_address (void *&base, s
   if (size == 0)
     return -1;
 
+base = (char *) base + ((size + 8191) & (size_t) -4096);
+
   /* Try to map the file with MAP_PRIVATE.  */
   addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset);
 
which forces all PCH restores to be relocated.  An earlier version of the
patch has been also regrest with base = (char *) base + 16384; in that spot,
so both relocation to a non-overlapping spot and to an overlapping spot have
been tested.

2021-12-07  Jakub Jelinek  <jakub@redhat.com>

	PR pch/71934
	* coretypes.h (gt_pointer_operator): Use 3 pointer arguments instead
	of two.
	* gengtype.c (struct walk_type_data): Add in_nested_ptr argument.
	(walk_type): Temporarily set d->in_nested_ptr around nested_ptr
	handling.
	(write_types_local_user_process_field): Pass a new middle pointer
	to gt_pointer_operator op calls, if d->in_nested_ptr pass there
	address of d->prev_val[2], otherwise NULL.
	(write_types_local_process_field): Likewise.
	* ggc-common.c (relocate_ptrs): Add real_ptr_p argument.  If equal
	to ptr_p, do nothing, otherwise if NULL remember ptr_p's
	or if non-NULL real_ptr_p's corresponding new address in
	reloc_addrs_vec.
	(reloc_addrs_vec): New variable.
	(compare_ptr, read_uleb128, write_uleb128): New functions.
	(gt_pch_save): When iterating over objects through relocate_ptrs,
	save current i into state.ptrs_i.  Sort reloc_addrs_vec and emit
	it as uleb128 of differences between pointer addresses into the
	PCH file.
	(gt_pch_restore): Allow restoring of PCH to a different address
	than the preferred one, in that case adjust global pointers by bias
	and also adjust by bias addresses read from the relocation table
	as uleb128 differences.  Otherwise fseek over it.  Perform
	gt_pch_restore_stringpool only after adjusting callbacks and for
	callback adjustments also take into account the bias.
	(default_gt_pch_use_address): Change type of first argument from
	void * to void *&.
	(mmap_gt_pch_use_address): Likewise.
	* ggc-tests.c (gt_pch_nx): Pass NULL as new middle argument to op.
	* hash-map.h (hash_map::pch_nx_helper): Likewise.
	(gt_pch_nx): Likewise.
	* hash-set.h (gt_pch_nx): Likewise.
	* hash-table.h (gt_pch_nx): Likewise.
	* hash-traits.h (ggc_remove::pch_nx): Likewise.
	* hosthooks-def.h (default_gt_pch_use_address): Change type of first
	argument from void * to void *&.
	(mmap_gt_pch_use_address): Likewise.
	* hosthooks.h (struct host_hooks): Change type of first argument of
	gt_pch_use_address hook from void * to void *&.
	* machmode.h (gt_pch_nx): Expect a callback with 3 pointers instead of
	two in the middle argument.
	* poly-int.h (gt_pch_nx): Likewise.
	* stringpool.c (gt_pch_nx): Pass NULL as new middle argument to op.
	* tree-cfg.c (gt_pch_nx): Likewise, except for LOCATION_BLOCK pass
	the same &(block) twice.
	* value-range.h (gt_pch_nx): Pass NULL as new middle argument to op.
	* vec.h (gt_pch_nx): Likewise.
	* wide-int.h (gt_pch_nx): Likewise.
	* config/host-darwin.c (darwin_gt_pch_use_address): Change type of
	first argument from void * to void *&.
	* config/host-darwin.h (darwin_gt_pch_use_address): Likewise.
	* config/host-hpux.c (hpux_gt_pch_use_address): Likewise.
	* config/host-linux.c (linux_gt_pch_use_address): Likewise.  If
	it couldn't succeed to mmap at the preferred location, set base
	to the actual one.  Update addr in the manual reading loop instead of
	base.
	* config/host-netbsd.c (netbsd_gt_pch_use_address): Change type of
	first argument from void * to void *&.
	* config/host-openbsd.c (openbsd_gt_pch_use_address): Likewise.
	* config/host-solaris.c (sol_gt_pch_use_address): Likewise.
	* config/i386/host-mingw32.c (mingw32_gt_pch_use_address): Likewise.
	* config/rs6000/rs6000-gen-builtins.c (write_init_file): Pass NULL
	as new middle argument to op in the generated code.
	* doc/gty.texi: Adjust samples for the addition of middle pointer
	to gt_pointer_operator callback.
gcc/ada/
	* gcc-interface/decl.c (gt_pch_nx): Pass NULL as new middle argument
	to op.
gcc/c-family/
	* c-pch.c (c_common_no_more_pch): Pass a temporary void * var
	with NULL value instead of NULL to host_hooks.gt_pch_use_address.
gcc/c/
	* c-decl.c (resort_field_decl_cmp): Pass the same pointer twice
	to resort_data.new_value.
gcc/cp/
	* module.cc (nop): Add another void * argument.
	* name-lookup.c (resort_member_name_cmp): Pass the same pointer twice
	to resort_data.new_value.

--- gcc/coretypes.h.jj	2021-09-08 09:55:28.802721647 +0200
+++ gcc/coretypes.h	2021-12-04 12:02:14.863270812 +0100
@@ -442,8 +442,10 @@  enum optimize_size_level
 };
 
 /* Support for user-provided GGC and PCH markers.  The first parameter
-   is a pointer to a pointer, the second a cookie.  */
-typedef void (*gt_pointer_operator) (void *, void *);
+   is a pointer to a pointer, the second either NULL if the pointer to
+   pointer points into a GC object or the actual pointer address if
+   the first argument points to a temporary and the third a cookie.  */
+typedef void (*gt_pointer_operator) (void *, void *, void *);
 
 #if !defined (HAVE_UCHAR)
 typedef unsigned char uchar;
--- gcc/gengtype.c.jj	2021-12-03 11:03:10.418504519 +0100
+++ gcc/gengtype.c	2021-12-04 12:23:47.746851329 +0100
@@ -2491,6 +2491,7 @@  struct walk_type_data
   int loopcounter;
   bool in_ptr_field;
   bool have_this_obj;
+  bool in_nested_ptr;
 };
 
 
@@ -2807,6 +2808,7 @@  walk_type (type_p t, struct walk_type_da
 	    if (nested_ptr_d)
 	      {
 		const char *oldprevval2 = d->prev_val[2];
+		bool old_in_nested_ptr = d->in_nested_ptr;
 
 		if (!union_or_struct_p (nested_ptr_d->type))
 		  {
@@ -2817,6 +2819,7 @@  walk_type (type_p t, struct walk_type_da
 		  }
 
 		d->prev_val[2] = d->val;
+		d->in_nested_ptr = true;
 		oprintf (d->of, "%*s{\n", d->indent, "");
 		d->indent += 2;
 		d->val = xasprintf ("x%d", d->counter++);
@@ -2846,6 +2849,7 @@  walk_type (type_p t, struct walk_type_da
 		oprintf (d->of, "%*s}\n", d->indent, "");
 		d->val = d->prev_val[2];
 		d->prev_val[2] = oldprevval2;
+		d->in_nested_ptr = old_in_nested_ptr;
 	      }
 	    else
 	      d->process_field (t->u.p, d);
@@ -3828,12 +3832,17 @@  write_types_local_user_process_field (ty
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
     case TYPE_STRING:
-      oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+      if (d->in_nested_ptr)
+	oprintf (d->of, "%*s  op (&(%s), &(%s), cookie);\n",
+		 d->indent, "", d->val, d->prev_val[2]);
+      oprintf (d->of, "%*s  op (&(%s), NULL, cookie);\n",
+	       d->indent, "", d->val);
       break;
 
     case TYPE_USER_STRUCT:
       if (d->in_ptr_field)
-	oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+	oprintf (d->of, "%*s  op (&(%s), NULL, cookie);\n",
+		 d->indent, "", d->val);
       else
 	oprintf (d->of, "%*s  gt_pch_nx (&(%s), op, cookie);\n",
 		 d->indent, "", d->val);
@@ -3911,14 +3920,20 @@  write_types_local_process_field (type_p
     case TYPE_STRING:
       oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
 	       d->prev_val[3]);
-      oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+      if (d->in_nested_ptr)
+	oprintf (d->of, "%*s  op (&(%s), &(%s), cookie);\n",
+		 d->indent, "", d->val, d->prev_val[2]);
+      else
+	oprintf (d->of, "%*s  op (&(%s), NULL, cookie);\n",
+		 d->indent, "", d->val);
       break;
 
     case TYPE_USER_STRUCT:
       oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "",
 	       d->prev_val[3]);
       if (d->in_ptr_field)
-	oprintf (d->of, "%*s  op (&(%s), cookie);\n", d->indent, "", d->val);
+	oprintf (d->of, "%*s  op (&(%s), NULL, cookie);\n",
+		 d->indent, "", d->val);
       else
 	oprintf (d->of, "%*s  gt_pch_nx (&(%s), op, cookie);\n",
 		 d->indent, "", d->val);
--- gcc/ggc-common.c.jj	2021-12-03 21:16:24.086933993 +0100
+++ gcc/ggc-common.c	2021-12-06 09:00:35.990354744 +0100
@@ -40,7 +40,7 @@  static ggc_statistics *ggc_stats;
 struct traversal_state;
 
 static int compare_ptr_data (const void *, const void *);
-static void relocate_ptrs (void *, void *);
+static void relocate_ptrs (void *, void *, void *);
 static void write_pch_globals (const struct ggc_root_tab * const *tab,
 			       struct traversal_state *state);
 
@@ -247,6 +247,7 @@  saving_hasher::equal (const ptr_data *p1
 
 static hash_table<saving_hasher> *saving_htab;
 static vec<void *> callback_vec;
+static vec<void *> reloc_addrs_vec;
 
 /* Register an object in the hash table.  */
 
@@ -363,10 +364,10 @@  compare_ptr_data (const void *p1_p, cons
 /* Callbacks for note_ptr_fn.  */
 
 static void
-relocate_ptrs (void *ptr_p, void *state_p)
+relocate_ptrs (void *ptr_p, void *real_ptr_p, void *state_p)
 {
   void **ptr = (void **)ptr_p;
-  struct traversal_state *state ATTRIBUTE_UNUSED
+  struct traversal_state *state
     = (struct traversal_state *)state_p;
   struct ptr_data *result;
 
@@ -377,6 +378,19 @@  relocate_ptrs (void *ptr_p, void *state_
     saving_htab->find_with_hash (*ptr, POINTER_HASH (*ptr));
   gcc_assert (result);
   *ptr = result->new_addr;
+  if (ptr_p == real_ptr_p)
+    return;
+  if (real_ptr_p == NULL)
+    real_ptr_p = ptr_p;
+  gcc_assert (real_ptr_p >= state->ptrs[state->ptrs_i]->obj
+	      && ((char *) real_ptr_p + sizeof (void *)
+		  <= ((char *) state->ptrs[state->ptrs_i]->obj
+		      + state->ptrs[state->ptrs_i]->size)));
+  void *addr
+    = (void *) ((char *) state->ptrs[state->ptrs_i]->new_addr
+		+ ((char *) real_ptr_p
+		   - (char *) state->ptrs[state->ptrs_i]->obj));
+  reloc_addrs_vec.safe_push (addr);
 }
 
 /* Write out, after relocation, the pointers in TAB.  */
@@ -411,6 +425,61 @@  write_pch_globals (const struct ggc_root
 	}
 }
 
+/* Callback for qsort.  */
+
+static int
+compare_ptr (const void *p1_p, const void *p2_p)
+{
+  void *p1 = *(void *const *)p1_p;
+  void *p2 = *(void *const *)p2_p;
+  return (((uintptr_t)p1 > (uintptr_t)p2)
+	  - ((uintptr_t)p1 < (uintptr_t)p2));
+}
+
+/* Decode one uleb128 from P, return first byte after it, store
+   decoded value into *VAL.  */
+
+static unsigned char *
+read_uleb128 (unsigned char *p, size_t *val)
+{
+  unsigned int shift = 0;
+  unsigned char byte;
+  size_t result;
+
+  result = 0;
+  do
+    {
+      byte = *p++;
+      result |= ((size_t) byte & 0x7f) << shift;
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  *val = result;
+  return p;
+}
+
+/* Store VAL as uleb128 at P, return length in bytes.  */
+
+static size_t
+write_uleb128 (unsigned char *p, size_t val)
+{
+  size_t len = 0;
+  do
+    {
+      unsigned char byte = (val & 0x7f);
+      val >>= 7;
+      if (val != 0)
+	/* More bytes to follow.  */
+	byte |= 0x80;
+
+      *p++ = byte;
+      ++len;
+    }
+  while (val != 0);
+  return len;
+}
+
 /* Hold the information we need to mmap the file back in.  */
 
 struct mmap_info
@@ -511,6 +580,7 @@  gt_pch_save (FILE *f)
   /* Actually write out the objects.  */
   for (i = 0; i < state.count; i++)
     {
+      state.ptrs_i = i;
       if (this_object_size < state.ptrs[i]->size)
 	{
 	  this_object_size = state.ptrs[i]->size;
@@ -591,7 +661,42 @@  gt_pch_save (FILE *f)
   vbits.release ();
 #endif
 
+  reloc_addrs_vec.qsort (compare_ptr);
+
+  size_t reloc_addrs_size = 0;
+  void *last_addr = NULL;
+  unsigned char uleb128_buf[sizeof (size_t) * 2];
+  for (void *addr : reloc_addrs_vec)
+    {
+      gcc_assert ((uintptr_t) addr >= (uintptr_t) mmi.preferred_base
+		  && ((uintptr_t) addr + sizeof (void *)
+		      < (uintptr_t) mmi.preferred_base + mmi.size));
+      if (addr == last_addr)
+	continue;
+      if (last_addr == NULL)
+	last_addr = mmi.preferred_base;
+      size_t diff = (uintptr_t) addr - (uintptr_t) last_addr;
+      reloc_addrs_size += write_uleb128 (uleb128_buf, diff);
+      last_addr = addr;
+    }
+  if (fwrite (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1)
+    fatal_error (input_location, "cannot write PCH file: %m");
+  last_addr = NULL;
+  for (void *addr : reloc_addrs_vec)
+    {
+      if (addr == last_addr)
+	continue;
+      if (last_addr == NULL)
+	last_addr = mmi.preferred_base;
+      size_t diff = (uintptr_t) addr - (uintptr_t) last_addr;
+      reloc_addrs_size = write_uleb128 (uleb128_buf, diff);
+      if (fwrite (uleb128_buf, 1, reloc_addrs_size, f) != reloc_addrs_size)
+	fatal_error (input_location, "cannot write PCH file: %m");
+      last_addr = addr;
+    }
+
   ggc_pch_finish (state.d, state.f);
+
   gt_pch_fixup_stringpool ();
 
   unsigned num_callbacks = callback_vec.length ();
@@ -608,6 +713,7 @@  gt_pch_save (FILE *f)
   delete saving_htab;
   saving_htab = NULL;
   callback_vec.release ();
+  reloc_addrs_vec.release ();
 }
 
 /* Read the state of the compiler back in from F.  */
@@ -660,6 +766,7 @@  gt_pch_restore (FILE *f)
   if (fread (&mmi, sizeof (mmi), 1, f) != 1)
     fatal_error (input_location, "cannot read PCH file: %m");
 
+  void *orig_preferred_base = mmi.preferred_base;
   result = host_hooks.gt_pch_use_address (mmi.preferred_base, mmi.size,
 					  fileno (f), mmi.offset);
 
@@ -667,7 +774,7 @@  gt_pch_restore (FILE *f)
      address needed.  */
   if (result < 0)
     {
-      sorry_at (input_location, "PCH relocation is not yet supported");
+      sorry_at (input_location, "PCH allocation failure");
       /* There is no point in continuing from here, we will only end up
 	 with a crashed (most likely hanging) compiler.  */
       exit (-1);
@@ -685,9 +792,75 @@  gt_pch_restore (FILE *f)
   else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
     fatal_error (input_location, "cannot read PCH file: %m");
 
-  ggc_pch_read (f, mmi.preferred_base);
+  size_t reloc_addrs_size;
+  if (fread (&reloc_addrs_size, sizeof (reloc_addrs_size), 1, f) != 1)
+    fatal_error (input_location, "cannot read PCH file: %m");
 
-  gt_pch_restore_stringpool ();
+  if (orig_preferred_base != mmi.preferred_base)
+    {
+      uintptr_t bias
+	= (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base;
+
+      /* Adjust all the global pointers by bias.  */
+      line_table = new_line_table;
+      for (rt = gt_ggc_rtab; *rt; rt++)
+	for (rti = *rt; rti->base != NULL; rti++)
+      for (i = 0; i < rti->nelt; i++)
+	{
+	  char *addr = (char *)rti->base + rti->stride * i;
+	  char *p;
+	  memcpy (&p, addr, sizeof (void *));
+	  if ((uintptr_t) p >= (uintptr_t) orig_preferred_base
+	      && (uintptr_t) p < (uintptr_t) orig_preferred_base + mmi.size)
+	    {
+	      p = (char *) ((uintptr_t) p + bias);
+	      memcpy (addr, &p, sizeof (void *));
+	    }
+	}
+      new_line_table = line_table;
+      line_table = save_line_table;
+
+      /* And adjust all the pointers in the image by bias too.  */
+      char *addr = (char *) mmi.preferred_base;
+      unsigned char uleb128_buf[4096], *uleb128_ptr = uleb128_buf;
+      while (reloc_addrs_size != 0)
+	{
+	  size_t this_size
+	    = MIN (reloc_addrs_size,
+		   (size_t) (4096 - (uleb128_ptr - uleb128_buf)));
+	  if (fread (uleb128_ptr, 1, this_size, f) != this_size)
+	    fatal_error (input_location, "cannot read PCH file: %m");
+	  unsigned char *uleb128_end = uleb128_ptr + this_size;
+	  if (this_size != reloc_addrs_size)
+	    uleb128_end -= 2 * sizeof (size_t);
+	  uleb128_ptr = uleb128_buf;
+	  while (uleb128_ptr < uleb128_end)
+	    {
+	      size_t diff;
+	      uleb128_ptr = read_uleb128 (uleb128_ptr, &diff);
+	      addr = (char *) ((uintptr_t) addr + diff);
+
+	      char *p;
+	      memcpy (&p, addr, sizeof (void *));
+	      gcc_assert ((uintptr_t) p >= (uintptr_t) orig_preferred_base
+			  && ((uintptr_t) p
+			      < (uintptr_t) orig_preferred_base + mmi.size));
+	      p = (char *) ((uintptr_t) p + bias);
+	      memcpy (addr, &p, sizeof (void *));
+	    }
+	  reloc_addrs_size -= this_size;
+	  if (reloc_addrs_size == 0)
+	    break;
+	  this_size = uleb128_end + 2 * sizeof (size_t) - uleb128_ptr;
+	  memcpy (uleb128_buf, uleb128_ptr, this_size);
+	  uleb128_ptr = uleb128_buf + this_size;
+	}
+    }
+  else if (fseek (f, (mmi.offset + mmi.size + sizeof (reloc_addrs_size)
+		      + reloc_addrs_size), SEEK_SET) != 0)
+    fatal_error (input_location, "cannot read PCH file: %m");
+
+  ggc_pch_read (f, mmi.preferred_base);
 
   void (*pch_save) (FILE *);
   unsigned num_callbacks;
@@ -696,23 +869,28 @@  gt_pch_restore (FILE *f)
     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;
+      uintptr_t binbias = (uintptr_t) &gt_pch_save - (uintptr_t) pch_save;
       void **ptrs = XNEWVEC (void *, num_callbacks);
       unsigned i;
+      uintptr_t bias
+	= (uintptr_t) mmi.preferred_base - (uintptr_t) orig_preferred_base;
 
       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));
+	  void *ptr = (void *) ((uintptr_t) ptrs[i] + bias);
+	  memcpy (&pch_save, ptr, sizeof (pch_save));
+	  pch_save = (void (*) (FILE *)) ((uintptr_t) pch_save + binbias);
+	  memcpy (ptr, &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");
 
+  gt_pch_restore_stringpool ();
+
   /* Barring corruption of the PCH file, the restored line table should be
      complete and usable.  */
   line_table = new_line_table;
@@ -736,7 +914,7 @@  default_gt_pch_get_address (size_t size
    of the PCH file would be required.  */
 
 int
-default_gt_pch_use_address (void *base, size_t size, int fd ATTRIBUTE_UNUSED,
+default_gt_pch_use_address (void *&base, size_t size, int fd ATTRIBUTE_UNUSED,
 			    size_t offset ATTRIBUTE_UNUSED)
 {
   void *addr = xmalloc (size);
@@ -782,7 +960,7 @@  mmap_gt_pch_get_address (size_t size, in
    mapped with something.  */
 
 int
-mmap_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
+mmap_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
 {
   void *addr;
 
--- gcc/ggc-tests.c.jj	2021-08-19 11:42:27.366422386 +0200
+++ gcc/ggc-tests.c	2021-12-04 12:03:37.772089692 +0100
@@ -415,7 +415,7 @@  gt_pch_nx (user_struct *p)
 static void
 gt_pch_nx (user_struct *p, gt_pointer_operator op, void *cookie)
 {
-  op (&(p->m_ptr), cookie);
+  op (&(p->m_ptr), NULL, cookie);
 }
 
 /* Verify that GTY((user)) works.  */
--- gcc/hash-map.h.jj	2021-05-28 11:03:19.648882063 +0200
+++ gcc/hash-map.h	2021-12-04 12:04:11.714606150 +0100
@@ -111,7 +111,7 @@  class GTY((user)) hash_map
       static void
       pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie)
 	{
-	  op (&x, cookie);
+	  op (&x, NULL, cookie);
 	}
 
     /* The overloads below should match those in ggc.h.  */
@@ -334,7 +334,7 @@  template<typename K, typename V, typenam
 static inline void
 gt_pch_nx (hash_map<K, V, H> *h, gt_pointer_operator op, void *cookie)
 {
-  op (&h->m_table.m_entries, cookie);
+  op (&h->m_table.m_entries, NULL, cookie);
 }
 
 enum hm_alloc { hm_heap = false, hm_ggc = true };
--- gcc/hash-set.h.jj	2021-01-04 10:25:37.493248997 +0100
+++ gcc/hash-set.h	2021-12-04 12:22:07.893274054 +0100
@@ -206,7 +206,7 @@  template<typename K, typename H>
 static inline void
 gt_pch_nx (hash_set<K, false, H> *h, gt_pointer_operator op, void *cookie)
 {
-  op (&h->m_table.m_entries, cookie);
+  op (&h->m_table.m_entries, NULL, cookie);
 }
 
 #endif
--- gcc/hash-table.h.jj	2021-09-17 18:15:02.481515580 +0200
+++ gcc/hash-table.h	2021-12-04 12:04:32.555309248 +0100
@@ -1206,7 +1206,7 @@  template<typename D>
 static inline void
 gt_pch_nx (hash_table<D> *h, gt_pointer_operator op, void *cookie)
 {
-  op (&h->m_entries, cookie);
+  op (&h->m_entries, NULL, cookie);
 }
 
 template<typename H>
--- gcc/hash-traits.h.jj	2021-01-04 10:25:37.560248239 +0100
+++ gcc/hash-traits.h	2021-12-04 12:04:49.983060976 +0100
@@ -254,7 +254,7 @@  struct ggc_remove
   static void
   pch_nx (T &p, gt_pointer_operator op, void *cookie)
   {
-    op (&p, cookie);
+    op (&p, NULL, cookie);
   }
 };
 
--- gcc/hosthooks-def.h.jj	2021-12-03 21:16:24.134933307 +0100
+++ gcc/hosthooks-def.h	2021-12-04 11:59:34.875550004 +0100
@@ -35,10 +35,10 @@  along with GCC; see the file COPYING3.
   default_gt_pch_alloc_granularity
 
 extern void* default_gt_pch_get_address (size_t, int);
-extern int default_gt_pch_use_address (void *, size_t, int, size_t);
+extern int default_gt_pch_use_address (void *&, size_t, int, size_t);
 extern size_t default_gt_pch_alloc_granularity (void);
 extern void* mmap_gt_pch_get_address (size_t, int);
-extern int mmap_gt_pch_use_address (void *, size_t, int, size_t);
+extern int mmap_gt_pch_use_address (void *&, size_t, int, size_t);
 
 /* The structure is defined in hosthooks.h.  */
 #define HOST_HOOKS_INITIALIZER {		\
--- gcc/hosthooks.h.jj	2021-12-03 21:16:24.134933307 +0100
+++ gcc/hosthooks.h	2021-12-04 11:59:34.875550004 +0100
@@ -30,10 +30,12 @@  struct host_hooks
   void * (*gt_pch_get_address) (size_t size, int fd);
 
   /* ADDR is an address returned by gt_pch_get_address.  Attempt to allocate
-     SIZE bytes at the same address and load it with the data from FD at
-     OFFSET.  Return -1 if we couldn't allocate memory at ADDR, return 0
-     if the memory is allocated but the data not loaded, return 1 if done.  */
-  int (*gt_pch_use_address) (void *addr, size_t size, int fd, size_t offset);
+     SIZE bytes at the same address (preferrably) or some other address
+     and load it with the data from FD at OFFSET.  Return -1 if we couldn't
+     allocate memory, otherwise update ADDR to the actual address where it got
+     allocated, return 0 if the memory is allocated but the data not loaded,
+     return 1 if done.  */
+  int (*gt_pch_use_address) (void *&addr, size_t size, int fd, size_t offset);
 
   /*  Return the alignment required for allocating virtual memory. Usually
       this is the same as pagesize.  */
--- gcc/machmode.h.jj	2021-01-04 10:25:39.930221403 +0100
+++ gcc/machmode.h	2021-12-04 12:35:22.309955863 +0100
@@ -1199,7 +1199,7 @@  gt_pch_nx (pod_mode<T> *)
 
 template<typename T>
 void
-gt_pch_nx (pod_mode<T> *, void (*) (void *, void *), void *)
+gt_pch_nx (pod_mode<T> *, void (*) (void *, void *, void *), void *)
 {
 }
 
--- gcc/poly-int.h.jj	2021-10-04 10:16:10.910139834 +0200
+++ gcc/poly-int.h	2021-12-04 12:31:30.195262302 +0100
@@ -2717,7 +2717,7 @@  gt_pch_nx (poly_int_pod<N, C> *)
 
 template<unsigned int N, typename C>
 void
-gt_pch_nx (poly_int_pod<N, C> *, void (*) (void *, void *), void *)
+gt_pch_nx (poly_int_pod<N, C> *, void (*) (void *, void *, void *), void *)
 {
 }
 
--- gcc/stringpool.c.jj	2021-09-28 11:34:10.336410112 +0200
+++ gcc/stringpool.c	2021-12-04 12:05:12.637738232 +0100
@@ -225,7 +225,7 @@  gt_pch_nx (unsigned char& x ATTRIBUTE_UN
 void
 gt_pch_nx (unsigned char *x, gt_pointer_operator op, void *cookie)
 {
-  op (x, cookie);
+  op (x, NULL, cookie);
 }
 
 /* Handle saving and restoring the string pool for PCH.  */
--- gcc/tree-cfg.c.jj	2021-11-29 10:10:50.900744821 +0100
+++ gcc/tree-cfg.c	2021-12-04 12:26:21.072666725 +0100
@@ -9946,13 +9946,13 @@  void
 gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
 {
   tree block = LOCATION_BLOCK (e->goto_locus);
-  op (&(e->src), cookie);
-  op (&(e->dest), cookie);
+  op (&(e->src), NULL, cookie);
+  op (&(e->dest), NULL, cookie);
   if (current_ir_type () == IR_GIMPLE)
-    op (&(e->insns.g), cookie);
+    op (&(e->insns.g), NULL, cookie);
   else
-    op (&(e->insns.r), cookie);
-  op (&(block), cookie);
+    op (&(e->insns.r), NULL, cookie);
+  op (&(block), &(block), cookie);
 }
 
 #if CHECKING_P
--- gcc/value-range.h.jj	2021-10-09 10:07:51.937704203 +0200
+++ gcc/value-range.h	2021-12-04 12:07:10.362061126 +0100
@@ -365,8 +365,8 @@  gt_pch_nx (irange *x, gt_pointer_operato
 {
   for (unsigned i = 0; i < x->m_num_ranges; ++i)
     {
-      op (&x->m_base[i * 2], cookie);
-      op (&x->m_base[i * 2 + 1], cookie);
+      op (&x->m_base[i * 2], NULL, cookie);
+      op (&x->m_base[i * 2 + 1], NULL, cookie);
     }
 }
 
--- gcc/vec.h.jj	2021-08-09 11:37:10.982942511 +0200
+++ gcc/vec.h	2021-12-04 12:07:31.373761795 +0100
@@ -1388,7 +1388,7 @@  void
 gt_pch_nx (vec<T *, A, vl_embed> *v, gt_pointer_operator op, void *cookie)
 {
   for (unsigned i = 0; i < v->length (); i++)
-    op (&((*v)[i]), cookie);
+    op (&((*v)[i]), NULL, cookie);
 }
 
 template<typename T, typename A>
--- gcc/wide-int.h.jj	2021-01-04 10:25:37.195252373 +0100
+++ gcc/wide-int.h	2021-12-04 12:21:39.782674577 +0100
@@ -3338,7 +3338,7 @@  gt_pch_nx (generic_wide_int <T> *)
 
 template<typename T>
 void
-gt_pch_nx (generic_wide_int <T> *, void (*) (void *, void *), void *)
+gt_pch_nx (generic_wide_int <T> *, void (*) (void *, void *, void *), void *)
 {
 }
 
@@ -3356,7 +3356,7 @@  gt_pch_nx (trailing_wide_ints <N> *)
 
 template<int N>
 void
-gt_pch_nx (trailing_wide_ints <N> *, void (*) (void *, void *), void *)
+gt_pch_nx (trailing_wide_ints <N> *, void (*) (void *, void *, void *), void *)
 {
 }
 
--- gcc/config/host-darwin.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/config/host-darwin.c	2021-12-04 11:59:34.787551258 +0100
@@ -136,7 +136,7 @@  darwin_gt_pch_get_address (size_t sz, in
    fail with -1.  */
 
 int
-darwin_gt_pch_use_address (void *addr, size_t sz, int fd, size_t off)
+darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off)
 {
   void *mapped_addr;
 
--- gcc/config/host-darwin.h.jj	2021-01-04 10:25:41.023209026 +0100
+++ gcc/config/host-darwin.h	2021-12-05 16:43:18.375820579 +0100
@@ -18,7 +18,7 @@ 
    <http://www.gnu.org/licenses/>.  */
 
 extern void * darwin_gt_pch_get_address (size_t sz, int fd);
-extern int darwin_gt_pch_use_address (void *addr, size_t sz, int fd, 
+extern int darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, 
 				      size_t off);
 
 #undef HOST_HOOKS_GT_PCH_GET_ADDRESS
--- gcc/config/host-hpux.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/config/host-hpux.c	2021-12-04 11:59:34.833550603 +0100
@@ -24,7 +24,7 @@ 
 #include "hosthooks-def.h"
 
 static void *hpux_gt_pch_get_address (size_t, int);
-static int hpux_gt_pch_use_address (void *, size_t, int, size_t);
+static int hpux_gt_pch_use_address (void *&, size_t, int, size_t);
 
 #undef HOST_HOOKS_GT_PCH_GET_ADDRESS
 #define HOST_HOOKS_GT_PCH_GET_ADDRESS hpux_gt_pch_get_address
@@ -78,7 +78,7 @@  hpux_gt_pch_get_address (size_t size, in
    little else we can do given the current PCH implementation.  */
 
 static int
-hpux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
+hpux_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
 {
   void *addr;
 
--- gcc/config/host-linux.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/config/host-linux.c	2021-12-06 10:20:08.832333389 +0100
@@ -181,7 +181,7 @@  linux_gt_pch_get_address (size_t size, i
    little else we can do given the current PCH implementation.  */
 
 static int
-linux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
+linux_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
 {
   void *addr;
 
@@ -204,24 +204,22 @@  linux_gt_pch_use_address (void *base, si
   addr = mmap (base, size, PROT_READ | PROT_WRITE,
 	       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 
-  if (addr != base)
-    {
-      if (addr != (void *) MAP_FAILED)
-        munmap (addr, size);
-      return -1;
-    }
+  if (addr == (void *) MAP_FAILED)
+    return -1;
 
   if (lseek (fd, offset, SEEK_SET) == (off_t)-1)
     return -1;
 
+  base = addr;
+
   while (size)
     {
       ssize_t nbytes;
 
-      nbytes = read (fd, base, MIN (size, (size_t)-1 >> 1));
+      nbytes = read (fd, addr, MIN (size, (size_t)-1 >> 1));
       if (nbytes <= 0)
         return -1;
-      base = (char *) base + nbytes;
+      addr = (char *) addr + nbytes;
       size -= nbytes;
     }
 
--- gcc/config/host-netbsd.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/config/host-netbsd.c	2021-12-04 11:59:34.862550190 +0100
@@ -66,7 +66,7 @@  netbsd_gt_pch_get_address (size_t size,
    mapping the data at BASE, -1 if we couldn't.  */
 
 static int
-netbsd_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
+netbsd_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
 {
   void *addr;
 
--- gcc/config/host-openbsd.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/config/host-openbsd.c	2021-12-04 11:59:34.845550432 +0100
@@ -66,7 +66,7 @@  openbsd_gt_pch_get_address (size_t size,
    mapping the data at BASE, -1 if we couldn't.  */
 
 static int
-openbsd_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
+openbsd_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
 {
   void *addr;
 
--- gcc/config/host-solaris.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/config/host-solaris.c	2021-12-04 11:59:34.853550318 +0100
@@ -105,7 +105,7 @@  sol_gt_pch_get_address (size_t size, int
    mapping the data at BASE, -1 if we couldn't.  */
 
 static int
-sol_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
+sol_gt_pch_use_address (void *&base, size_t size, int fd, size_t offset)
 {
   void *addr;
 
--- gcc/config/i386/host-mingw32.c.jj	2021-12-03 21:16:24.086933993 +0100
+++ gcc/config/i386/host-mingw32.c	2021-12-04 11:59:34.830550645 +0100
@@ -32,7 +32,7 @@ 
 #include <stdlib.h>
 
 static void * mingw32_gt_pch_get_address (size_t, int);
-static int mingw32_gt_pch_use_address (void *, size_t, int, size_t);
+static int mingw32_gt_pch_use_address (void *&, size_t, int, size_t);
 static size_t mingw32_gt_pch_alloc_granularity (void);
 
 #undef HOST_HOOKS_GT_PCH_GET_ADDRESS
@@ -118,7 +118,7 @@  mingw32_gt_pch_get_address (size_t size,
    if the memory is allocated but the data not loaded, return 1 if done.  */
 
 static int
-mingw32_gt_pch_use_address (void *addr, size_t size, int fd,
+mingw32_gt_pch_use_address (void *&addr, size_t size, int fd,
 			    size_t offset)
 {
   void * mmap_addr;
--- gcc/config/rs6000/rs6000-gen-builtins.c.jj	2021-12-02 19:41:52.572553592 +0100
+++ gcc/config/rs6000/rs6000-gen-builtins.c	2021-12-04 12:09:00.538491547 +0100
@@ -2886,7 +2886,7 @@  write_init_file (void)
 	   "void gt_pch_nx (bifdata *bd, gt_pointer_operator op, "
 	   "void *cookie)\n");
   fprintf (init_file,
-	   "{\n  op(&(bd->fntype), cookie);\n}\n\n");
+	   "{\n  op(&(bd->fntype), NULL, cookie);\n}\n\n");
   fprintf (init_file,
 	   "void gt_ggc_mx (ovlddata *od)\n");
   fprintf (init_file,
@@ -2899,7 +2899,7 @@  write_init_file (void)
 	   "void gt_pch_nx (ovlddata *od, gt_pointer_operator op, "
 	   "void *cookie)\n");
   fprintf (init_file,
-	   "{\n  op(&(od->fntype), cookie);\n}\n");
+	   "{\n  op(&(od->fntype), NULL, cookie);\n}\n");
 
   return 1;
 }
--- gcc/doc/gty.texi.jj	2021-12-03 11:03:10.437504245 +0100
+++ gcc/doc/gty.texi	2021-12-06 09:40:05.291516818 +0100
@@ -483,7 +483,7 @@  void gt_pch_nx (my_struct *p)
 void gt_pch_nx (my_struct *p, gt_pointer_operator op, void *cookie)
 @{
   /* For every field 'fld', call the given pointer operator.  */
-  op (&(tp->fld), cookie);
+  op (&(tp->fld), NULL, cookie);
 @}
 @end smallexample
 
@@ -536,7 +536,7 @@  void gt_pch_nx (TP<T *> *tp, gt_pointer_
 @{
   /* For every field 'fld' of 'tp' with type 'T *', call the given
      pointer operator.  */
-  op (&(tp->fld), cookie);
+  op (&(tp->fld), NULL, cookie);
 @}
 
 template<typename T>
--- gcc/c-family/c-pch.c.jj	2021-12-03 21:16:23.992935336 +0100
+++ gcc/c-family/c-pch.c	2021-12-04 11:59:34.875550004 +0100
@@ -375,7 +375,8 @@  c_common_no_more_pch (void)
   if (cpp_get_callbacks (parse_in)->valid_pch)
     {
       cpp_get_callbacks (parse_in)->valid_pch = NULL;
-      host_hooks.gt_pch_use_address (NULL, 0, -1, 0);
+      void *addr = NULL;
+      host_hooks.gt_pch_use_address (addr, 0, -1, 0);
     }
 }
 
--- gcc/c/c-decl.c.jj	2021-11-18 12:33:22.011628227 +0100
+++ gcc/c/c-decl.c	2021-12-04 12:25:28.201420039 +0100
@@ -9040,8 +9040,8 @@  resort_field_decl_cmp (const void *x_p,
   {
     tree d1 = DECL_NAME (*x);
     tree d2 = DECL_NAME (*y);
-    resort_data.new_value (&d1, resort_data.cookie);
-    resort_data.new_value (&d2, resort_data.cookie);
+    resort_data.new_value (&d1, &d1, resort_data.cookie);
+    resort_data.new_value (&d2, &d2, resort_data.cookie);
     if (d1 < d2)
       return -1;
   }
--- gcc/cp/module.cc.jj	2021-09-09 10:40:26.080175894 +0200
+++ gcc/cp/module.cc	2021-12-04 12:37:24.106221104 +0100
@@ -11750,7 +11750,7 @@  trees_out::mark_class_def (tree defn)
 /* Nop sorting, needed for resorting the member vec.  */
 
 static void
-nop (void *, void *)
+nop (void *, void *, void *)
 {
 }
 
--- gcc/cp/name-lookup.c.jj	2021-11-24 09:54:11.476739292 +0100
+++ gcc/cp/name-lookup.c	2021-12-04 12:26:02.434932278 +0100
@@ -2123,8 +2123,8 @@  resort_member_name_cmp (const void *a_p,
   tree name_a = OVL_NAME (a);
   tree name_b = OVL_NAME (b);
 
-  resort_data.new_value (&name_a, resort_data.cookie);
-  resort_data.new_value (&name_b, resort_data.cookie);
+  resort_data.new_value (&name_a, &name_a, resort_data.cookie);
+  resort_data.new_value (&name_b, &name_b, resort_data.cookie);
 
   gcc_checking_assert (name_a != name_b);
 
--- gcc/ada/gcc-interface/decl.c.jj	2021-12-02 19:41:52.347556798 +0100
+++ gcc/ada/gcc-interface/decl.c	2021-12-05 16:42:46.745270951 +0100
@@ -171,7 +171,7 @@  gt_pch_nx (Entity_Id &)
 void
 gt_pch_nx (Entity_Id *x, gt_pointer_operator op, void *cookie)
 {
-  op (x, cookie);
+  op (x, NULL, cookie);
 }
 
 struct dummy_type_hasher : ggc_cache_ptr_hash<tree_entity_vec_map>