[PATCH v4] x86: Properly handle relocation against local ABS symbol

H.J. Lu hjl.tools@gmail.com
Sat May 17 21:54:26 GMT 2025


On x86-64,

	movq	symbol@GOTPCREL(%rip), %rax

may be used to get the symbol address via GOT.  If the symbol turns out
to be a local symbol, linker normally converts it into

	leaq	symbol(%rip), %rax

But if the symbol is an ABS symbol, RAX won't have the correct value at
run-time and it will have the symbol value + load address.  If the symbol
is declared as hidden or protected, compiler will generate

	leaq	symbol(%rip), %rax

to get the symbol address.  If symbol is a local ABS symbol, RAX will have
the same incorrect value at run-time.  On i386,

	movl	symbol@GOT(%reg1), %reg2

may be used to get the symbol address via GOT.  If the symbol turns out
to be a local symbol, a symbol is local if it is hidden/protected symbol
or the output is an executable, linker normally converts it into

	leal	symbol@GOTOFF(%reg1), %reg2

If the symbol is declared as hidden or protected, compiler will generate

	leal	symbol@GOTOFF(%reg1), %reg2

In both cases, if symbol is a local ABS symbol, REG2 will have the same
incorrect value at run-time.  This patch changes the x86-64 linker to
convert

	movq	symbol@GOTPCREL(%rip), %rax
and
	leaq	symbol(%rip), %rax
to
	movq	$symbol, %rax

and changes the i386 linker to convert

	movl	symbol@GOT(%reg1), %reg2
and
	leal	symbol@GOTOFF(%reg1), %reg2
	leal	symbol@GOTOFF, %reg2
to
	movl	$symbol, %reg2

for local ABS symbols.

bfd/

	PR ld/32443
	* elf32-i386.c (elf_i386_convert_load_reloc): Convert
	lea symbol@GOTOFF[(%reg1)], %reg2" to "mov $symbol, %reg2"
	for R_386_GOTOFF relocation against local ABS symbols.
	(elf_i386_scan_relocs): Call elf_i386_convert_load_reloc only
	on executable sections. Also convert R_386_GOTOFF relocation
	against global symbol.
	(elf_i386_finish_dynamic_symbol): Don't generate dynamic
	relocation against local ABS symbols.
	* elf64-x86-64.c (elf_x86_64_convert_load_reloc): Convert
	"lea symbol(%rip), %reg" to "mov $symbol, %reg" for R_X86_64_PC32
	relocation against local ABS symbols.
	(elf_x86_64_scan_relocs): Call elf_x86_64_convert_load_reloc only
	on executable sections. Also convert R_X86_64_PC32 relocation
	against global symbol.
	(elf_x86_64_finish_dynamic_symbol): Don't generate dynamic
	relocation against local ABS symbol.
	* elfxx-x86.h (ABS_SYMBOL_P): Drop linker-script defined check.
	(LOCAL_ABS_SYMBOL_P): New.

