[v3] x86-64: Estimate output section layout before sizing dynamic sections

Message ID CAMe9rOqCyAzTwLC2n8Gq2WpR5KWG9X_setbrKi19az0wGt9JDA@mail.gmail.com
State New
Headers
Series [v3] x86-64: Estimate output section layout before sizing dynamic sections |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

H.J. Lu Feb. 4, 2025, 5:19 a.m. UTC
  When sizing dynamic sections, elf_x86_64_scan_relocs converts GOTPCREL
relocations to R_X86_64_PC32, R_X86_64_32S or R_X86_64_32 for local
symbols.  But at that time, since the output section layout is unknown,
the local symbol values can't be determined.  Later linker issues an
error if the converted relocation overflows when resolving relocations
against these local symbols.  Update the x86-64 ELF linker to estimate
output section layout before sizing dynamic sections and use the
preliminary output section layout info to skip the GOTPCREL relocation
conversion if the converted relocation overflows.

bfd/

PR ld/32591
* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Add an input
section argument.  Use the lowest-addressed section to estimate
the __ehdr_start symbol value.  Don't convert relocation if the
converted relocation will overflow.

ld/

PR ld/32591
* emultempl/elf-x86.em (elf_x86_64_before_allocation):
New.  Defined for x86-64.
(LDEMUL_BEFORE_ALLOCATION): Likewise.
* testsuite/ld-x86-64/pr19609-2a.d: Don't fail.
* testsuite/ld-x86-64/pr19609-2b.d: Likewise.
* testsuite/ld-x86-64/pr19609-4a.d: Likewise.
* testsuite/ld-x86-64/pr19609-5d.d: Likewise.
* testsuite/ld-x86-64/pr19609-7a.d: Likewise.
* testsuite/ld-x86-64/pr19609-7c.d: Likewise.
* testsuite/ld-x86-64/pr32591-1.s: New file.
* testsuite/ld-x86-64/pr32591-1a-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-1a.d: Likewise.
* testsuite/ld-x86-64/pr32591-1a.t: Likewise.
* testsuite/ld-x86-64/pr32591-1b-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-1b.d: Likewise.
* testsuite/ld-x86-64/pr32591-1b.t: Likewise.
* testsuite/ld-x86-64/pr32591-1c-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-1c.d: Likewise.
* testsuite/ld-x86-64/pr32591-1c.t: Likewise.
* testsuite/ld-x86-64/pr32591-1d-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-1d.d: Likewise.
* testsuite/ld-x86-64/pr32591-1d.t: Likewise.
* testsuite/ld-x86-64/pr32591-2.s: Likewise.
* testsuite/ld-x86-64/pr32591-2-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-2.d: Likewise.
* testsuite/ld-x86-64/pr32591-2.t: Likewise.
* testsuite/ld-x86-64/pr32591-3.s: Likewise.
* testsuite/ld-x86-64/pr32591-3-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-3.d: Likewise.
* testsuite/ld-x86-64/pr32591-3.t: Likewise.
* testsuite/ld-x86-64/pr32591-4.s: Likewise.
* testsuite/ld-x86-64/pr32591-4-x32.d: Likewise.
* testsuite/ld-x86-64/pr32591-4.d: Likewise.
* testsuite/ld-x86-64/x86-64.exp: Run PR ld/32591 tests.
  

Comments

H.J. Lu Feb. 6, 2025, 10:01 p.m. UTC | #1
On Tue, Feb 4, 2025 at 1:19 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> When sizing dynamic sections, elf_x86_64_scan_relocs converts GOTPCREL
> relocations to R_X86_64_PC32, R_X86_64_32S or R_X86_64_32 for local
> symbols.  But at that time, since the output section layout is unknown,
> the local symbol values can't be determined.  Later linker issues an
> error if the converted relocation overflows when resolving relocations
> against these local symbols.  Update the x86-64 ELF linker to estimate
> output section layout before sizing dynamic sections and use the
> preliminary output section layout info to skip the GOTPCREL relocation
> conversion if the converted relocation overflows.
>
> bfd/
>
> PR ld/32591
> * elf64-x86-64.c (elf_x86_64_convert_load_reloc): Add an input
> section argument.  Use the lowest-addressed section to estimate
> the __ehdr_start symbol value.  Don't convert relocation if the
> converted relocation will overflow.
>
> ld/
>
> PR ld/32591
> * emultempl/elf-x86.em (elf_x86_64_before_allocation):
> New.  Defined for x86-64.
> (LDEMUL_BEFORE_ALLOCATION): Likewise.
> * testsuite/ld-x86-64/pr19609-2a.d: Don't fail.
> * testsuite/ld-x86-64/pr19609-2b.d: Likewise.
> * testsuite/ld-x86-64/pr19609-4a.d: Likewise.
> * testsuite/ld-x86-64/pr19609-5d.d: Likewise.
> * testsuite/ld-x86-64/pr19609-7a.d: Likewise.
> * testsuite/ld-x86-64/pr19609-7c.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1.s: New file.
> * testsuite/ld-x86-64/pr32591-1a-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1a.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1a.t: Likewise.
> * testsuite/ld-x86-64/pr32591-1b-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1b.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1b.t: Likewise.
> * testsuite/ld-x86-64/pr32591-1c-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1c.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1c.t: Likewise.
> * testsuite/ld-x86-64/pr32591-1d-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1d.d: Likewise.
> * testsuite/ld-x86-64/pr32591-1d.t: Likewise.
> * testsuite/ld-x86-64/pr32591-2.s: Likewise.
> * testsuite/ld-x86-64/pr32591-2-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-2.d: Likewise.
> * testsuite/ld-x86-64/pr32591-2.t: Likewise.
> * testsuite/ld-x86-64/pr32591-3.s: Likewise.
> * testsuite/ld-x86-64/pr32591-3-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-3.d: Likewise.
> * testsuite/ld-x86-64/pr32591-3.t: Likewise.
> * testsuite/ld-x86-64/pr32591-4.s: Likewise.
> * testsuite/ld-x86-64/pr32591-4-x32.d: Likewise.
> * testsuite/ld-x86-64/pr32591-4.d: Likewise.
> * testsuite/ld-x86-64/x86-64.exp: Run PR ld/32591 tests.
>
> --
> H.J.