ld/

	PR ld/32443
	* testsuite/ld-elf/linux-x86.exp: Run PR ld/32443 tests.  Allow
	PC32 relocation against local ABS symbol in PIE.
	* testsuite/ld-elf/pr25749-1b.err: Removed.
	* testsuite/ld-elf/pr32443-hidden.rd: New file.
	* testsuite/ld-elf/pr32443-hidden.t: Likewise.
	* testsuite/ld-elf/pr32443.t: Likewise.
	* testsuite/ld-elf/pr32443a.c: Likewise.
	* testsuite/ld-elf/pr32443b.c: Likewise.
	* testsuite/ld-i386/i386.exp: PR ld/32443 tests.
	* testsuite/ld-i386/lea2.s: New file.
	* testsuite/ld-i386/lea2a.d: Likewise.
	* testsuite/ld-i386/lea2b.d: Likewise.
	* testsuite/ld-i386/lea2c.d: Likewise.
	* testsuite/ld-i386/lea3.d: Likewise.
	* testsuite/ld-i386/lea3.s: Likewise.
	* testsuite/ld-i386/mov4.s: Likewise.
	* testsuite/ld-i386/mov4a.d: Likewise.
	* testsuite/ld-i386/mov4b.d: Likewise.
	* testsuite/ld-i386/mov4c.d: Likewise.
	* testsuite/ld-x86-64/lea2.s: Likewise.
	* testsuite/ld-x86-64/lea2a-x32.d: Likewise.
	* testsuite/ld-x86-64/lea2a.d: Likewise.
	* testsuite/ld-x86-64/lea2b-x32.d: Likewise.
	* testsuite/ld-x86-64/lea2b.d: Likewise.
	* testsuite/ld-x86-64/lea2c-x32.d: Likewise.
	* testsuite/ld-x86-64/lea2c.d: Likewise.
	* testsuite/ld-x86-64/lea2d-x32.d: Likewise.
	* testsuite/ld-x86-64/lea2d.d: Likewise.
	* testsuite/ld-x86-64/lea2e-x32.d: Likewise.
	* testsuite/ld-x86-64/lea2e.d: Likewise.
	* testsuite/ld-x86-64/lea3-x32.d: Likewise.
	* testsuite/ld-x86-64/lea3.d: Likewise.
	* testsuite/ld-x86-64/lea4-x32.d: Likewise.
	* testsuite/ld-x86-64/lea4.d: Likewise.
	* testsuite/ld-x86-64/mov3.s: Likewise.
	* testsuite/ld-x86-64/mov3a-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3a.d: Likewise.
	* testsuite/ld-x86-64/mov3b-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3b.d: Likewise.
	* testsuite/ld-x86-64/mov3c-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3c.d: Likewise.
	* testsuite/ld-x86-64/mov3d-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3d.d: Likewise.
	* testsuite/ld-x86-64/mov3d-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3d.d: Likewise.
	* testsuite/ld-x86-64/mov3e-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3e.d: Likewise.
	* testsuite/ld-x86-64/mov3f-x32.d: Likewise.
	* testsuite/ld-x86-64/mov3f.d: Likewise.
	* testsuite/ld-x86-64/x86-64.exp: Run PR ld/32443 tests.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 bfd/elf32-i386.c                      |  84 ++++++++++++----
 bfd/elf64-x86-64.c                    | 137 +++++++++++++++++++-------
 bfd/elfxx-x86.h                       |  14 ++-
 ld/testsuite/ld-elf/linux-x86.exp     |  68 +++++++++++--
 ld/testsuite/ld-elf/pr25749-1b.err    |   3 -
 ld/testsuite/ld-elf/pr32443-hidden.rd |   4 +
 ld/testsuite/ld-elf/pr32443-hidden.t  |   1 +
 ld/testsuite/ld-elf/pr32443.t         |   1 +
 ld/testsuite/ld-elf/pr32443a.c        |  15 +++
 ld/testsuite/ld-elf/pr32443b.c        |   7 ++
 ld/testsuite/ld-i386/i386.exp         |   7 ++
 ld/testsuite/ld-i386/lea2.s           |  12 +++
 ld/testsuite/ld-i386/lea2a.d          |  14 +++
 ld/testsuite/ld-i386/lea2b.d          |  14 +++
 ld/testsuite/ld-i386/lea2c.d          |  14 +++
 ld/testsuite/ld-i386/lea3.d           |   6 ++
 ld/testsuite/ld-i386/lea3.s           |  10 ++
 ld/testsuite/ld-i386/mov4.s           |  11 +++
 ld/testsuite/ld-i386/mov4a.d          |  13 +++
 ld/testsuite/ld-i386/mov4b.d          |  13 +++
 ld/testsuite/ld-i386/mov4c.d          |  13 +++
 ld/testsuite/ld-x86-64/lea2.s         |  11 +++
 ld/testsuite/ld-x86-64/lea2a-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/lea2a.d        |  13 +++
 ld/testsuite/ld-x86-64/lea2b-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/lea2b.d        |  13 +++
 ld/testsuite/ld-x86-64/lea2c-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/lea2c.d        |  13 +++
 ld/testsuite/ld-x86-64/lea2d-x32.d    |   4 +
 ld/testsuite/ld-x86-64/lea2d.d        |   4 +
 ld/testsuite/ld-x86-64/lea2e-x32.d    |   4 +
 ld/testsuite/ld-x86-64/lea2e.d        |   4 +
 ld/testsuite/ld-x86-64/lea3-x32.d     |   7 ++
 ld/testsuite/ld-x86-64/lea3.d         |   6 ++
 ld/testsuite/ld-x86-64/lea3.s         |  10 ++
 ld/testsuite/ld-x86-64/lea4-x32.d     |  13 +++
 ld/testsuite/ld-x86-64/lea4.d         |  12 +++
 ld/testsuite/ld-x86-64/lea4.s         |   9 ++
 ld/testsuite/ld-x86-64/mov3.s         |  11 +++
 ld/testsuite/ld-x86-64/mov3a-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/mov3a.d        |  13 +++
 ld/testsuite/ld-x86-64/mov3b-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/mov3b.d        |  13 +++
 ld/testsuite/ld-x86-64/mov3c-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/mov3c.d        |  13 +++
 ld/testsuite/ld-x86-64/mov3d-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/mov3d.d        |  13 +++
 ld/testsuite/ld-x86-64/mov3e-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/mov3e.d        |  13 +++
 ld/testsuite/ld-x86-64/mov3f-x32.d    |  13 +++
 ld/testsuite/ld-x86-64/mov3f.d        |  13 +++
 ld/testsuite/ld-x86-64/x86-64.exp     |  26 +++++
 52 files changed, 744 insertions(+), 72 deletions(-)
 delete mode 100644 ld/testsuite/ld-elf/pr25749-1b.err
 create mode 100644 ld/testsuite/ld-elf/pr32443-hidden.rd
 create mode 100644 ld/testsuite/ld-elf/pr32443-hidden.t
 create mode 100644 ld/testsuite/ld-elf/pr32443.t
 create mode 100644 ld/testsuite/ld-elf/pr32443a.c
 create mode 100644 ld/testsuite/ld-elf/pr32443b.c
 create mode 100644 ld/testsuite/ld-i386/lea2.s
 create mode 100644 ld/testsuite/ld-i386/lea2a.d
 create mode 100644 ld/testsuite/ld-i386/lea2b.d
 create mode 100644 ld/testsuite/ld-i386/lea2c.d
 create mode 100644 ld/testsuite/ld-i386/lea3.d
 create mode 100644 ld/testsuite/ld-i386/lea3.s
 create mode 100644 ld/testsuite/ld-i386/mov4.s
 create mode 100644 ld/testsuite/ld-i386/mov4a.d
 create mode 100644 ld/testsuite/ld-i386/mov4b.d
 create mode 100644 ld/testsuite/ld-i386/mov4c.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2.s
 create mode 100644 ld/testsuite/ld-x86-64/lea2a-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2a.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2b-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2b.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2c-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2c.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2d-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2d.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2e-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea2e.d
 create mode 100644 ld/testsuite/ld-x86-64/lea3-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea3.d
 create mode 100644 ld/testsuite/ld-x86-64/lea3.s
 create mode 100644 ld/testsuite/ld-x86-64/lea4-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/lea4.d
 create mode 100644 ld/testsuite/ld-x86-64/lea4.s
 create mode 100644 ld/testsuite/ld-x86-64/mov3.s
 create mode 100644 ld/testsuite/ld-x86-64/mov3a-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3a.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3b-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3b.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3c-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3c.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3d-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3d.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3e-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3e.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3f-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/mov3f.d

diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 5939548d0da..f8204f58ab9 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1239,6 +1239,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   bfd_vma nop_offset;
   bool is_pic, is_branch = false;
   bool to_reloc_32;
+  bool reloc_gotoff;
   bool abs_symbol;
   unsigned int r_type;
   unsigned int r_symndx;
@@ -1249,7 +1250,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   if (roff < 2)
     return true;
 
-  /* Addend for R_386_GOT32X relocations must be 0.  */
+  /* Addend for R_386_GOT32X/R_386_GOTOFF relocations must be 0.  */
   addend = bfd_get_32 (abfd, contents + roff);
   if (addend != 0)
     return true;
@@ -1266,6 +1267,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
   r_type = *r_type_p;
   r_symndx = ELF32_R_SYM (irel->r_info);
 
+  reloc_gotoff = r_type == R_386_GOTOFF;
   modrm = bfd_get_8 (abfd, contents + roff - 1);
   baseless = (modrm & 0xc7) == 0x5;
 