I am checking it in.
  

Patch

From aa88073d38aacbf1ad9f6759d27ec618fcb8e603 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 30 Jan 2025 08:48:45 +0800
Subject: [PATCH v3] x86-64: Estimate output section layout before sizing
 dynamic sections

When sizing dynamic sections, elf_x86_64_scan_relocs converts GOTPCREL
relocations to R_X86_64_PC32, R_X86_64_32S or R_X86_64_32 for local
symbols.  But at that time, since the output section layout is unknown,
the local symbol values can't be determined.  Later linker issues an
error if the converted relocation overflows when resolving relocations
against these local symbols.  Update the x86-64 ELF linker to estimate
output section layout before sizing dynamic sections and use the
preliminary output section layout info to skip the GOTPCREL relocation
conversion if the converted relocation overflows.

bfd/

	PR ld/32591
	* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Add an input
	section argument.  Use the lowest-addressed section to estimate
	the __ehdr_start symbol value.  Don't convert relocation if the
	converted relocation will overflow.

ld/

	PR ld/32591
	* emultempl/elf-x86.em (elf_x86_64_before_allocation):
	New.  Defined for x86-64.
	(LDEMUL_BEFORE_ALLOCATION): Likewise.
	* testsuite/ld-x86-64/pr19609-2a.d: Don't fail.
	* testsuite/ld-x86-64/pr19609-2b.d: Likewise.
	* testsuite/ld-x86-64/pr19609-4a.d: Likewise.
	* testsuite/ld-x86-64/pr19609-5d.d: Likewise.
	* testsuite/ld-x86-64/pr19609-7a.d: Likewise.
	* testsuite/ld-x86-64/pr19609-7c.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1.s: New file.
	* testsuite/ld-x86-64/pr32591-1a-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1a.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1a.t: Likewise.
	* testsuite/ld-x86-64/pr32591-1b-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1b.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1b.t: Likewise.
	* testsuite/ld-x86-64/pr32591-1c-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1c.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1c.t: Likewise.
	* testsuite/ld-x86-64/pr32591-1d-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1d.d: Likewise.
	* testsuite/ld-x86-64/pr32591-1d.t: Likewise.
	* testsuite/ld-x86-64/pr32591-2.s: Likewise.
	* testsuite/ld-x86-64/pr32591-2-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-2.d: Likewise.
	* testsuite/ld-x86-64/pr32591-2.t: Likewise.
	* testsuite/ld-x86-64/pr32591-3.s: Likewise.
	* testsuite/ld-x86-64/pr32591-3-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-3.d: Likewise.
	* testsuite/ld-x86-64/pr32591-3.t: Likewise.
	* testsuite/ld-x86-64/pr32591-4.s: Likewise.
	* testsuite/ld-x86-64/pr32591-4-x32.d: Likewise.
	* testsuite/ld-x86-64/pr32591-4.d: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/32591 tests.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 bfd/elf64-x86-64.c                      | 89 +++++++++++++++++++++++--
 ld/emultempl/elf-x86.em                 | 41 ++++++++++++
 ld/testsuite/ld-x86-64/pr19609-2a.d     | 11 ++-
 ld/testsuite/ld-x86-64/pr19609-2b.d     | 11 ++-
 ld/testsuite/ld-x86-64/pr19609-4a.d     | 11 ++-
 ld/testsuite/ld-x86-64/pr19609-5d.d     | 10 ++-
 ld/testsuite/ld-x86-64/pr19609-7a.d     | 13 +++-
 ld/testsuite/ld-x86-64/pr19609-7c.d     | 13 +++-
 ld/testsuite/ld-x86-64/pr32591-1.s      | 24 +++++++
 ld/testsuite/ld-x86-64/pr32591-1a-x32.d | 22 ++++++
 ld/testsuite/ld-x86-64/pr32591-1a.d     | 22 ++++++
 ld/testsuite/ld-x86-64/pr32591-1a.t     |  7 ++
 ld/testsuite/ld-x86-64/pr32591-1b-x32.d | 27 ++++++++
 ld/testsuite/ld-x86-64/pr32591-1b.d     | 27 ++++++++
 ld/testsuite/ld-x86-64/pr32591-1b.t     |  7 ++
 ld/testsuite/ld-x86-64/pr32591-1c-x32.d | 22 ++++++
 ld/testsuite/ld-x86-64/pr32591-1c.d     | 22 ++++++
 ld/testsuite/ld-x86-64/pr32591-1c.t     |  6 ++
 ld/testsuite/ld-x86-64/pr32591-1d-x32.d | 22 ++++++
 ld/testsuite/ld-x86-64/pr32591-1d.d     | 22 ++++++
 ld/testsuite/ld-x86-64/pr32591-1d.t     |  7 ++
 ld/testsuite/ld-x86-64/pr32591-2-x32.d  | 12 ++++
 ld/testsuite/ld-x86-64/pr32591-2.d      | 12 ++++
 ld/testsuite/ld-x86-64/pr32591-2.s      | 13 ++++
 ld/testsuite/ld-x86-64/pr32591-2.t      |  4 ++
 ld/testsuite/ld-x86-64/pr32591-3-x32.d  | 13 ++++
 ld/testsuite/ld-x86-64/pr32591-3.d      | 13 ++++
 ld/testsuite/ld-x86-64/pr32591-3.s      |  7 ++
 ld/testsuite/ld-x86-64/pr32591-3.t      |  5 ++
 ld/testsuite/ld-x86-64/pr32591-4-x32.d  | 13 ++++
 ld/testsuite/ld-x86-64/pr32591-4.d      | 13 ++++
 ld/testsuite/ld-x86-64/pr32591-4.s      |  7 ++
 ld/testsuite/ld-x86-64/x86-64.exp       | 14 ++++
 33 files changed, 548 insertions(+), 14 deletions(-)
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1.s
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1a-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1a.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1a.t
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1b-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1b.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1b.t
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1c-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1c.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1c.t
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1d-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1d.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-1d.t
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-2-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-2.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-2.s
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-2.t
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-3-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-3.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-3.s
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-3.t
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-4-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-4.d
 create mode 100644 ld/testsuite/ld-x86-64/pr32591-4.s

diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 61334c3ab04..cc493c5e0dc 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1770,6 +1770,7 @@  static unsigned int evex_move_r_to_b (unsigned int byte1)
 
 static bool
 elf_x86_64_convert_load_reloc (bfd *abfd,
+			       asection *input_section,
 			       bfd_byte *contents,
 			       unsigned int *r_type_p,
 			       Elf_Internal_Rela *irel,
@@ -1793,6 +1794,10 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
   unsigned int r_symndx;
   bfd_vma roff = irel->r_offset;
   bfd_vma abs_relocation;
+  reloc_howto_type *howto;
+  bfd_reloc_status_type r;
+  Elf_Internal_Sym *isym;
+  bfd_vma relocation;
 
   switch (r_type)
     {
@@ -1901,8 +1906,8 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
   /* Get the symbol referred to by the reloc.  */
   if (h == NULL)
     {
-      Elf_Internal_Sym *isym
-	= bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd, r_symndx);
+      isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache, abfd,
+				    r_symndx);
 
       /* Skip relocation against undefined symbols.  */
       if (isym->st_shndx == SHN_UNDEF)
@@ -1932,6 +1937,9 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
 	 R_X86_64_PC32.  */
       struct elf_x86_link_hash_entry *eh = elf_x86_hash_entry (h);
 
+      isym = NULL;
+      tsec = NULL;
+
       abs_symbol = ABS_SYMBOL_P (h);
       abs_relocation = h->root.u.def.value;
 
@@ -1991,6 +1999,22 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
 	      /* Skip since R_X86_64_32/R_X86_64_32S may overflow.  */
 	      if (no_overflow)
 		return true;
+	      if (h->start_stop)
+		tsec = h->root.u.def.section;
+	      else if (h == htab->elf.hehdr_start)
+		{
+		  /* Use the lowest-addressed section to estimate the
+		     __ehdr_start symbol value.  */
+		  asection *sec;
+		  tsec = NULL;
+		  for (sec = link_info->output_bfd->sections;
+		       sec != NULL;
+		       sec = sec->next)
+		    if ((sec->flags & SEC_LOAD) != 0
+			&& (tsec == NULL || tsec->vma > sec->vma))
+		      tsec = sec;
+
+		}
 	      goto convert;
 	    }
 	  tsec = h->root.u.def.section;
@@ -2009,6 +2033,25 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
     return true;
 
  convert:
+  /* Compute relocation value so that it can be used later to check for
+     overflow against the converted relocation.  */
+  if (h == NULL)
+    {
+      /* Make a copy of IREL so that _bfd_elf_rela_local_sym won't
+	 change IREL.  */
+      Elf_Internal_Rela rel = *irel;
+      relocation = _bfd_elf_rela_local_sym (link_info->output_bfd, isym,
+					    &tsec, &rel);
+      /* Use the updated r_addend.  */
+      raddend = rel.r_addend;
+    }
+  else if (tsec != NULL)
+    relocation = (h->root.u.def.value
+		  + tsec->output_section->vma
+		  + tsec->output_offset);
+  else
+    relocation = 0;
+
   if (opcode == 0xff)
     {
       /* We have "call/jmp *foo@GOTPCREL(%rip)".  */
@@ -2016,6 +2059,16 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
       unsigned int disp;
       bfd_vma nop_offset;
 
+      r_type = R_X86_64_PC32;
+
+      /* Skip if the converted relocation will overflow.  */
+      howto = elf_x86_64_rtype_to_howto (abfd, r_type);
+      r = _bfd_final_link_relocate (howto, abfd, input_section,
+				    contents, irel->r_offset,
+				    relocation, raddend);
+      if (r == bfd_reloc_overflow)
+	return true;
+
       /* Convert R_X86_64_GOTPCRELX and R_X86_64_REX_GOTPCRELX to
 	 R_X86_64_PC32.  */
       modrm = bfd_get_8 (abfd, contents + roff - 1);
@@ -2060,7 +2113,6 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
 	}
       bfd_put_8 (abfd, nop, contents + nop_offset);
       bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1);