@@ -1284,7 +1286,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       abs_symbol = isym->st_shndx == SHN_ABS;
     }
 
-  if (baseless && is_pic)
+  if (baseless && is_pic && !reloc_gotoff)
     {
       /* For PIC, disallow R_386_GOT32X without a base register
 	 since we don't know what the GOT base is.  */
@@ -1305,31 +1307,45 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 
   opcode = bfd_get_8 (abfd, contents + roff - 2);
 
-  if (opcode == 0xff)
+  if (reloc_gotoff)
     {
-      switch (modrm & 0x38)
+      /* Only "lea symbol@GOTOFF[(%reg1)], %reg2" is allowed which will
+	 be converted to "mov $symbol, %reg2" for a local ABS symbol.  */
+      if (opcode != 0x8d)
+	return true;
+
+      /* Assuming it will be converted to R_386_32 against the local
+	 ABS symbol.  If it isn't case, it will be skipped.  */
+      to_reloc_32 = true;
+    }
+  else
+    {
+      if (opcode == 0xff)
 	{
-	case 0x10: /* CALL */
-	case 0x20: /* JMP */
-	  is_branch = true;
-	  break;
+	  switch (modrm & 0x38)
+	    {
+	    case 0x10: /* CALL */
+	    case 0x20: /* JMP */
+	      is_branch = true;
+	      break;
 
-	case 0x30: /* PUSH */
-	  break;
+	    case 0x30: /* PUSH */
+	      break;
 
-	default:
-	  return true;
+	    default:
+	      return true;
+	    }
 	}
-    }
 
-  /* Convert to R_386_32 if PIC is false (if PIC is true we already know
-     there is a base register).  */
-  to_reloc_32 = !is_pic;
+      /* Convert R_386_GOT32X to R_386_32 if PIC is false (if PIC is
+	 true we already know there is a base register).  */
+      to_reloc_32 = !is_pic;
+    }
 
   eh = elf_x86_hash_entry (h);
 
-  /* Try to convert R_386_GOT32X.  Get the symbol referred to by the
-     reloc.  */
+  /* Try to convert R_386_GOT32X/R_386_GOTOFF.  Get the symbol referred
+     to by the reloc.  */
   if (h == NULL)
     {
       if (is_branch)
@@ -1341,6 +1357,29 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 	   "binop foo@GOT[(%reg1)], %reg2". */
 	goto convert_load;
     }
+  else if (LOCAL_ABS_SYMBOL_P (link_info, h))
+    {
+      /* Covert relocation against a local ABS symbol to R_386_32 so
+	 that we will get the absolute value for the ABS symbol at
+	 run-time.  Convert
+		leal	symbol@GOTOFF[(%reg1)], %reg2
+	 and
+		movl	symbol@GOT(%reg1), %reg2
+	 to
+		movl	$symbol, %reg2
+       */
+      if (reloc_gotoff || opcode == 0x8b)
+	{
+	  to_reloc_32 = true;
+	  goto lea_to_mov;
+	}
+      return true;
+    }
+
+  /* R_386_GOTOFF can only be converted to R_386_32 against hidden or
+     protected ABS symbol.  */
+  if (reloc_gotoff)
+    return true;
 
   /* Undefined weak symbol is only bound locally in executable
      and its reference is resolved as 0.  */
@@ -1447,6 +1486,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
 
 	      if (to_reloc_32)
 		{
+		lea_to_mov:
 		  /* Convert "mov foo@GOT[(%reg1)], %reg2" to
 		     "mov $foo, %reg2" with R_386_32.  */
 		  r_type = R_386_32;
@@ -1635,8 +1675,10 @@ elf_i386_scan_relocs (bfd *abfd,
 	  h->ref_regular = 1;
 	}
 
-      if (r_type == R_386_GOT32X
-	  && (h == NULL || h->type != STT_GNU_IFUNC))
+      if ((sec->flags & SEC_CODE) != 0
+	  && (h == NULL || h->type != STT_GNU_IFUNC)
+	  && (r_type == R_386_GOT32X
+	      || (h != NULL && r_type == R_386_GOTOFF)))
 	{
 	  Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel;
 	  if (!elf_i386_convert_load_reloc (abfd, symtab_hdr, contents,
@@ -3991,7 +4033,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
 	       && SYMBOL_REFERENCES_LOCAL_P (info, h))
 	{
 	  BFD_ASSERT((h->got.offset & 1) != 0);
-	  if (info->enable_dt_relr)
+	  if (info->enable_dt_relr || LOCAL_ABS_SYMBOL_P (info, h))
 	    generate_dynamic_reloc = false;
 	  else
 	    {
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 1baa8a01cee..4d730bab347 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1791,6 +1791,8 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
   bool relocx;
   bool is_branch = false;
   bool to_reloc_pc32;
+  bool reloc_pc32 = false;
+  bool to_reloc_32s = false;
   bool abs_symbol;
   bool local_ref;
   asection *tsec = NULL;
@@ -1813,6 +1815,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
       if (roff < 2)
 	return true;
       relocx = (r_type == R_X86_64_GOTPCRELX);
+      reloc_pc32 = r_type == R_X86_64_PC32;
       break;
 
     case R_X86_64_REX_GOTPCRELX:
@@ -1887,31 +1890,40 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 
   opcode = bfd_get_8 (abfd, contents + roff - 2);
   modrm = bfd_get_8 (abfd, contents + roff - 1);
-  if (opcode == 0xff)
+  if (reloc_pc32)
     {
-      switch (modrm & 0x38)
+      /* Only "lea symbol(%rip), %reg" is allowed which will be converted
+	 to "mov $symbol, %reg" for a local ABS symbol.  */
+      if (opcode != 0x8d || modrm != 05)
+	 return true;
+    }
+  else
+    {
+      if (opcode == 0xff)
 	{
-	case 0x10: /* CALL */
-	case 0x20: /* JMP */
-	  is_branch = true;
-	  break;
+	  switch (modrm & 0x38)
+	    {
+	    case 0x10: /* CALL */
+	    case 0x20: /* JMP */
+	      is_branch = true;
+	      break;
 
-	case 0x30: /* PUSH */
-	  break;
+	    case 0x30: /* PUSH */
+	      break;
 
-	default:
-	  return true;
+	    default:
+	      return true;
+	    }
+	}
+      /* Convert mov to lea since it has been done for a while.  */
+      else if (opcode != 0x8b)
+	{
+	  /* Only convert R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX
+	     and R_X86_64_CODE_<n>_GOTPCRELX for call, jmp or one of adc,
+	     add, and, cmp, or, sbb, sub, test, xor instructions.  */
+	  if (!relocx)
+	    return true;
 	}
-    }
-
-  /* Convert mov to lea since it has been done for a while.  */
-  if (opcode != 0x8b)
-    {
-      /* Only convert R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX
-	 and R_X86_64_CODE_<n>_GOTPCRELX for call, jmp or one of adc,
-	 add, and, cmp, or, sbb, sub, test, xor instructions.  */
-      if (!relocx)
-	return true;
     }
 
   /* We convert only to R_X86_64_PC32:
@@ -1920,10 +1932,11 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
      3. no_overflow is true.
      4. PIC.
      */
-  to_reloc_pc32 = (is_branch
-		   || !relocx
-		   || no_overflow
-		   || is_pic);
+  to_reloc_pc32 = (!reloc_pc32
+		   && (is_branch
+		       || !relocx
+		       || no_overflow
+		       || is_pic));
 
   abs_symbol = false;
   abs_relocation = 0;
@@ -1962,12 +1975,34 @@ 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;
 
+      if (LOCAL_ABS_SYMBOL_P (link_info, h))
+	{
+	  /* Covert relocation against local ABS symbol to R_X86_64_32S
+	     so that we will get the absolute value for the ABS symbol
+	     at run-time.  Convert
+		leaq	symbol(%rip), %rax
+	     and
+		movq	symbol@GOTPCREL(%rip), %rax
+	     to
+		movq	$symbol, %rax
+	     */
+	  if (reloc_pc32 || opcode == 0x8b)
+	    to_reloc_32s = true;
+	  else
+	    return true;
+	}
+
+      /* R_X86_64_PC32 can only be converted R_X86_64_32S against a
+	 local ABS symbol.  */
+      if (reloc_pc32 && !to_reloc_32s)
+	return true;
+
+      isym = NULL;
+      tsec = NULL;
+
       /* NB: Also set linker_def via SYMBOL_REFERENCES_LOCAL_P.  */
       local_ref = SYMBOL_REFERENCES_LOCAL_P (link_info, h);
       if ((relocx || opcode == 0x8b)
@@ -2292,13 +2327,17 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 	  else if (bfd_get_8 (abfd, contents + roff - 4) == 0x0f)
 	    movrs = 4;
 	}
-      else if (r_type == R_X86_64_REX_GOTPCRELX)
+      else if (reloc_pc32 || r_type == R_X86_64_REX_GOTPCRELX)
 	{
 	  rex = bfd_get_8 (abfd, contents + roff - 3);
 	  rex_w = (rex & REX_W) != 0;
 	}
 
-      if (opcode == 0x8b)
+      /* Convert "lea symbol(%rip), %reg" to "mov $symbol, %reg".  When
+	 we get here, to_reloc_32s must be true.  */
+      if (reloc_pc32)
+	goto lea_to_mov;
+      else if (opcode == 0x8b)
 	{
 	  if (abs_symbol && local_ref && relocx)
 	    to_reloc_pc32 = false;
@@ -2325,6 +2364,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 	    }
 	  else
 	    {
+	    lea_to_mov:
 	      /* Convert "mov foo@GOTPCREL(%rip), %reg" to
 		 "mov $foo, %reg".  */
 	      opcode = 0xc7;
@@ -2415,7 +2455,26 @@ elf_x86_64_convert_load_reloc (bfd *abfd,
 					contents, irel->r_offset,
 					relocation, 0);
 	  if (r == bfd_reloc_overflow)
-	    return true;
+	    {
+	      if ((r_type == (rex_w && ABI_64_P (link_info->output_bfd)
+			      ? R_X86_64_32S : R_X86_64_32))
+		  && reloc_pc32
+		  && LOCAL_ABS_SYMBOL_P (link_info, h))
+		{
+		  /* Since R_X86_64_PC32S/R_X86_64_32 relocation, which
+		     is converted from R_X86_64_PC32, against a local
+		     ABS symbol overflows, the unconverted R_X86_64_PC32
+		     relocation will also overflow.  */
+		  howto = elf_x86_64_rtype_to_howto (abfd,
+						     R_X86_64_PC32);
+		  link_info->callbacks->reloc_overflow
+		    (link_info, &h->root, h->root.root.string,
+		     howto->name, (bfd_vma) 0, abfd, input_section,
+		   irel->r_offset);
+		  return false;
+		}
+	      return true;
+	    }
 
 	  if (abs_relocation)
 	    {
@@ -2638,13 +2697,15 @@ elf_x86_64_scan_relocs (bfd *abfd, struct bfd_link_info *info,
 	}
 
       converted_reloc = false;
-      if ((r_type == R_X86_64_GOTPCREL
-	   || r_type == R_X86_64_GOTPCRELX
-	   || r_type == R_X86_64_REX_GOTPCRELX
-	   || r_type == R_X86_64_CODE_4_GOTPCRELX
-	   || r_type == R_X86_64_CODE_5_GOTPCRELX
-	   || r_type == R_X86_64_CODE_6_GOTPCRELX)
-	  && (h == NULL || h->type != STT_GNU_IFUNC))
+      if ((sec->flags & SEC_CODE) != 0
+	  && (h == NULL || h->type != STT_GNU_IFUNC)
+	  && (r_type == R_X86_64_GOTPCREL
+	      || r_type == R_X86_64_GOTPCRELX
+	      || r_type == R_X86_64_REX_GOTPCRELX
+	      || r_type == R_X86_64_CODE_4_GOTPCRELX
+	      || r_type == R_X86_64_CODE_5_GOTPCRELX
+	      || r_type == R_X86_64_CODE_6_GOTPCRELX
+	      || (h != NULL && r_type == R_X86_64_PC32)))
 	{
 	  Elf_Internal_Rela *irel = (Elf_Internal_Rela *) rel;
 	  if (!elf_x86_64_convert_load_reloc (abfd, sec, contents,
@@ -5462,7 +5523,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
 	  if (!SYMBOL_DEFINED_NON_SHARED_P (h))
 	    return false;
 	  BFD_ASSERT((h->got.offset & 1) != 0);
-	  if (info->enable_dt_relr)
+	  if (info->enable_dt_relr || LOCAL_ABS_SYMBOL_P (info, h))
 	    generate_dynamic_reloc = false;
 	  else
 	    {
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 88bfa05bce2..a1201367373 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -252,10 +252,16 @@
    || ELF_COMMON_DEF_P (H))
 
 /* Return TRUE if the symbol described by a linker hash entry H is
-   going to be absolute.  Similar to bfd_is_abs_symbol, but excluding
-   all linker-script defined symbols.  */
-#define ABS_SYMBOL_P(H) \
-  (bfd_is_abs_symbol (&(H)->root) && !(H)->root.ldscript_def)
+   going to be absolute.  */
+#define ABS_SYMBOL_P(H) bfd_is_abs_symbol (&(H)->root)
+
+/* Return TRUE if the symbol described by a linker hash entry H is a
+   local symbol which is going to be absolute.  */
+#define LOCAL_ABS_SYMBOL_P(INFO, H) \
+  (ABS_SYMBOL_P (H) \
+   && (bfd_link_executable (INFO) \
+       || ELF_ST_VISIBILITY ((H)->other) == STV_HIDDEN \
+       || ELF_ST_VISIBILITY ((H)->other) == STV_PROTECTED))
 
 /* TRUE if relative relocation should be generated.  GOT reference to
    global symbol in PIC will lead to dynamic symbol.  It becomes a
diff --git a/ld/testsuite/ld-elf/linux-x86.exp b/ld/testsuite/ld-elf/linux-x86.exp
index 27173b916da..681b7cda3f0 100644
--- a/ld/testsuite/ld-elf/linux-x86.exp
+++ b/ld/testsuite/ld-elf/linux-x86.exp
@@ -150,6 +150,30 @@ run_cc_link_tests [list \
 	{} \
 	"pr29377" \
     ] \
+    [list \
+	"Build pr32443a.so" \
+	"-shared $srcdir/$subdir/pr32443.t" \
+	"-O0 -fPIC" \
+	{pr32443a.c} \
+	{} \
+	"pr32443a.so" \
+    ] \
+    [list \
+	"Build pr32443b.so" \
+	"-shared $srcdir/$subdir/pr32443.t" \
+	"-O0 -fPIC -DHIDDEN" \
+	{pr32443a.c} \
+	{} \
+	"pr32443b.so" \
+    ] \
+    [list \
+	"Build pr32443-hidden.so" \
+	"-shared $srcdir/$subdir/pr32443-hidden.t" \
+	"-O0 -fPIC" \
+	{pr32443a.c} \
+	{{readelf {-Wr} pr32443-hidden.rd}}  \
+	"pr32443-hidden.so" \
+    ] \
 ]
 
 run_ld_link_exec_tests [list \
@@ -201,6 +225,42 @@ run_ld_link_exec_tests [list \
 	"" \
 	"tmpdir/indirect-extern-access-2.so" \
     ] \
+    [list \
+	"Run pr32443a with pr32443a.so" \
+	"" \
+	"" \
+	{ pr32443b.c } \
+	"pr32443a" \
+	"pass.out" \
+	"" \
+	"" \
+	"" \
+	"tmpdir/pr32443a.so" \
+    ] \
+    [list \
+	"Run pr32443b with pr32443b.so" \
+	"" \
+	"" \
+	{ pr32443b.c } \
+	"pr32443b" \
+	"pass.out" \
+	"" \
+	"" \
+	"" \
+	"tmpdir/pr32443b.so" \
+    ] \
+    [list \
+	"Run pr32443 with pr32443-hidden.so" \
+	"" \
+	"" \
+	{ pr32443b.c } \
+	"pr32443-hidden" \
+	"pass.out" \
+	"" \
+	"" \
+	"" \
+	"tmpdir/pr32443-hidden.so" \
+    ] \
 ]
 
 # Run-time tests which require working ifunc attribute support.
@@ -376,12 +436,8 @@ proc check_pr25749a {testname srcfilea srcfileb cflags ldflags lderror} {
 check_pr25749a "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
 check_pr25749a "pr25749-1a" "pr25749-1.c" "pr25749-1a.c" "-fPIE" "-pie" ""
 check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
-if { [istarget "i?86-*-linux*"] || ![at_least_gcc_version 5 1] } {
-    check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" ""
-} else {
-    check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" "pr25749-1b.err"
-}
-check_pr25749a "pr25749-1c" "pr25749-1.c" "pr25749-1c.c" "-fPIC" "-shared" "pr25749-1b.err"
+check_pr25749a "pr25749-1b" "pr25749-1.c" "pr25749-1b.c" "-fPIE" "-pie" ""
+check_pr25749a "pr25749-1c" "pr25749-1.c" "pr25749-1c.c" "-fPIE" "-pie" ""
 check_pr25749a "pr25749-2a" "pr25749-2.c" "pr25749-2a.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
 check_pr25749a "pr25749-2a" "pr25749-2.c" "pr25749-2a.s" "-fPIE" "-pie" ""
 check_pr25749a "pr25749-2b" "pr25749-2.c" "pr25749-2b.s" "$NOPIE_CFLAGS" "$NOPIE_LDFLAGS" ""
diff --git a/ld/testsuite/ld-elf/pr25749-1b.err b/ld/testsuite/ld-elf/pr25749-1b.err
deleted file mode 100644
index bb389172f16..00000000000
--- a/ld/testsuite/ld-elf/pr25749-1b.err
+++ /dev/null
@@ -1,3 +0,0 @@
-#...
-.*: .* against absolute symbol `_binary_pr25749_1_c_size' .* is disallowed
-#pass
diff --git a/ld/testsuite/ld-elf/pr32443-hidden.rd b/ld/testsuite/ld-elf/pr32443-hidden.rd
new file mode 100644
index 00000000000..fbc68bf2688
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr32443-hidden.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_.*_NONE.*
+#...
diff --git a/ld/testsuite/ld-elf/pr32443-hidden.t b/ld/testsuite/ld-elf/pr32443-hidden.t
new file mode 100644
index 00000000000..0754d57c012
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr32443-hidden.t
@@ -0,0 +1 @@
+PROVIDE_HIDDEN (value = 42);
diff --git a/ld/testsuite/ld-elf/pr32443.t b/ld/testsuite/ld-elf/pr32443.t
new file mode 100644
index 00000000000..9590849c5fb
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr32443.t
@@ -0,0 +1 @@
+PROVIDE (value = 42);
diff --git a/ld/testsuite/ld-elf/pr32443a.c b/ld/testsuite/ld-elf/pr32443a.c
new file mode 100644
index 00000000000..5111e373fdf
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr32443a.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdint.h>
+
+#ifdef HIDDEN
+extern int value __attribute__ ((visibility("hidden")));
+#else
+extern int value;
+#endif
+
+void
+lib_func (void)
+{
+  if ((uintptr_t) &value == 42)
+    printf ("PASS\n");
+}
diff --git a/ld/testsuite/ld-elf/pr32443b.c b/ld/testsuite/ld-elf/pr32443b.c
new file mode 100644
index 00000000000..a46c8e00f03
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr32443b.c
@@ -0,0 +1,7 @@
+extern void lib_func(void);
+int
+main(void)
+{
+  lib_func();
+  return 0;
+}
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 67ad1e926c9..c8a6d8900d7 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -344,11 +344,18 @@ run_dump_test "lea1c"
 run_dump_test "lea1d"
 run_dump_test "lea1e"
 run_dump_test "lea1f"
+run_dump_test "lea2a"
+run_dump_test "lea2b"
+run_dump_test "lea2c"
+run_dump_test "lea3"
 run_dump_test "mov1a"
 run_dump_test "mov1b"
 run_dump_test "mov2a"
 run_dump_test "mov2b"
 run_dump_test "mov3"
+run_dump_test "mov4a"
+run_dump_test "mov4b"
+run_dump_test "mov4c"
 run_dump_test "branch1"
 run_dump_test "call1"
 run_dump_test "call2"
diff --git a/ld/testsuite/ld-i386/lea2.s b/ld/testsuite/ld-i386/lea2.s
new file mode 100644
index 00000000000..d5f78831d67
--- /dev/null
+++ b/ld/testsuite/ld-i386/lea2.s
@@ -0,0 +1,12 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	leal	foo@GOTOFF(%ebx), %eax
+	leal	foo@GOTOFF, %eax
+	.size	_start, .-_start
+.ifdef __hidden__
+	.hidden foo
+.elseif __protected__ == 1
+	.protected foo
+.endif
diff --git a/ld/testsuite/ld-i386/lea2a.d b/ld/testsuite/ld-i386/lea2a.d
new file mode 100644
index 00000000000..7666508d65d
--- /dev/null
+++ b/ld/testsuite/ld-i386/lea2a.d
@@ -0,0 +1,14 @@
+#source: lea2.s
+#as: --32 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf_i386 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/lea2b.d b/ld/testsuite/ld-i386/lea2b.d
new file mode 100644
index 00000000000..de146dcf765
--- /dev/null
+++ b/ld/testsuite/ld-i386/lea2b.d
@@ -0,0 +1,14 @@
+#source: lea2.s
+#as: --32 -mrelax-relocations=yes --defsym __protected__=1
+#ld: -shared -melf_i386 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/lea2c.d b/ld/testsuite/ld-i386/lea2c.d
new file mode 100644
index 00000000000..53032ea47ce
--- /dev/null
+++ b/ld/testsuite/ld-i386/lea2c.d
@@ -0,0 +1,14 @@
+#source: lea2.s
+#as: --32 -mrelax-relocations=yes
+#ld: -melf_i386 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/lea3.d b/ld/testsuite/ld-i386/lea3.d
new file mode 100644
index 00000000000..e97eb998033
--- /dev/null
+++ b/ld/testsuite/ld-i386/lea3.d
@@ -0,0 +1,6 @@
+#as: --32 -mrelax-relocations=yes
+#ld: -melf_i386 --defsym foo=0x100 -z separate-code
+#readelf: -x .data
+
+Hex dump of section '\.data':
+  0x08049000 8d050071 fbf7                       ...q..
diff --git a/ld/testsuite/ld-i386/lea3.s b/ld/testsuite/ld-i386/lea3.s
new file mode 100644
index 00000000000..7c7e9655576
--- /dev/null
+++ b/ld/testsuite/ld-i386/lea3.s
@@ -0,0 +1,10 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	nop
+	.size	_start, .-_start
+	.data
+	.byte 0x8d
+	.byte 0x05
+	.long	foo@GOTOFF
diff --git a/ld/testsuite/ld-i386/mov4.s b/ld/testsuite/ld-i386/mov4.s
new file mode 100644
index 00000000000..13544542601
--- /dev/null
+++ b/ld/testsuite/ld-i386/mov4.s
@@ -0,0 +1,11 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	movl	foo@GOT(%ebx), %eax
+	.size	_start, .-_start
+.ifdef __hidden__
+	.hidden foo
+.elseif __protected__ == 1
+	.protected foo
+.endif
diff --git a/ld/testsuite/ld-i386/mov4a.d b/ld/testsuite/ld-i386/mov4a.d
new file mode 100644
index 00000000000..30216379bc8
--- /dev/null
+++ b/ld/testsuite/ld-i386/mov4a.d
@@ -0,0 +1,13 @@
+#source: mov4.s
+#as: --32 -mrelax-relocations=yes
+#ld: -shared -melf_i386 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	8b 83 ([0-9a-f]{2} ){4} *	mov    -0x[a-f0-9]+\(%ebx\),%eax
+#pass
diff --git a/ld/testsuite/ld-i386/mov4b.d b/ld/testsuite/ld-i386/mov4b.d
new file mode 100644
index 00000000000..61a8bbf93b4
--- /dev/null
+++ b/ld/testsuite/ld-i386/mov4b.d
@@ -0,0 +1,13 @@
+#source: mov4.s
+#as: --32 -mrelax-relocations=yes -defsym __hidden__=1
+#ld: -shared -melf_i386 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/mov4c.d b/ld/testsuite/ld-i386/mov4c.d
new file mode 100644
index 00000000000..2fdfb878441
--- /dev/null
+++ b/ld/testsuite/ld-i386/mov4c.d
@@ -0,0 +1,13 @@
+#source: mov4.s
+#as: --32 -mrelax-relocations=yes -defsym __protected__=1
+#ld: -shared -melf_i386 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	c7 c0 00 01 00 00    	mov    \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2.s b/ld/testsuite/ld-x86-64/lea2.s
new file mode 100644
index 00000000000..307712079d6
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2.s
@@ -0,0 +1,11 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	leaq	foo(%rip), %rax
+	.size	_start, .-_start
+.ifdef __hidden__
+	.hidden foo
+.elseif __protected__ == 1
+	.protected foo
+.endif
diff --git a/ld/testsuite/ld-x86-64/lea2a-x32.d b/ld/testsuite/ld-x86-64/lea2a-x32.d
new file mode 100644
index 00000000000..a177c076e12
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2a-x32.d
@@ -0,0 +1,13 @@
+#source: lea2.s
+#as: --x32 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	40 c7 c0 00 01 00 00 	rex mov \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2a.d b/ld/testsuite/ld-x86-64/lea2a.d
new file mode 100644
index 00000000000..afbcc348ee9
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2a.d
@@ -0,0 +1,13 @@
+#source: lea2.s
+#as: --64 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 c7 c0 00 01 00 00 	mov    \$0x100,%rax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2b-x32.d b/ld/testsuite/ld-x86-64/lea2b-x32.d
new file mode 100644
index 00000000000..3273d9ff7dc
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2b-x32.d
@@ -0,0 +1,13 @@
+#source: lea2.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	40 c7 c0 00 01 00 00 	rex mov \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2b.d b/ld/testsuite/ld-x86-64/lea2b.d
new file mode 100644
index 00000000000..f792636731e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2b.d
@@ -0,0 +1,13 @@
+#source: lea2.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 c7 c0 00 01 00 00 	mov    \$0x100,%rax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2c-x32.d b/ld/testsuite/ld-x86-64/lea2c-x32.d
new file mode 100644
index 00000000000..f580f25214c
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2c-x32.d
@@ -0,0 +1,13 @@
+#source: lea2.s
+#as: --x32 -mrelax-relocations=yes --defsym __protected__=1
+#ld: -shared -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	40 c7 c0 00 01 00 00 	rex mov \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2c.d b/ld/testsuite/ld-x86-64/lea2c.d
new file mode 100644
index 00000000000..618f7c27115
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2c.d
@@ -0,0 +1,13 @@
+#source: lea2.s
+#as: --64 -mrelax-relocations=yes --defsym __protected__=1
+#ld: -shared -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 c7 c0 00 01 00 00 	mov    \$0x100,%rax
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea2d-x32.d b/ld/testsuite/ld-x86-64/lea2d-x32.d
new file mode 100644
index 00000000000..b5bc02c6d12
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2d-x32.d
@@ -0,0 +1,4 @@
+#source: lea2.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 --defsym foo=0x100000000
+#error: .*relocation truncated to fit: R_X86_64_PC32 against symbol `foo' defined in \*ABS\* section in .*
diff --git a/ld/testsuite/ld-x86-64/lea2d.d b/ld/testsuite/ld-x86-64/lea2d.d
new file mode 100644
index 00000000000..24dc0c78c80
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2d.d
@@ -0,0 +1,4 @@
+#source: lea2.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 --defsym foo=0x81000000
+#error: .*relocation truncated to fit: R_X86_64_PC32 against symbol `foo' defined in \*ABS\* section in .*
diff --git a/ld/testsuite/ld-x86-64/lea2e-x32.d b/ld/testsuite/ld-x86-64/lea2e-x32.d
new file mode 100644
index 00000000000..23e844d63be
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2e-x32.d
@@ -0,0 +1,4 @@
+#source: lea2.s
+#as: --x32 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf32_x86_64 --defsym foo=0x100000000
+#error: .*relocation truncated to fit: R_X86_64_PC32 against symbol `foo' defined in \*ABS\* section in .*
diff --git a/ld/testsuite/ld-x86-64/lea2e.d b/ld/testsuite/ld-x86-64/lea2e.d
new file mode 100644
index 00000000000..6b8a6216def
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea2e.d
@@ -0,0 +1,4 @@
+#source: lea2.s
+#as: --64 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf_x86_64 --defsym foo=0x81000000
+#error: .*relocation truncated to fit: R_X86_64_PC32 against symbol `foo' defined in \*ABS\* section in .*
diff --git a/ld/testsuite/ld-x86-64/lea3-x32.d b/ld/testsuite/ld-x86-64/lea3-x32.d
new file mode 100644
index 00000000000..b41dea8f821
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea3-x32.d
@@ -0,0 +1,7 @@
+#source: lea3.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 --defsym foo=0x100 -z separate-code
+#readelf: -x .data
+
+Hex dump of section '\.data':
+  0x00401000 8d05faf0 bfff                       ......
diff --git a/ld/testsuite/ld-x86-64/lea3.d b/ld/testsuite/ld-x86-64/lea3.d
new file mode 100644
index 00000000000..fa4336d7300
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea3.d
@@ -0,0 +1,6 @@
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 --defsym foo=0x100 -z separate-code
+#readelf: -x .data
+
+Hex dump of section '\.data':
+  0x00401000 8d05faf0 bfff                       ......
diff --git a/ld/testsuite/ld-x86-64/lea3.s b/ld/testsuite/ld-x86-64/lea3.s
new file mode 100644
index 00000000000..eb9aceef3f3
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea3.s
@@ -0,0 +1,10 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	nop
+	.size	_start, .-_start
+	.data
+	.byte 0x8d
+	.byte 0x05
+	.long	foo - 4 - .
diff --git a/ld/testsuite/ld-x86-64/lea4-x32.d b/ld/testsuite/ld-x86-64/lea4-x32.d
new file mode 100644
index 00000000000..95c20526497
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea4-x32.d
@@ -0,0 +1,13 @@
+#source: lea4.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8d 90 ([0-9a-f]{2} ){4} *	lea    -0x[a-f0-9]+\(%rax\),%rdx
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea4.d b/ld/testsuite/ld-x86-64/lea4.d
new file mode 100644
index 00000000000..6e4476e0945
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea4.d
@@ -0,0 +1,12 @@
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8d 90 ([0-9a-f]{2} ){4} *	lea    -0x[a-f0-9]+\(%rax\),%rdx
+#pass
diff --git a/ld/testsuite/ld-x86-64/lea4.s b/ld/testsuite/ld-x86-64/lea4.s
new file mode 100644
index 00000000000..3620f5015d9
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/lea4.s
@@ -0,0 +1,9 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	.byte 0x48
+	.byte 0x8d
+	.byte 0x90
+	.long	foo - 4 - .
+	.size	_start, .-_start
diff --git a/ld/testsuite/ld-x86-64/mov3.s b/ld/testsuite/ld-x86-64/mov3.s
new file mode 100644
index 00000000000..ad86f14fdce
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3.s
@@ -0,0 +1,11 @@
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	movq	foo@GOTPCREL(%rip), %rax
+	.size	_start, .-_start
+.ifdef __hidden__
+	.hidden foo
+.elseif __protected__ == 1
+	.protected foo
+.endif
diff --git a/ld/testsuite/ld-x86-64/mov3a-x32.d b/ld/testsuite/ld-x86-64/mov3a-x32.d
new file mode 100644
index 00000000000..a73e5e417b8
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3a-x32.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -shared -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.*>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3a.d b/ld/testsuite/ld-x86-64/mov3a.d
new file mode 100644
index 00000000000..06430c5368f
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3a.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --64 -mrelax-relocations=yes
+#ld: -shared -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.*>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3b-x32.d b/ld/testsuite/ld-x86-64/mov3b-x32.d
new file mode 100644
index 00000000000..8bf6684eae6
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3b-x32.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --x32 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	40 c7 c0 00 01 00 00 	rex mov \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3b.d b/ld/testsuite/ld-x86-64/mov3b.d
new file mode 100644
index 00000000000..5ed26cbbfc1
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3b.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --64 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 c7 c0 00 01 00 00 	mov    \$0x100,%rax
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3c-x32.d b/ld/testsuite/ld-x86-64/mov3c-x32.d
new file mode 100644
index 00000000000..9c684e358db
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3c-x32.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -shared -melf32_x86_64 --defsym foo=0x100000000
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.*>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3c.d b/ld/testsuite/ld-x86-64/mov3c.d
new file mode 100644
index 00000000000..ebdfcfbcf7a
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3c.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --64 -mrelax-relocations=yes
+#ld: -shared -melf_x86_64 --defsym foo=0x100000000
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.*>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3d-x32.d b/ld/testsuite/ld-x86-64/mov3d-x32.d
new file mode 100644
index 00000000000..fde0d327966
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3d-x32.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --x32 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf32_x86_64 --defsym foo=0x100000000
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.*>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3d.d b/ld/testsuite/ld-x86-64/mov3d.d
new file mode 100644
index 00000000000..3af4c42953c
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3d.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --64 -mrelax-relocations=yes --defsym __hidden__=1
+#ld: -shared -melf_x86_64 --defsym foo=0x100000000
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 8b 05 ([0-9a-f]{2} ){4} *	mov    0x[a-f0-9]+\(%rip\),%rax        # [a-f0-9]+ <.*>
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3e-x32.d b/ld/testsuite/ld-x86-64/mov3e-x32.d
new file mode 100644
index 00000000000..fe62229784d
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3e-x32.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --x32 -mrelax-relocations=yes --defsym __protected__=1
+#ld: -shared -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	40 c7 c0 00 01 00 00 	rex mov \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3e.d b/ld/testsuite/ld-x86-64/mov3e.d
new file mode 100644
index 00000000000..3531c64d8e4
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3e.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --64 -mrelax-relocations=yes --defsym __protected__=1
+#ld: -shared -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 c7 c0 00 01 00 00 	mov    \$0x100,%rax
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3f-x32.d b/ld/testsuite/ld-x86-64/mov3f-x32.d
new file mode 100644
index 00000000000..5a391ca8714
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3f-x32.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --x32 -mrelax-relocations=yes
+#ld: -melf32_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	40 c7 c0 00 01 00 00 	rex mov \$0x100,%eax
+#pass
diff --git a/ld/testsuite/ld-x86-64/mov3f.d b/ld/testsuite/ld-x86-64/mov3f.d
new file mode 100644
index 00000000000..47d12c116bf
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/mov3f.d
@@ -0,0 +1,13 @@
+#source: mov3.s
+#as: --64 -mrelax-relocations=yes
+#ld: -melf_x86_64 --defsym foo=0x100
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	48 c7 c0 00 01 00 00 	mov    \$0x100,%rax
+#pass
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index a2159c0154c..11493a5e894 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -654,6 +654,20 @@ run_dump_test "lea1i"
 run_dump_test "lea1j"
 run_dump_test "lea1k"
 run_dump_test "lea1l"
+run_dump_test "lea2a"
+run_dump_test "lea2a-x32"
+run_dump_test "lea2b"
+run_dump_test "lea2b-x32"
+run_dump_test "lea2c"
+run_dump_test "lea2c-x32"
+run_dump_test "lea2d"
+run_dump_test "lea2d-x32"
+run_dump_test "lea2e"
+run_dump_test "lea2e-x32"
+run_dump_test "lea3"
+run_dump_test "lea3-x32"
+run_dump_test "lea4"
+run_dump_test "lea4-x32"
 run_dump_test "mov1a"
 run_dump_test "mov1b"
 run_dump_test "mov1c"
@@ -662,6 +676,18 @@ run_dump_test "mov2a"
 run_dump_test "mov2b"
 run_dump_test "mov2c"
 run_dump_test "mov2d"
+run_dump_test "mov3a"
+run_dump_test "mov3a-x32"
+run_dump_test "mov3b"
+run_dump_test "mov3b-x32"
+run_dump_test "mov3c"
+run_dump_test "mov3c-x32"
+run_dump_test "mov3d"
+run_dump_test "mov3d-x32"
+run_dump_test "mov3e"
+run_dump_test "mov3e-x32"
+run_dump_test "mov3f"
+run_dump_test "mov3f-x32"
 run_dump_test "ljmp1"
 run_dump_test "ljmp2"
 run_dump_test "load1a"
-- 
2.49.0



More information about the Binutils mailing list