-      r_type = R_X86_64_PC32;
     }
   else if (r_type == R_X86_64_CODE_6_GOTPCRELX && opcode != 0x8b)
     {
@@ -2101,6 +2153,14 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
 	 overflow when sign-extending imm32 to 64 bits.  */
       r_type = evex[1] & 0x80 ? R_X86_64_32S : R_X86_64_32;
 
+      /* Skip if the converted relocation will overflow.  */
+      howto = elf_x86_64_rtype_to_howto (abfd, r_type);
+      r = _bfd_final_link_relocate (howto, abfd, input_section,
+				    contents, irel->r_offset,
+				    relocation, 0);
+      if (r == bfd_reloc_overflow)
+	return true;
+
       if (abs_relocation) /* Bogus; should be abs_symbol.  */
 	{
 	  /* Check if R_X86_64_32S/R_X86_64_32 fits.  */
@@ -2186,6 +2246,15 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
 	      opcode = 0x8d;
 	      r_type = R_X86_64_PC32;
 
+	      /* Skip if the converted relocation will overflow.  */
+	      howto = elf_x86_64_rtype_to_howto (abfd, r_type);
+	      r = _bfd_final_link_relocate (howto, abfd, input_section,
+					    contents, irel->r_offset,
+					    relocation,
+					    raddend);
+	      if (r == bfd_reloc_overflow)
+		return true;
+
 	      /* For MOVRS move a possible REX prefix as necessary.  */
 	      if (movrs == 5)
 		bfd_put_8 (abfd, rex, contents + roff - 3);
@@ -2245,6 +2314,14 @@  elf_x86_64_convert_load_reloc (bfd *abfd,
 	  r_type = rex_w ? R_X86_64_32S : R_X86_64_32;
 
 	rewrite_modrm_rex:
+	  /* Skip if the converted relocation will overflow.  */
+	  howto = elf_x86_64_rtype_to_howto (abfd, r_type);
+	  r = _bfd_final_link_relocate (howto, abfd, input_section,
+					contents, irel->r_offset,
+					relocation, 0);
+	  if (r == bfd_reloc_overflow)
+	    return true;
+
 	  if (abs_relocation)
 	    {
 	      /* Check if R_X86_64_32S/R_X86_64_32 fits.  */
@@ -2465,9 +2542,9 @@  elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
 	  && (h == NULL || h->type != STT_GNU_IFUNC))
 	{
 	  Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel;
-	  if (!elf_x86_64_convert_load_reloc (abfd, contents, &r_type,
-					      irel, h, &converted_reloc,
-					      info))
+	  if (!elf_x86_64_convert_load_reloc (abfd, sec, contents,
+					      &r_type, irel, h,
+					      &converted_reloc, info))
 	    goto error_return;
 
 	  if (converted_reloc)
diff --git a/ld/emultempl/elf-x86.em b/ld/emultempl/elf-x86.em
index 8546923da23..f72a0cd0d4a 100644
--- a/ld/emultempl/elf-x86.em
+++ b/ld/emultempl/elf-x86.em
@@ -73,3 +73,44 @@  EOF
     LDEMUL_BEFORE_PARSE=elf_x86_64_before_parse
     ;;
 esac
+
+case x${OUTPUT_FORMAT} in
+  x*x86-64*)
+fragment <<EOF
+
+static void
+elf_x86_64_before_allocation (void)
+{
+  if (!bfd_link_relocatable (&link_info)
+      && is_elf_hash_table (link_info.hash)
+      && expld.phase != lang_mark_phase_enum)
+    {
+      struct elf_link_hash_table *htab = elf_hash_table (&link_info);
+      /* Run one_lang_size_sections_pass to estimate the output section
+	 layout before sizing dynamic sections.  */
+      expld.dataseg.phase = exp_seg_none;
+      expld.phase = lang_mark_phase_enum;
+      /* NB: Exclude linker created GOT setions when estimating output
+	 section layout as sizing dynamic sections may change linker
+	 created GOT sections.  */
+      if (htab->sgot != NULL)
+	htab->sgot->flags |= SEC_EXCLUDE;
+      if (htab->sgotplt != NULL)
+	htab->sgotplt->flags |= SEC_EXCLUDE;
+      one_lang_size_sections_pass (NULL, false);
+      /* Restore linker created GOT setions.  */
+      if (htab->sgot != NULL)
+	htab->sgot->flags &= ~SEC_EXCLUDE;
+      if (htab->sgotplt != NULL)
+	htab->sgotplt->flags &= ~SEC_EXCLUDE;
+      lang_reset_memory_regions ();
+    }
+
+  gld${EMULATION_NAME}_before_allocation ();
+}
+
+EOF
+
+LDEMUL_BEFORE_ALLOCATION=elf_x86_64_before_allocation
+    ;;
+esac
diff --git a/ld/testsuite/ld-x86-64/pr19609-2a.d b/ld/testsuite/ld-x86-64/pr19609-2a.d
index 6d3db92afb7..401d64affef 100644
--- a/ld/testsuite/ld-x86-64/pr19609-2a.d
+++ b/ld/testsuite/ld-x86-64/pr19609-2a.d
@@ -1,4 +1,13 @@ 
 #source: pr19609-2.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+70000000 <_start>:
+[ 	]*[a-f0-9]+:	48 3b 05 ([0-9a-f]{2} ){4}	cmp    -?0x[a-f0-9]+\(%rip\),%rax        # .*
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr19609-2b.d b/ld/testsuite/ld-x86-64/pr19609-2b.d
index 4fee93d7034..7e6e8cd3c91 100644
--- a/ld/testsuite/ld-x86-64/pr19609-2b.d
+++ b/ld/testsuite/ld-x86-64/pr19609-2b.d
@@ -1,4 +1,13 @@ 
 #source: pr19609-2.s
 #as: --x32 -mrelax-relocations=yes
 #ld: -melf32_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+70000000 <_start>:
+[ 	]*[a-f0-9]+:	48 3b 05 ([0-9a-f]{2} ){4}	cmp    -?0x[a-f0-9]+\(%rip\),%rax        # .*
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr19609-4a.d b/ld/testsuite/ld-x86-64/pr19609-4a.d
index eb37d0c8729..b6e41f5ee78 100644
--- a/ld/testsuite/ld-x86-64/pr19609-4a.d
+++ b/ld/testsuite/ld-x86-64/pr19609-4a.d
@@ -1,4 +1,13 @@ 
 #source: pr19609-4.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x70000000 -Tdata=0xa0000000
-#error: .*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*failed to convert GOTPCREL relocation against 'foo'; relink with --no-relax.*
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+70000000 <_start>:
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    [-]?0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <_start\+0x1000>
+[ 	]*[a-f0-9]+:	4c 8b 1d ([0-9a-f]{2} ){4} *	mov    [-]?0x[a-f0-9]+\(%rip\),%r11        # [a-f0-9]+ <_start\+0x1000>
diff --git a/ld/testsuite/ld-x86-64/pr19609-5d.d b/ld/testsuite/ld-x86-64/pr19609-5d.d
index 0ab28efff1e..0b011e0943e 100644
--- a/ld/testsuite/ld-x86-64/pr19609-5d.d
+++ b/ld/testsuite/ld-x86-64/pr19609-5d.d
@@ -1,4 +1,12 @@ 
 #source: pr19609-5.s
 #as: --64 -mrelax-relocations=yes
 #ld: -melf_x86_64 -Ttext=0x80000000
-#error: .*failed to convert GOTPCREL relocation against 'bar'; relink with --no-relax
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]+[a-f0-9]+:	ff 15 ([0-9a-f]{2} ){4} *	call   \*-?0x[a-f0-9]+\(%rip\)        # [a-f0-9]+ <.*>
diff --git a/ld/testsuite/ld-x86-64/pr19609-7a.d b/ld/testsuite/ld-x86-64/pr19609-7a.d
index 34704a94c16..f00f0b88de2 100644
--- a/ld/testsuite/ld-x86-64/pr19609-7a.d
+++ b/ld/testsuite/ld-x86-64/pr19609-7a.d
@@ -1,4 +1,13 @@ 
 #source: pr19609-7.s
 #as: --64 -mrelax-relocations=yes
-#ld: -melf_x86_64 -Ttext=0x80000000
-#error: .*failed to convert GOTPCREL relocation against 'foobar'; relink with --no-relax
+#ld: -melf_x86_64 -Ttext=0x80000000 -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]*[a-f0-9]+:	ff 15 ([0-9a-f]{2} ){4} *	call   \*-?0x[a-f0-9]+\(%rip\)        # [a-f0-9]+ <_start\+0x1000>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr19609-7c.d b/ld/testsuite/ld-x86-64/pr19609-7c.d
index 09488e22a8e..c1ee443dd30 100644
--- a/ld/testsuite/ld-x86-64/pr19609-7c.d
+++ b/ld/testsuite/ld-x86-64/pr19609-7c.d
@@ -1,4 +1,13 @@ 
 #source: pr19609-7.s
 #as: --x32 -mrelax-relocations=yes
-#ld: -melf32_x86_64 -Ttext=0x80000000
-#error: .*failed to convert GOTPCREL relocation against 'foobar'; relink with --no-relax
+#ld: -melf32_x86_64 -Ttext=0x80000000 -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ ]*[a-f0-9]+:	ff 15 ([0-9a-f]{2} ){4} *	call   \*-?0x[a-f0-9]+\(%rip\)        # [a-f0-9]+ <_start\+0x1000>
+#pass
diff --git a/ld/testsuite/ld-x86-64/pr32591-1.s b/ld/testsuite/ld-x86-64/pr32591-1.s
new file mode 100644
index 00000000000..853645646d2
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1.s
@@ -0,0 +1,24 @@ 
+.section .text.foo,"ax"
+.globl _foo
+.type _foo, @function
+_foo:
+  movl __start_data@GOTPCREL(%rip), %eax
+  addq foo_1@GOTPCREL(%rip), %rax
+  addq foo@GOTPCREL(%rip), %rax
+
+.section .text,"ax"
+.globl _start
+.type _start, @function
+_start:
+  movl __stop_data@GOTPCREL(%rip), %eax
+  movq __stop_data@GOTPCREL(%rip), %rax
+  movq __stop_data@GOTPCREL(%rip), %rax
+  movl __stop_data@GOTPCREL(%rip), %eax
+
+.section foo,"aw",@progbits
+.space 1
+foo_1:
+.space 1
+
+.section data,"aw",@progbits
+.space 13
diff --git a/ld/testsuite/ld-x86-64/pr32591-1a-x32.d b/ld/testsuite/ld-x86-64/pr32591-1a-x32.d
new file mode 100644
index 00000000000..693437317ea
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1a-x32.d
@@ -0,0 +1,22 @@ 
+#source: pr32591-1.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -T pr32591-1a.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+00100000 <_foo>:
+  100000:	c7 c0 00 00 20 80    	mov    \$0x80200000,%eax
+  100006:	48 03 05 f3 ff 1f 00 	add    0x1ffff3\(%rip\),%rax        # 300000 <_start\+0x100000>
+  10000d:	48 81 c0 ff ff ff 7f 	add    \$0x7fffffff,%rax
+
+Disassembly of section .text:
+
+00200000 <_start>:
+  200000:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
+  200006:	40 c7 c0 0d 00 20 80 	rex mov \$0x8020000d,%eax
+  20000d:	40 c7 c0 0d 00 20 80 	rex mov \$0x8020000d,%eax
+  200014:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1a.d b/ld/testsuite/ld-x86-64/pr32591-1a.d
new file mode 100644
index 00000000000..30637a75d08
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1a.d
@@ -0,0 +1,22 @@ 
+#source: pr32591-1.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -T pr32591-1a.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+0000000000100000 <_foo>:
+  100000:	c7 c0 00 00 20 80    	mov    \$0x80200000,%eax
+  100006:	48 03 05 f3 ff 1f 00 	add    0x1ffff3\(%rip\),%rax        # 300000 <_start\+0x100000>
+  10000d:	48 81 c0 ff ff ff 7f 	add    \$0x7fffffff,%rax
+
+Disassembly of section .text:
+
+0000000000200000 <_start>:
+  200000:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
+  200006:	48 8b 05 fb ff 0f 00 	mov    0xffffb\(%rip\),%rax        # 300008 <_start\+0x100008>
+  20000d:	48 8b 05 f4 ff 0f 00 	mov    0xffff4\(%rip\),%rax        # 300008 <_start\+0x100008>
+  200014:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1a.t b/ld/testsuite/ld-x86-64/pr32591-1a.t
new file mode 100644
index 00000000000..efe8a070143
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1a.t
@@ -0,0 +1,7 @@ 
+SECTIONS {
+  .text.foo 0x100000 : { *(.text.foo) }
+  .text 0x200000 : { *(.text) }
+  .got 0x300000 : { *(.got) }
+  foo 0x7fffffff : { *(foo) }
+  data 0x80200000 : { *(data) }
+}
diff --git a/ld/testsuite/ld-x86-64/pr32591-1b-x32.d b/ld/testsuite/ld-x86-64/pr32591-1b-x32.d
new file mode 100644
index 00000000000..0b98e87e84a
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1b-x32.d
@@ -0,0 +1,27 @@ 
+#source: pr32591-1.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -T pr32591-1b.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+00100000 <_foo>:
+  100000:	c7 c0 00 00 20 80    	mov    \$0x80200000,%eax
+  100006:	48 03 05 f3 ff 1f 00 	add    0x1ffff3\(%rip\),%rax        # 300000 <_start\+0x100000>
+  10000d:	48 81 c0 ff ff ff 7f 	add    \$0x7fffffff,%rax
+
+Disassembly of section .text:
+
+001ff000 <_start-0x1000>:
+  1ff000:	66 2e 0f 1f 84 00 00 00 00 00 	cs nopw 0x0\(%rax,%rax,1\)
+#...
+  1ffffa:	66 0f 1f 44 00 00    	nopw   0x0\(%rax,%rax,1\)
+
+00200000 <_start>:
+  200000:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
+  200006:	40 c7 c0 0d 00 20 80 	rex mov \$0x8020000d,%eax
+  20000d:	40 c7 c0 0d 00 20 80 	rex mov \$0x8020000d,%eax
+  200014:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1b.d b/ld/testsuite/ld-x86-64/pr32591-1b.d
new file mode 100644
index 00000000000..149f851a97e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1b.d
@@ -0,0 +1,27 @@ 
+#source: pr32591-1.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -T pr32591-1b.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+0000000000100000 <_foo>:
+  100000:	c7 c0 00 00 20 80    	mov    \$0x80200000,%eax
+  100006:	48 03 05 f3 ff 1f 00 	add    0x1ffff3\(%rip\),%rax        # 300000 <_start\+0x100000>
+  10000d:	48 81 c0 ff ff ff 7f 	add    \$0x7fffffff,%rax
+
+Disassembly of section .text:
+
+00000000001ff000 <_start-0x1000>:
+  1ff000:	66 2e 0f 1f 84 00 00 00 00 00 	cs nopw 0x0\(%rax,%rax,1\)
+#...
+  1ffffa:	66 0f 1f 44 00 00    	nopw   0x0\(%rax,%rax,1\)
+
+0000000000200000 <_start>:
+  200000:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
+  200006:	48 8b 05 fb ff 0f 00 	mov    0xffffb\(%rip\),%rax        # 300008 <_start\+0x100008>
+  20000d:	48 8b 05 f4 ff 0f 00 	mov    0xffff4\(%rip\),%rax        # 300008 <_start\+0x100008>
+  200014:	c7 c0 0d 00 20 80    	mov    \$0x8020000d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1b.t b/ld/testsuite/ld-x86-64/pr32591-1b.t
new file mode 100644
index 00000000000..1f7a0e12023
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1b.t
@@ -0,0 +1,7 @@ 
+SECTIONS {
+  .text.foo 0x100000 : { *(.text.foo) }
+  .text 0x1ff000 : { . = . + 0x1000 ; *(.text) }
+  .got 0x300000 : { *(.got) }
+  foo 0x7fffffff : { *(foo) }
+  data 0x80200000 : { *(data) }
+}
diff --git a/ld/testsuite/ld-x86-64/pr32591-1c-x32.d b/ld/testsuite/ld-x86-64/pr32591-1c-x32.d
new file mode 100644
index 00000000000..e1c7fc61816
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1c-x32.d
@@ -0,0 +1,22 @@ 
+#source: pr32591-1.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -T pr32591-1c.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+00100000 <_foo>:
+  100000:	c7 c0 00 00 40 00    	mov    \$0x400000,%eax
+  100006:	48 81 c0 0e 00 40 00 	add    \$0x40000e,%rax
+  10000d:	48 81 c0 0d 00 40 00 	add    \$0x40000d,%rax
+
+Disassembly of section .text:
+
+00200000 <_start>:
+  200000:	c7 c0 0d 00 40 00    	mov    \$0x40000d,%eax
+  200006:	40 c7 c0 0d 00 40 00 	rex mov \$0x40000d,%eax
+  20000d:	40 c7 c0 0d 00 40 00 	rex mov \$0x40000d,%eax
+  200014:	c7 c0 0d 00 40 00    	mov    \$0x40000d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1c.d b/ld/testsuite/ld-x86-64/pr32591-1c.d
new file mode 100644
index 00000000000..f7b390fe485
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1c.d
@@ -0,0 +1,22 @@ 
+#source: pr32591-1.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -T pr32591-1c.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+0000000000100000 <_foo>:
+  100000:	c7 c0 00 00 40 00    	mov    \$0x400000,%eax
+  100006:	48 81 c0 0e 00 40 00 	add    \$0x40000e,%rax
+  10000d:	48 81 c0 0d 00 40 00 	add    \$0x40000d,%rax
+
+Disassembly of section .text:
+
+0000000000200000 <_start>:
+  200000:	c7 c0 0d 00 40 00    	mov    \$0x40000d,%eax
+  200006:	48 c7 c0 0d 00 40 00 	mov    \$0x40000d,%rax
+  20000d:	48 c7 c0 0d 00 40 00 	mov    \$0x40000d,%rax
+  200014:	c7 c0 0d 00 40 00    	mov    \$0x40000d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1c.t b/ld/testsuite/ld-x86-64/pr32591-1c.t
new file mode 100644
index 00000000000..3bfb7f22cd2
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1c.t
@@ -0,0 +1,6 @@ 
+SECTIONS {
+  .text.foo 0x100000 : { *(.text.foo) }
+  .text 0x200000 : { *(.text) }
+  .got 0x300000 : { *(.got) }
+  data 0x400000 : { *(data) }
+}
diff --git a/ld/testsuite/ld-x86-64/pr32591-1d-x32.d b/ld/testsuite/ld-x86-64/pr32591-1d-x32.d
new file mode 100644
index 00000000000..c5bc0eef6fb
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1d-x32.d
@@ -0,0 +1,22 @@ 
+#source: pr32591-1.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -T pr32591-1d.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+00002000 <_foo>:
+    2000:	c7 c0 00 10 00 80    	mov    \$0x80001000,%eax
+    2006:	48 03 05 f3 1f 00 00 	add    0x1ff3\(%rip\),%rax        # 4000 <_start\+0x1000>
+    200d:	48 81 c0 ff ff ff 7f 	add    \$0x7fffffff,%rax
+
+Disassembly of section .text:
+
+00003000 <_start>:
+    3000:	c7 c0 0d 10 00 80    	mov    \$0x8000100d,%eax
+    3006:	40 c7 c0 0d 10 00 80 	rex mov \$0x8000100d,%eax
+    300d:	40 c7 c0 0d 10 00 80 	rex mov \$0x8000100d,%eax
+    3014:	c7 c0 0d 10 00 80    	mov    \$0x8000100d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1d.d b/ld/testsuite/ld-x86-64/pr32591-1d.d
new file mode 100644
index 00000000000..36b0853c9ad
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1d.d
@@ -0,0 +1,22 @@ 
+#source: pr32591-1.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -T pr32591-1d.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text.foo:
+
+0000000000002000 <_foo>:
+    2000:	c7 c0 00 10 00 80    	mov    \$0x80001000,%eax
+    2006:	48 03 05 f3 1f 00 00 	add    0x1ff3\(%rip\),%rax        # 4000 <_start\+0x1000>
+    200d:	48 81 c0 ff ff ff 7f 	add    \$0x7fffffff,%rax
+
+Disassembly of section .text:
+
+0000000000003000 <_start>:
+    3000:	c7 c0 0d 10 00 80    	mov    \$0x8000100d,%eax
+    3006:	48 8b 05 fb 0f 00 00 	mov    0xffb\(%rip\),%rax        # 4008 <_start\+0x1008>
+    300d:	48 8b 05 f4 0f 00 00 	mov    0xff4\(%rip\),%rax        # 4008 <_start\+0x1008>
+    3014:	c7 c0 0d 10 00 80    	mov    \$0x8000100d,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-1d.t b/ld/testsuite/ld-x86-64/pr32591-1d.t
new file mode 100644
index 00000000000..accfd804f86
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-1d.t
@@ -0,0 +1,7 @@ 
+SECTIONS {
+  .text.foo 0x02000 : { *(.text.foo) }
+  .text 0x3000 : { *(.text) }
+  .got 0x4000 : { *(.got) }
+  foo 0x7fffffff : { *(foo) }
+  data 0x80001000 : { *(data) }
+}
diff --git a/ld/testsuite/ld-x86-64/pr32591-2-x32.d b/ld/testsuite/ld-x86-64/pr32591-2-x32.d
new file mode 100644
index 00000000000..765b3793b4d
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-2-x32.d
@@ -0,0 +1,12 @@ 
+#source: pr32591-2.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -T pr32591-2.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+ffff0000 <_start>:
+ffff0000:	40 c7 c0 08 00 ff ff 	rex mov \$0xffff0008,%eax
diff --git a/ld/testsuite/ld-x86-64/pr32591-2.d b/ld/testsuite/ld-x86-64/pr32591-2.d
new file mode 100644
index 00000000000..dccf546db81
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-2.d
@@ -0,0 +1,12 @@ 
+#source: pr32591-2.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -T pr32591-2.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+00000000ffff0000 <_start>:
+    ffff0000:	48 8b 05 09 00 00 00 	mov    0x9\(%rip\),%rax        # ffff0010 <__stack_chk_guard\+0x8>
diff --git a/ld/testsuite/ld-x86-64/pr32591-2.s b/ld/testsuite/ld-x86-64/pr32591-2.s
new file mode 100644
index 00000000000..76168cef209
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-2.s
@@ -0,0 +1,13 @@ 
+	.text
+	.p2align 4
+	.globl	_start
+	.type	_start, @function
+_start:
+	movq	__stack_chk_guard@GOTPCREL(%rip), %rax
+	.globl	__stack_chk_guard
+	.section	.rodata
+	.align 8
+	.type	__stack_chk_guard, @object
+__stack_chk_guard:
+	.quad -1
+	.section	.note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr32591-2.t b/ld/testsuite/ld-x86-64/pr32591-2.t
new file mode 100644
index 00000000000..0b1109c38c7
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-2.t
@@ -0,0 +1,4 @@ 
+SECTIONS {
+  .text  0xffff0000 : { *(.text*) }
+  .rodata : AT(ADDR(".rodata") - 0xffff0000) { *(.rodata*) }
+}
diff --git a/ld/testsuite/ld-x86-64/pr32591-3-x32.d b/ld/testsuite/ld-x86-64/pr32591-3-x32.d
new file mode 100644
index 00000000000..3b91f7d7b9e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-3-x32.d
@@ -0,0 +1,13 @@ 
+#source: pr32591-3.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -T pr32591-3.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+f0000000 <_start>:
+f0000000:	40 c7 c0 08 00 30 ff 	rex mov \$0xff300008,%eax
+f0000007:	48 03 1d f2 ff 2f 0f 	add    0xf2ffff2\(%rip\),%rbx        # ff300000 <_start\+0xf300000>
diff --git a/ld/testsuite/ld-x86-64/pr32591-3.d b/ld/testsuite/ld-x86-64/pr32591-3.d
new file mode 100644
index 00000000000..4ad0878b1b4
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-3.d
@@ -0,0 +1,13 @@ 
+#source: pr32591-3.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -T pr32591-3.t -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+00000000f0000000 <_start>:
+    f0000000:	48 8b 05 f9 ff 2f 0f 	mov    0xf2ffff9\(%rip\),%rax        # ff300000 <_start\+0xf300000>
+    f0000007:	48 03 1d f2 ff 2f 0f 	add    0xf2ffff2\(%rip\),%rbx        # ff300000 <_start\+0xf300000>
diff --git a/ld/testsuite/ld-x86-64/pr32591-3.s b/ld/testsuite/ld-x86-64/pr32591-3.s
new file mode 100644
index 00000000000..ba8ebf3f0c7
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-3.s
@@ -0,0 +1,7 @@ 
+	.text
+	.globl  _start
+	.type	_start, @function
+_start:
+	movq	foo@GOTPCREL(%rip), %rax
+	addq	foo@GOTPCREL(%rip), %rbx
+	.size	_start, .-_start
diff --git a/ld/testsuite/ld-x86-64/pr32591-3.t b/ld/testsuite/ld-x86-64/pr32591-3.t
new file mode 100644
index 00000000000..91feb7caa91
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-3.t
@@ -0,0 +1,5 @@ 
+SECTIONS {
+  .text 0xf0000000 : { *(.text) }
+  .got 0xff300000 : { *(.got) }
+  foo = .;
+}
diff --git a/ld/testsuite/ld-x86-64/pr32591-4-x32.d b/ld/testsuite/ld-x86-64/pr32591-4-x32.d
new file mode 100644
index 00000000000..12e1790f174
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-4-x32.d
@@ -0,0 +1,13 @@ 
+#source: pr32591-4.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 -Ttext-segment=0xf0000000 -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+f0001000 <_start>:
+f0001000:	40 c7 c0 00 00 00 f0 	rex mov \$0xf0000000,%eax
+f0001007:	48 03 1d f2 0f 00 00 	add    0xff2\(%rip\),%rbx        # f0002000 <_start\+0x1000>
diff --git a/ld/testsuite/ld-x86-64/pr32591-4.d b/ld/testsuite/ld-x86-64/pr32591-4.d
new file mode 100644
index 00000000000..ac578055ac9
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-4.d
@@ -0,0 +1,13 @@ 
+#source: pr32591-4.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 -Ttext-segment=0xf0000000 -z max-page-size=0x1000 -z separate-code --no-rosegment
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+00000000f0001000 <_start>:
+    f0001000:	48 8b 05 f9 0f 00 00 	mov    0xff9\(%rip\),%rax        # f0002000 <_start\+0x1000>
+    f0001007:	48 03 1d f2 0f 00 00 	add    0xff2\(%rip\),%rbx        # f0002000 <_start\+0x1000>
diff --git a/ld/testsuite/ld-x86-64/pr32591-4.s b/ld/testsuite/ld-x86-64/pr32591-4.s
new file mode 100644
index 00000000000..aa784b80799
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr32591-4.s
@@ -0,0 +1,7 @@ 
+	.text
+	.globl  _start
+	.type	_start, @function
+_start:
+	movq	__ehdr_start@GOTPCREL(%rip), %rax
+	addq	__ehdr_start@GOTPCREL(%rip), %rbx
+	.size	_start, .-_start
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index bde29fbd571..bcec5c1926a 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -544,6 +544,20 @@  run_dump_test "tlsdesc4"
 run_dump_test "tlsdesc5"
 run_dump_test "pr32191"
 run_dump_test "pr32191-x32"
+run_dump_test "pr32591-1a"
+run_dump_test "pr32591-1a-x32"
+run_dump_test "pr32591-1b"
+run_dump_test "pr32591-1b-x32"
+run_dump_test "pr32591-1c"
+run_dump_test "pr32591-1c-x32"
+run_dump_test "pr32591-1d"
+run_dump_test "pr32591-1d-x32"
+run_dump_test "pr32591-2"
+run_dump_test "pr32591-2-x32"
+run_dump_test "pr32591-3"
+run_dump_test "pr32591-3-x32"
+run_dump_test "pr32591-4"
+run_dump_test "pr32591-4-x32"
 
 if { ![skip_sframe_tests] } {
     run_dump_test "sframe-simple-1"
-- 
2.48.1