This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/5] Add R_386_GOT32X support to gas and ld


This patch adds support for the R_386_GOT32X relocation proposed in

https://groups.google.com/forum/#!topic/ia32-abi/GbJJskkid4I

to gas and ld.  It updates gas to generate R_386_GOT32X relocation for
memory operand, foo@GOT[(%reg)].  We must encode "mov foo@GOT, %eax"
with the 0x8b opcode, instead of the 0xb8 opcode, so that it can be
transformed to "lea foo, %eax".  With the locally defined symbol, foo,
we convert

   mov foo@GOT[(%reg1)], %reg2
to
   lea foo[@GOTOFF(%reg1)], %reg2

and convert

   call/jmp *foo@GOT[(%reg)]
to

   nop call foo/jmp foo nop

When PIC is false, convert

   test %reg1, foo@GOT[(%reg2)]
to
   test $foo, %reg1

and convert

binop foo@GOT[(%reg1)], %reg2

to

binop $foo, %reg2

where binop is one of adc, add, and, cmp, or, sbb, sub, xor instructions.

bfd/

	* elf32-i386.c: Include opcode/i386.h.
	(elf_howto_table): Add R_386_GOT32X.
	(R_386_ext2): Replace R_386_IRELATIVE with R_386_GOT32X.
	(elf_i386_reloc_type_lookup): Handle BFD_RELOC_386_GOT32X.
	(need_convert_mov_to_lea): Renamed to ...
	(need_convert_load): This.
	(elf_i386_check_relocs): Handle R_386_GOT32X.  Replace
	need_convert_mov_to_lea with need_convert_load.
	(elf_i386_gc_sweep_hook): Handle R_386_GOT32X.
	(elf_i386_size_dynamic_sections): Likewise.
	(elf_i386_relocate_section): Likewise.
	(elf_i386_convert_mov_to_lea): Renamed to ...
	(elf_i386_convert_load): This.  Replace need_convert_mov_to_lea
	with need_convert_load.  Support R_386_GOT32X transformations.
	* reloc.c (BFD_RELOC_386_GOT32X): New.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

gas/

	* config/tc-i386.c (tc_i386_fix_adjustable): Handle
	BFD_RELOC_386_GOT32X.
	(tc_gen_reloc): Likewise.
	(match_template): Force 0x8b encoding for "mov foo@GOT, %eax".
	(output_disp): Check for "call/jmp *mem", "mov mem, %reg",
	"test %reg, mem" and "binop mem, %reg" where binop is one of
	adc, add, and, cmp, or, sbb, sub, xor instructions.  Set
	fx_tcbit if the REX prefix is generated.  Set fx_tcbit2 if
	BFD_RELOC_386_GOT32X should be generated.
	(i386_validate_fix): Generate BFD_RELOC_386_GOT32X if fx_tcbit2
	is set.

gas/testsuite/

	* gas/i386/got.d: New file.
	* gas/i386/got.s: Likewise.
	* gas/i386/i386.exp: Run got.
	* gas/i386/localpic.d: Replace R_386_GOT32 with R_386_GOT32X.
	* gas/i386/mixed-mode-reloc32.d: Likewise.
	* gas/i386/reloc32.d: Likewise.

include/elf/

	* i386.h (R_386_GOT32X): New relocation.

ld/testsuite/

	* ld-i386/branch1.d: New file.
	* ld-i386/branch1.s: Likewise.
	* ld-i386/call1.d: Likewise.
	* ld-i386/call1.s: Likewise.
	* ld-i386/call2.d: Likewise.
	* ld-i386/call2.s: Likewise.
	* ld-i386/got1.dd: Likewise.
	* ld-i386/got1.out: Likewise.
	* ld-i386/got1a.S: Likewise.
	* ld-i386/got1b.c: Likewise.
	* ld-i386/got1c.c: Likewise.
	* ld-i386/got1d.S: Likewise.
	* ld-i386/jmp1.d: Likewise.
	* ld-i386/jmp1.s: Likewise.
	* ld-i386/jmp2.d: Likewise.
	* ld-i386/jmp2.s: Likewise.
	* ld-i386/load1.d: Likewise.
	* ld-i386/load1.s: Likewise.
	* ld-i386/load2.d: Likewise.
	* ld-i386/load2.s: Likewise.
	* ld-i386/load3.d: Likewise.
	* ld-i386/load3.s: Likewise.
	* ld-i386/load4.s: Likewise.
	* ld-i386/load4a.d: Likewise.
	* ld-i386/load4b.d: Likewise.
	* ld-i386/load5.s: Likewise.
	* ld-i386/load5a.d: Likewise.
	* ld-i386/load5b.d: Likewise.
	* ld-i386/load6.d: Likewise.
	* ld-i386/load6.s: Likewise.
	* ld-i386/i386.exp: Run branch1, call1, call2, jmp1, jmp2,
	load1, load2, load3, load4a, load4b, load5a, load5b and load6
	tests.  Run got1 test.
---
 bfd/bfd-in2.h                               |   1 +
 bfd/elf32-i386.c                            | 357 ++++++++++++++++++++++++----
 bfd/libbfd.h                                |   1 +
 bfd/reloc.c                                 |   2 +
 gas/config/tc-i386.c                        |  77 ++++--
 gas/testsuite/gas/i386/got.d                |  29 +++
 gas/testsuite/gas/i386/got.s                |  29 +++
 gas/testsuite/gas/i386/i386.exp             |   2 +
 gas/testsuite/gas/i386/localpic.d           |   2 +-
 gas/testsuite/gas/i386/mixed-mode-reloc32.d |   6 +-
 gas/testsuite/gas/i386/reloc32.d            |   2 +-
 include/elf/i386.h                          |   2 +
 ld/testsuite/ld-i386/branch1.d              |  17 ++
 ld/testsuite/ld-i386/branch1.s              |  15 ++
 ld/testsuite/ld-i386/call1.d                |   3 +
 ld/testsuite/ld-i386/call1.s                |   9 +
 ld/testsuite/ld-i386/call2.d                |   3 +
 ld/testsuite/ld-i386/call2.s                |   8 +
 ld/testsuite/ld-i386/got1.dd                |  20 ++
 ld/testsuite/ld-i386/got1.out               |   7 +
 ld/testsuite/ld-i386/got1a.S                |  21 ++
 ld/testsuite/ld-i386/got1b.c                |   7 +
 ld/testsuite/ld-i386/got1c.c                |   7 +
 ld/testsuite/ld-i386/got1d.S                |  54 +++++
 ld/testsuite/ld-i386/i386.exp               |  37 +++
 ld/testsuite/ld-i386/jmp1.d                 |   3 +
 ld/testsuite/ld-i386/jmp1.s                 |   9 +
 ld/testsuite/ld-i386/jmp2.d                 |   3 +
 ld/testsuite/ld-i386/jmp2.s                 |   8 +
 ld/testsuite/ld-i386/lea1c.d                |   4 +-
 ld/testsuite/ld-i386/load1.d                |  57 +++++
 ld/testsuite/ld-i386/load1.s                |  55 +++++
 ld/testsuite/ld-i386/load2.d                |   3 +
 ld/testsuite/ld-i386/load2.s                |   8 +
 ld/testsuite/ld-i386/load3.d                |   3 +
 ld/testsuite/ld-i386/load3.s                |   9 +
 ld/testsuite/ld-i386/load4.s                |   9 +
 ld/testsuite/ld-i386/load4a.d               |   4 +
 ld/testsuite/ld-i386/load4b.d               |  13 +
 ld/testsuite/ld-i386/load5.s                |   8 +
 ld/testsuite/ld-i386/load5a.d               |   4 +
 ld/testsuite/ld-i386/load5b.d               |  13 +
 ld/testsuite/ld-i386/load6.d                |  28 +++
 ld/testsuite/ld-i386/load6.s                |  33 +++
 ld/testsuite/ld-i386/plt-main1.rd           |   2 +-
 ld/testsuite/ld-i386/plt-main3.rd           |   2 +-
 ld/testsuite/ld-i386/plt-main4.rd           |   2 +-
 47 files changed, 929 insertions(+), 69 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/got.d
 create mode 100644 gas/testsuite/gas/i386/got.s
 create mode 100644 ld/testsuite/ld-i386/branch1.d
 create mode 100644 ld/testsuite/ld-i386/branch1.s
 create mode 100644 ld/testsuite/ld-i386/call1.d
 create mode 100644 ld/testsuite/ld-i386/call1.s
 create mode 100644 ld/testsuite/ld-i386/call2.d
 create mode 100644 ld/testsuite/ld-i386/call2.s
 create mode 100644 ld/testsuite/ld-i386/got1.dd
 create mode 100644 ld/testsuite/ld-i386/got1.out
 create mode 100644 ld/testsuite/ld-i386/got1a.S
 create mode 100644 ld/testsuite/ld-i386/got1b.c
 create mode 100644 ld/testsuite/ld-i386/got1c.c
 create mode 100644 ld/testsuite/ld-i386/got1d.S
 create mode 100644 ld/testsuite/ld-i386/jmp1.d
 create mode 100644 ld/testsuite/ld-i386/jmp1.s
 create mode 100644 ld/testsuite/ld-i386/jmp2.d
 create mode 100644 ld/testsuite/ld-i386/jmp2.s
 create mode 100644 ld/testsuite/ld-i386/load1.d
 create mode 100644 ld/testsuite/ld-i386/load1.s
 create mode 100644 ld/testsuite/ld-i386/load2.d
 create mode 100644 ld/testsuite/ld-i386/load2.s
 create mode 100644 ld/testsuite/ld-i386/load3.d
 create mode 100644 ld/testsuite/ld-i386/load3.s
 create mode 100644 ld/testsuite/ld-i386/load4.s
 create mode 100644 ld/testsuite/ld-i386/load4a.d
 create mode 100644 ld/testsuite/ld-i386/load4b.d
 create mode 100644 ld/testsuite/ld-i386/load5.s
 create mode 100644 ld/testsuite/ld-i386/load5a.d
 create mode 100644 ld/testsuite/ld-i386/load5b.d
 create mode 100644 ld/testsuite/ld-i386/load6.d
 create mode 100644 ld/testsuite/ld-i386/load6.s

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 60d7e45..ad246c8 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3177,6 +3177,7 @@ instruction.  */
   BFD_RELOC_386_TLS_DESC_CALL,
   BFD_RELOC_386_TLS_DESC,
   BFD_RELOC_386_IRELATIVE,
+  BFD_RELOC_386_GOT32X,
 
 /* x86-64/elf relocations  */
   BFD_RELOC_X86_64_GOT32,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 8c1dadb..f56b39e 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -29,6 +29,7 @@
 #include "objalloc.h"
 #include "hashtab.h"
 #include "dwarf2.h"
+#include "opcode/i386.h"
 
 /* 386 uses REL relocations instead of RELA.  */
 #define USE_REL	1
@@ -146,9 +147,12 @@ static reloc_howto_type elf_howto_table[]=
   HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
 	bfd_elf_generic_reloc, "R_386_IRELATIVE",
 	TRUE, 0xffffffff, 0xffffffff, FALSE),
+  HOWTO(R_386_GOT32X, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
+	bfd_elf_generic_reloc, "R_386_GOT32X",
+	TRUE, 0xffffffff, 0xffffffff, FALSE),
 
   /* Another gap.  */
-#define R_386_ext2 (R_386_IRELATIVE + 1 - R_386_tls_offset)
+#define R_386_ext2 (R_386_GOT32X + 1 - R_386_tls_offset)
 #define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_ext2)
 
 /* GNU extension to record C++ vtable hierarchy.  */
@@ -332,6 +336,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
       TRACE ("BFD_RELOC_386_IRELATIVE");
       return &elf_howto_table[R_386_IRELATIVE - R_386_tls_offset];
 
+    case BFD_RELOC_386_GOT32X:
+      TRACE ("BFD_RELOC_386_GOT32X");
+      return &elf_howto_table[R_386_GOT32X - R_386_tls_offset];
+
     case BFD_RELOC_VTABLE_INHERIT:
       TRACE ("BFD_RELOC_VTABLE_INHERIT");
       return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset];
@@ -1468,7 +1476,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
 
 /* Rename some of the generic section flags to better document how they
    are used here.  */
-#define need_convert_mov_to_lea sec_flg0
+#define need_convert_load sec_flg0
 
 /* Look through the relocs for a section during the first phase, and
    calculate needed space in the global offset table, procedure linkage
@@ -1580,6 +1588,7 @@ elf_i386_check_relocs (bfd *abfd,
 	    case R_386_PC32:
 	    case R_386_PLT32:
 	    case R_386_GOT32:
+	    case R_386_GOT32X:
 	      if (htab->elf.dynobj == NULL)
 		htab->elf.dynobj = abfd;
 	      if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info))
@@ -1637,6 +1646,7 @@ elf_i386_check_relocs (bfd *abfd,
 	  /* Fall through */
 
 	case R_386_GOT32:
+	case R_386_GOT32X:
 	case R_386_TLS_GD:
 	case R_386_TLS_GOTDESC:
 	case R_386_TLS_DESC_CALL:
@@ -1647,7 +1657,10 @@ elf_i386_check_relocs (bfd *abfd,
 	    switch (r_type)
 	      {
 	      default:
-	      case R_386_GOT32: tls_type = GOT_NORMAL; break;
+	      case R_386_GOT32:
+	      case R_386_GOT32X:
+		tls_type = GOT_NORMAL;
+		break;
 	      case R_386_TLS_GD: tls_type = GOT_TLS_GD; break;
 	      case R_386_TLS_GOTDESC:
 	      case R_386_TLS_DESC_CALL:
@@ -1948,9 +1961,9 @@ do_size:
 	    return FALSE;
 	}
 
-      if (r_type == R_386_GOT32
+      if ((r_type == R_386_GOT32 || r_type == R_386_GOT32X)
 	  && (h == NULL || h->type != STT_GNU_IFUNC))
-	sec->need_convert_mov_to_lea = 1;
+	sec->need_convert_load = 1;
     }
 
   return TRUE;
@@ -2074,6 +2087,7 @@ elf_i386_gc_sweep_hook (bfd *abfd,
 	case R_386_TLS_IE:
 	case R_386_TLS_GOTIE:
 	case R_386_GOT32:
+	case R_386_GOT32X:
 	  if (h != NULL)
 	    {
 	      if (h->got.refcount > 0)
@@ -2718,14 +2732,27 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf)
   return TRUE;
 }
 
-/* Convert
-   mov foo@GOT(%reg), %reg
+/* With the local symbol, foo, we convert
+   mov foo@GOT[(%reg1)], %reg2
+   to
+   lea foo[@GOTOFF(%reg1)], %reg2
+   and convert
+   call/jmp *foo@GOT[(%reg)]
    to
-   lea foo@GOTOFF(%reg), %reg
-   with the local symbol, foo.  */
+   nop call foo/jmp foo nop
+   When PIC is false, convert
+   test %reg1, foo@GOT[(%reg2)]
+   to
+   test $foo, %reg1
+   and convert
+   binop foo@GOT[(%reg1)], %reg2
+   to
+   binop $foo, %reg2
+   where binop is one of adc, add, and, cmp, or, sbb, sub, xor
+   instructions.  */
 
 static bfd_boolean
-elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
+elf_i386_convert_load (bfd *abfd, asection *sec,
 			     struct bfd_link_info *link_info)
 {
   Elf_Internal_Shdr *symtab_hdr;
@@ -2743,7 +2770,7 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
 
   /* Nothing to do if there is no need or no output.  */
   if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC)
-      || sec->need_convert_mov_to_lea == 0
+      || sec->need_convert_load == 0
       || bfd_is_abs_section (sec->output_section))
     return TRUE;
 
@@ -2777,32 +2804,92 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
       unsigned int r_symndx = ELF32_R_SYM (irel->r_info);
       unsigned int indx;
       struct elf_link_hash_entry *h;
+      unsigned int opcode;
+      unsigned int modrm;
+      bfd_vma roff;
+      bfd_boolean baseless;
+      Elf_Internal_Sym *isym;
+      unsigned int addend;
+      unsigned int nop;
+      bfd_vma nop_offset;
 
-      if (r_type != R_386_GOT32)
+      if (r_type != R_386_GOT32 && r_type != R_386_GOT32X)
 	continue;
 
-      /* Get the symbol referred to by the reloc.  */
-      if (r_symndx < symtab_hdr->sh_info)
+      roff = irel->r_offset;
+      if (roff < 2)
+	continue;
+
+      modrm = bfd_get_8 (abfd, contents + roff - 1);
+      baseless = (modrm & 0xc7) == 0x5;
+
+      if (r_type == R_386_GOT32X
+	  && baseless
+	  && bfd_link_pic (link_info))
 	{
-	  Elf_Internal_Sym *isym;
+	  /* For PIC, disallow R_386_GOT32X without a base register
+	     since we don't know what the GOT base is.   Allow
+	     R_386_GOT32 for existing object files.  */
+	  const char *name;
+
+	  if (r_symndx < symtab_hdr->sh_info)
+	    {
+	      isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd,
+					    r_symndx);
+	      name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
+	    }
+	  else
+	    {
+	      indx = r_symndx - symtab_hdr->sh_info;
+	      h = elf_sym_hashes (abfd)[indx];
+	      BFD_ASSERT (h != NULL);
+	      name = h->root.root.string;
+	    }
+
+	  (*_bfd_error_handler)
+	    (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base register can not be used when making a shared object"),
+	     abfd, name);
+	  goto error_return;
+	}
+
+      opcode = bfd_get_8 (abfd, contents + roff - 2);
+
+      /* It is OK to convert mov to lea.  */
+      if (opcode != 0x8b)
+	{
+	  /* Only convert R_386_GOT32X relocation for call, jmp or
+	     one of adc, add, and, cmp, or, sbb, sub, test, xor
+	     instructions.  */
+	  if (r_type != R_386_GOT32X)
+	    continue;
+
+	  /* It is OK to convert indirect branch to direct branch.  It
+	     is OK to convert adc, add, and, cmp, or, sbb, sub, test,
+	     xor only when PIC is false.   */
+	  if (opcode != 0xff && bfd_link_pic (link_info))
+	    continue;
+	}
 
+      /* Try to convert R_386_GOT32 and R_386_GOT32X.  Get the symbol
+	 referred to by the reloc.  */
+      if (r_symndx < symtab_hdr->sh_info)
+	{
 	  isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 					abfd, r_symndx);
 
-	  /* STT_GNU_IFUNC must keep R_386_GOT32 relocation.  */
-	  if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC
-	      && irel->r_offset >= 2
-	      && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
-	    {
-	      bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2);
-	      irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF);
-	      if (local_got_refcounts != NULL
-		  && local_got_refcounts[r_symndx] > 0)
-		local_got_refcounts[r_symndx] -= 1;
-	      changed_contents = TRUE;
-	      changed_relocs = TRUE;
-	    }
-	  continue;
+	  /* STT_GNU_IFUNC must keep GOT32 relocations.  */
+	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+	    continue;
+
+	  h = NULL;
+	  if (opcode == 0x0ff)
+	    /* Convert "call/jmp *foo@GOT[(%reg)]".  */
+	    goto convert_branch;
+	  else
+	    /* Convert "mov foo@GOT[(%reg1)], %reg2",
+	       "test %reg1, foo@GOT(%reg2)" and
+	       "binop foo@GOT[(%reg1)], %reg2". */
+	    goto convert_load;
 	}
 
       indx = r_symndx - symtab_hdr->sh_info;
@@ -2813,22 +2900,147 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec,
 	     || h->root.type == bfd_link_hash_warning)
 	h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
-      /* STT_GNU_IFUNC must keep R_386_GOT32 relocation.  We also avoid
-	 optimizing _DYNAMIC since ld.so may use its link-time address.  */
-      if ((h->root.type == bfd_link_hash_defined
-	   || h->root.type == bfd_link_hash_defweak)
-	  && h->type != STT_GNU_IFUNC
-	  && h != htab->elf.hdynamic
-	  && SYMBOL_REFERENCES_LOCAL (link_info, h)
-	  && irel->r_offset >= 2
-	  && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b)
+      /* STT_GNU_IFUNC must keep GOT32 relocations.  */
+      if (h->type == STT_GNU_IFUNC)
+	continue;
+
+      if (opcode == 0xff)
+	{
+	  /* We have "call/jmp *foo@GOT[(%reg)]".  */
+	  if ((h->root.type == bfd_link_hash_defined
+	       || h->root.type == bfd_link_hash_defweak)
+	      && SYMBOL_REFERENCES_LOCAL (link_info, h))
+	    {
+	      /* The function is locally defined.   */
+convert_branch:
+	      addend = bfd_get_32 (abfd, contents + roff);
+	      /* Addend for R_386_GOT32X relocation must be 0.  */
+	      if (addend != 0)
+		continue;
+
+	      /* Convert R_386_GOT32X to R_386_PC32.  */
+	      if (modrm == 0x15 || (modrm & 0xf8) == 0x90)
+		{
+		  /* Convert to "nop call foo".  ADDR_PREFIX_OPCODE
+		     is a nop prefix.  */
+		  modrm = 0xe8;
+		  nop = ADDR_PREFIX_OPCODE;
+		  nop_offset = roff - 2;
+		}
+	      else
+		{
+		  /* Convert to "jmp foo nop".  */
+		  modrm = 0xe9;
+		  nop = NOP_OPCODE;
+		  nop_offset = roff + 3;
+		  irel->r_offset -= 1;
+		}
+
+	      bfd_put_8 (abfd, nop, contents + nop_offset);
+	      bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1);
+	      /* When converting to PC-relative relocation, we
+		 need to adjust addend by -4.  */
+	      bfd_put_32 (abfd, -4, contents + irel->r_offset);
+	      irel->r_info = ELF32_R_INFO (r_symndx, R_386_PC32);
+
+	      if (h)
+		{
+		  if (h->got.refcount > 0)
+		    h->got.refcount -= 1;
+		}
+	      else
+		{
+		  if (local_got_refcounts != NULL
+		      && local_got_refcounts[r_symndx] > 0)
+		    local_got_refcounts[r_symndx] -= 1;
+		}
+
+	      changed_contents = TRUE;
+	      changed_relocs = TRUE;
+	    }
+	}
+      else
 	{
-	  bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2);
-	  irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF);
-	  if (h->got.refcount > 0)
-	    h->got.refcount -= 1;
-	  changed_contents = TRUE;
-	  changed_relocs = TRUE;
+	  /* We have "mov foo@GOT[(%re1g)], %reg2",
+	     "test %reg1, foo@GOT(%reg2)" and
+	     "binop foo@GOT[(%reg1)], %reg2".
+
+	     Avoid optimizing _DYNAMIC since ld.so may use its
+	     link-time address.  */
+	  if (h == htab->elf.hdynamic)
+	    continue;
+
+	  if ((h->root.type == bfd_link_hash_defined
+	       || h->root.type == bfd_link_hash_defweak)
+	      && SYMBOL_REFERENCES_LOCAL (link_info, h))
+	    {
+convert_load:
+	      if (opcode == 0x8b)
+		{
+		  /* Convert "mov foo@GOT(%reg1), %reg2" to
+		     "lea foo@GOTOFF(%reg1), %reg2".  */
+		  if (r_type == R_386_GOT32X
+		      && (baseless || !bfd_link_pic (link_info)))
+		    {
+		      r_type = R_386_32;
+		      /* For R_386_32, convert
+			 "lea foo@GOTOFF(%reg1), %reg2" to
+			 "lea foo@GOT, %reg2".  */
+		      if (!baseless)
+			{
+			  modrm = 0x5 | (modrm & 0x38);
+			  bfd_put_8 (abfd, modrm, contents + roff - 1);
+			}
+		    }
+		  else
+		    r_type = R_386_GOTOFF;
+		  opcode = 0x8d;
+		}
+	      else
+		{
+		  /* Addend for R_386_GOT32X relocation must be 0.  */
+		  addend = bfd_get_32 (abfd, contents + roff);
+		  if (addend != 0)
+		    continue;
+
+		  if (opcode == 0x85)
+		    {
+		      /* Convert "test %reg1, foo@GOT(%reg2)" to
+			 "test $foo, %reg1".  */
+		      modrm = 0xc0 | (modrm & 0x38) >> 3;
+		      opcode = 0xf7;
+		    }
+		  else
+		    {
+		      /* Convert "binop foo@GOT(%reg1), %reg2" to
+			 "binop $foo, %reg2".  */
+		      modrm = (0xc0
+			       | (modrm & 0x38) >> 3
+			       | (opcode & 0x3c));
+		      opcode = 0x81;
+		    }
+		  bfd_put_8 (abfd, modrm, contents + roff - 1);
+		  r_type = R_386_32;
+		}
+
+	      bfd_put_8 (abfd, opcode, contents + roff - 2);
+	      irel->r_info = ELF32_R_INFO (r_symndx, r_type);
+
+	      if (h)
+		{
+		  if (h->got.refcount > 0)
+		    h->got.refcount -= 1;
+		}
+	      else
+		{
+		  if (local_got_refcounts != NULL
+		      && local_got_refcounts[r_symndx] > 0)
+		    local_got_refcounts[r_symndx] -= 1;
+		}
+
+	      changed_contents = TRUE;
+	      changed_relocs = TRUE;
+	    }
 	}
     }
 
@@ -2914,7 +3126,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
 	{
 	  struct elf_dyn_relocs *p;
 
-	  if (!elf_i386_convert_mov_to_lea (ibfd, s, info))
+	  if (!elf_i386_convert_load (ibfd, s, info))
 	    return FALSE;
 
 	  for (p = ((struct elf_dyn_relocs *)
@@ -3664,6 +3876,7 @@ elf_i386_relocate_section (bfd *output_bfd,
 	      goto do_relocation;
 
 	    case R_386_GOT32:
+	    case R_386_GOT32X:
 	      base_got = htab->elf.sgot;
 	      off = h->got.offset;
 
@@ -3741,7 +3954,61 @@ elf_i386_relocate_section (bfd *output_bfd,
       eh = (struct elf_i386_link_hash_entry *) h;
       switch (r_type)
 	{
+	case R_386_GOT32X:
+	  /* Avoid optimizing _DYNAMIC since ld.so may use its
+	     link-time address.  */
+	  if (h == htab->elf.hdynamic)
+	    goto r_386_got32;
+
+	  if (bfd_link_pic (info))
+	    {
+	      /* It is OK to convert mov to lea and convert indirect
+		 branch to direct branch.  It is OK to convert adc,
+		 add, and, cmp, or, sbb, sub, test, xor only when PIC
+		 is false.   */
+	      unsigned int opcode;
+	      opcode = bfd_get_8 (abfd, contents + rel->r_offset - 2);
+	      if (opcode != 0x8b && opcode != 0xff)
+		goto r_386_got32;
+	    }
+
+	  /* Resolve "mov GOT[(%reg)], %reg",
+	     "call/jmp *GOT[(%reg)]", "test %reg, foo@GOT[(%reg)]"
+	     and "binop foo@GOT[(%reg)], %reg".  */
+	  if (h == NULL
+	      || (h->plt.offset == (bfd_vma) -1
+		  && h->got.offset == (bfd_vma) -1)
+	      || htab->elf.sgotplt == NULL)
+	    abort ();
+
+	  offplt = (htab->elf.sgotplt->output_section->vma
+		    + htab->elf.sgotplt->output_offset);
+
+	  /* It is relative to .got.plt section.  */
+	  if (h->got.offset != (bfd_vma) -1)
+	    /* Use GOT entry.  */
+	    relocation = (htab->elf.sgot->output_section->vma
+			  + htab->elf.sgot->output_offset
+			  + h->got.offset - offplt);
+	  else
+	    /* Use GOTPLT entry.  */
+	    relocation = (h->plt.offset / plt_entry_size - 1 + 3) * 4;
+
+	  if (!bfd_link_pic (info))
+	    {
+	      /* If not PIC, add the .got.plt section address for
+		 baseless adressing.  */
+	      unsigned int modrm;
+	      modrm = bfd_get_8 (abfd, contents + rel->r_offset - 1);
+	      if ((modrm & 0xc7) == 0x5)
+		relocation += offplt;
+	    }
+
+	  unresolved_reloc = FALSE;
+	  break;
+
 	case R_386_GOT32:
+r_386_got32:
 	  /* Relocation is to the entry for this symbol in the global
 	     offset table.  */
 	  if (htab->elf.sgot == NULL)
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 9ae9ba2..3bf1400 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1292,6 +1292,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_386_TLS_DESC_CALL",
   "BFD_RELOC_386_TLS_DESC",
   "BFD_RELOC_386_IRELATIVE",
+  "BFD_RELOC_386_GOT32X",
   "BFD_RELOC_X86_64_GOT32",
   "BFD_RELOC_X86_64_PLT32",
   "BFD_RELOC_X86_64_COPY",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 886c63e..c6e2807 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2676,6 +2676,8 @@ ENUMX
   BFD_RELOC_386_TLS_DESC
 ENUMX
   BFD_RELOC_386_IRELATIVE
+ENUMX
+  BFD_RELOC_386_GOT32X
 ENUMDOC
   i386/elf relocations
 
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index b5c27ee..dd1a41b 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -2928,6 +2928,7 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED)
       || fixP->fx_r_type == BFD_RELOC_386_GOTOFF
       || fixP->fx_r_type == BFD_RELOC_386_PLT32
       || fixP->fx_r_type == BFD_RELOC_386_GOT32
+      || fixP->fx_r_type == BFD_RELOC_386_GOT32X
       || fixP->fx_r_type == BFD_RELOC_386_TLS_GD
       || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM
       || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32
@@ -4791,6 +4792,10 @@ match_template (void)
 	    }
 	  }
 
+      /* Force 0x8b encoding for "mov foo@GOT, %eax".  */
+      if (i.reloc[0] == BFD_RELOC_386_GOT32 && t->base_opcode == 0xa0)
+	continue;
+
       /* We check register size if needed.  */
       check_register = t->opcode_modifier.checkregsize;
       overlap0 = operand_type_and (i.types[0], operand_types[0]);
@@ -7157,6 +7162,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 	      int size = disp_size (n);
 	      int sign = i.types[n].bitfield.disp32s;
 	      int pcrel = (i.flags[n] & Operand_PCrel) != 0;
+	      fixS *fixP;
 
 	      /* We can't have 8 bit displacement here.  */
 	      gas_assert (!i.types[n].bitfield.disp8);
@@ -7225,8 +7231,34 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 		       insn, and that is taken care of in other code.  */
 		    reloc_type = BFD_RELOC_X86_64_GOTPC32;
 		}
-	      fix_new_exp (frag_now, p - frag_now->fr_literal, size,
-			   i.op[n].disps, pcrel, reloc_type);
+	      fixP = fix_new_exp (frag_now, p - frag_now->fr_literal,
+				  size, i.op[n].disps, pcrel,
+				  reloc_type);
+	      /* Check for "call/jmp *mem", "mov mem, %reg",
+		 "test %reg, mem" and "binop mem, %reg" where binop
+		 is one of adc, add, and, cmp, or, sbb, sub, xor
+		 instructions.  */
+	      if ((i.rm.mode == 2
+		   || (i.rm.mode == 0 && i.rm.regmem == 5))
+		  && ((i.operands == 1
+		       && i.tm.base_opcode == 0xff
+		       && (i.rm.reg == 2 || i.rm.reg == 4))
+		      || (i.operands == 2
+			  && (i.tm.base_opcode == 0x8b
+			      || i.tm.base_opcode == 0x85
+			      || (i.tm.base_opcode & 0xc7) == 0x03))))
+		{
+		  if (object_64bit)
+		    {
+		      fixP->fx_tcbit = i.rex != 0;
+		      if (i.base_reg
+			  && (i.base_reg->reg_num == RegRip
+			      || i.base_reg->reg_num == RegEip))
+		      fixP->fx_tcbit2 = 1;
+		    }
+		  else
+		    fixP->fx_tcbit2 = 1;
+		}
 	    }
 	}
     }
@@ -10321,23 +10353,39 @@ s_bss (int ignore ATTRIBUTE_UNUSED)
 void
 i386_validate_fix (fixS *fixp)
 {
-  if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol)
+  if (fixp->fx_subsy)
     {
-      if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
-	{
-	  if (!object_64bit)
-	    abort ();
-	  fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
-	}
-      else
+      if (fixp->fx_subsy == GOT_symbol)
 	{
-	  if (!object_64bit)
-	    fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+	  if (fixp->fx_r_type == BFD_RELOC_32_PCREL)
+	    {
+	      if (!object_64bit)
+		abort ();
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+	      if (fixp->fx_tcbit2)
+		fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
+	      else
+#endif
+		fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL;
+	    }
 	  else
-	    fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
+	    {
+	      if (!object_64bit)
+		fixp->fx_r_type = BFD_RELOC_386_GOTOFF;
+	      else
+		fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64;
+	    }
+	  fixp->fx_subsy = 0;
 	}
-      fixp->fx_subsy = 0;
     }
+#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
+  else if (!object_64bit)
+    {
+      if (fixp->fx_r_type == BFD_RELOC_386_GOT32
+	  && fixp->fx_tcbit2)
+	fixp->fx_r_type = BFD_RELOC_386_GOT32X;
+    }
+#endif
 }
 
 arelent *
@@ -10373,6 +10421,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
     case BFD_RELOC_X86_64_GOTPCREL:
     case BFD_RELOC_386_PLT32:
     case BFD_RELOC_386_GOT32:
+    case BFD_RELOC_386_GOT32X:
     case BFD_RELOC_386_GOTOFF:
     case BFD_RELOC_386_GOTPC:
     case BFD_RELOC_386_TLS_GD:
diff --git a/gas/testsuite/gas/i386/got.d b/gas/testsuite/gas/i386/got.d
new file mode 100644
index 0000000..f76ca47
--- /dev/null
+++ b/gas/testsuite/gas/i386/got.d
@@ -0,0 +1,29 @@
+#objdump: -dwr
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+0+ <_start>:
+[ 	]*[a-f0-9]+:	b8 00 00 00 00       	mov    \$0x0,%eax	1: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	8b 05 00 00 00 00    	mov    0x0,%eax	7: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	8b 80 00 00 00 00    	mov    0x0\(%eax\),%eax	d: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	05 00 00 00 00       	add    \$0x0,%eax	12: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	03 05 00 00 00 00    	add    0x0,%eax	18: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	03 80 00 00 00 00    	add    0x0\(%eax\),%eax	1e: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff 15 00 00 00 00    	call   \*0x0	24: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff 90 00 00 00 00    	call   \*0x0\(%eax\)	2a: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff 25 00 00 00 00    	jmp    \*0x0	30: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff a0 00 00 00 00    	jmp    \*0x0\(%eax\)	36: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	b8 00 00 00 00       	mov    \$0x0,%eax	3b: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	8b 05 00 00 00 00    	mov    0x0,%eax	41: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	8b 80 00 00 00 00    	mov    0x0\(%eax\),%eax	47: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	05 00 00 00 00       	add    \$0x0,%eax	4c: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	03 05 00 00 00 00    	add    0x0,%eax	52: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	03 80 00 00 00 00    	add    0x0\(%eax\),%eax	58: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff 90 00 00 00 00    	call   \*0x0\(%eax\)	5e: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff 15 00 00 00 00    	call   \*0x0	64: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff a0 00 00 00 00    	jmp    \*0x0\(%eax\)	6a: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	ff 25 00 00 00 00    	jmp    \*0x0	70: R_386_GOT32X	foo
+#pass
diff --git a/gas/testsuite/gas/i386/got.s b/gas/testsuite/gas/i386/got.s
new file mode 100644
index 0000000..10fa881
--- /dev/null
+++ b/gas/testsuite/gas/i386/got.s
@@ -0,0 +1,29 @@
+	.text
+_start:
+	movl	$foo@GOT, %eax
+	movl	foo@GOT, %eax
+	movl	foo@GOT(%eax), %eax
+
+	addl	$foo@GOT, %eax
+	addl	foo@GOT, %eax
+	addl	foo@GOT(%eax), %eax
+
+	call	*foo@GOT
+	call	*foo@GOT(%eax)
+	jmp	*foo@GOT
+	jmp	*foo@GOT(%eax)
+
+	.intel_syntax noprefix
+
+	mov	eax, offset foo@got
+	mov	eax, DWORD PTR [foo@GOT]
+	mov	eax, DWORD PTR [eax + foo@GOT]
+
+	add	eax, offset foo@got
+	add	eax, DWORD PTR [foo@GOT]
+	add	eax, DWORD PTR [eax + foo@GOT]
+
+	call	DWORD PTR [eax + foo@GOT]
+	call	DWORD PTR [foo@GOT]
+	jmp	DWORD PTR [eax + foo@GOT]
+	jmp	DWORD PTR [foo@GOT]
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index f59b598..8c374f2 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -404,6 +404,8 @@ if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
 	run_dump_test "relax-3"
 	run_dump_test "relax-4"
 
+	run_dump_test "got"
+
 	if {![istarget "*-*-nacl*"]} then {
 	    run_dump_test "iamcu-1"
 	    run_dump_test "iamcu-2"
diff --git a/gas/testsuite/gas/i386/localpic.d b/gas/testsuite/gas/i386/localpic.d
index 93ac871..04fb5ce 100644
--- a/gas/testsuite/gas/i386/localpic.d
+++ b/gas/testsuite/gas/i386/localpic.d
@@ -3,7 +3,7 @@
 
 Relocation section '.rel.text' at offset 0x[0-9a-f]+ contains 1 entries:
  Offset     Info    Type            Sym.Value  Sym. Name
-[0-9a-f]+ +[0-9a-f]+ R_386_GOT32 +[0-9a-f]+ +foo
+[0-9a-f]+ +[0-9a-f]+ R_386_GOT32X +[0-9a-f]+ +foo
 #...
  +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +foo
 #pass
diff --git a/gas/testsuite/gas/i386/mixed-mode-reloc32.d b/gas/testsuite/gas/i386/mixed-mode-reloc32.d
index 6bc52f7..9affc36 100644
--- a/gas/testsuite/gas/i386/mixed-mode-reloc32.d
+++ b/gas/testsuite/gas/i386/mixed-mode-reloc32.d
@@ -6,9 +6,9 @@
 
 RELOCATION RECORDS FOR \[.text\]:
 OFFSET[ 	]+TYPE[ 	]+VALUE[ 	]*
-[0-9a-f]+[ 	]+R_386_GOT32[ 	]+xtrn[ 	]*
+[0-9a-f]+[ 	]+R_386_GOT32X[ 	]+xtrn[ 	]*
 [0-9a-f]+[ 	]+R_386_PLT32[ 	]+xtrn[ 	]*
-[0-9a-f]+[ 	]+R_386_GOT32[ 	]+xtrn[ 	]*
+[0-9a-f]+[ 	]+R_386_GOT32X[ 	]+xtrn[ 	]*
 [0-9a-f]+[ 	]+R_386_PLT32[ 	]+xtrn[ 	]*
-[0-9a-f]+[ 	]+R_386_GOT32[ 	]+xtrn[ 	]*
+[0-9a-f]+[ 	]+R_386_GOT32X[ 	]+xtrn[ 	]*
 [0-9a-f]+[ 	]+R_386_PLT32[ 	]+xtrn[ 	]*
diff --git a/gas/testsuite/gas/i386/reloc32.d b/gas/testsuite/gas/i386/reloc32.d
index cbd71d6..45c9cd2 100644
--- a/gas/testsuite/gas/i386/reloc32.d
+++ b/gas/testsuite/gas/i386/reloc32.d
@@ -18,7 +18,7 @@ Disassembly of section \.text:
 .*[ 	]+R_386_PC32[ 	]+xtrn
 .*[ 	]+R_386_PC8[ 	]+xtrn
 .*[ 	]+R_386_GOT32[ 	]+xtrn
-.*[ 	]+R_386_GOT32[ 	]+xtrn
+.*[ 	]+R_386_GOT32X[ 	]+xtrn
 .*[ 	]+R_386_GOTOFF[ 	]+xtrn
 .*[ 	]+R_386_GOTOFF[ 	]+xtrn
 .*[ 	]+R_386_GOTPC[ 	]+_GLOBAL_OFFSET_TABLE_
diff --git a/include/elf/i386.h b/include/elf/i386.h
index 08c9455..dea65f4 100644
--- a/include/elf/i386.h
+++ b/include/elf/i386.h
@@ -66,6 +66,8 @@ START_RELOC_NUMBERS (elf_i386_reloc_type)
      RELOC_NUMBER (R_386_TLS_DESC_CALL,40)
      RELOC_NUMBER (R_386_TLS_DESC,     41)
      RELOC_NUMBER (R_386_IRELATIVE,    42) /* Adjust indirectly by program base */
+     /* Load from 32 bit GOT entry, relaxable.  */
+     RELOC_NUMBER (R_386_GOT32X,       43)
 
      /* Used by Intel.  */
      RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200)
diff --git a/ld/testsuite/ld-i386/branch1.d b/ld/testsuite/ld-i386/branch1.d
new file mode 100644
index 0000000..a078f1d
--- /dev/null
+++ b/ld/testsuite/ld-i386/branch1.d
@@ -0,0 +1,17 @@
+#as: --32
+#ld: -melf_i386
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	67 e8 ([0-9a-f]{2} ){4} *	addr16 call +[a-f0-9]+ <foo>
+[ 	]*[a-f0-9]+:	67 e8 ([0-9a-f]{2} ){4} *	addr16 call +[a-f0-9]+ <bar>
+[ 	]*[a-f0-9]+:	e9 ([0-9a-f]{2} ){4} *	jmp +[a-f0-9]+ <foo>
+[ 	]*[a-f0-9]+:	90                   	nop
+[ 	]*[a-f0-9]+:	e9 ([0-9a-f]{2} ){4} *	jmp +[a-f0-9]+ <bar>
+[ 	]*[a-f0-9]+:	90                   	nop
+#pass
diff --git a/ld/testsuite/ld-i386/branch1.s b/ld/testsuite/ld-i386/branch1.s
new file mode 100644
index 0000000..0ccf5cf
--- /dev/null
+++ b/ld/testsuite/ld-i386/branch1.s
@@ -0,0 +1,15 @@
+	.text
+	.type	bar, @function
+bar:
+	ret
+	.globl	foo
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	call	*foo@GOT
+	call	*bar@GOT
+	jmp	*foo@GOT
+	jmp	*bar@GOT
diff --git a/ld/testsuite/ld-i386/call1.d b/ld/testsuite/ld-i386/call1.d
new file mode 100644
index 0000000..69383b2
--- /dev/null
+++ b/ld/testsuite/ld-i386/call1.d
@@ -0,0 +1,3 @@
+#as: --32
+#ld: -shared -melf_i386
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/call1.s b/ld/testsuite/ld-i386/call1.s
new file mode 100644
index 0000000..ce003c8
--- /dev/null
+++ b/ld/testsuite/ld-i386/call1.s
@@ -0,0 +1,9 @@
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	call	*foo@GOT
diff --git a/ld/testsuite/ld-i386/call2.d b/ld/testsuite/ld-i386/call2.d
new file mode 100644
index 0000000..69383b2
--- /dev/null
+++ b/ld/testsuite/ld-i386/call2.d
@@ -0,0 +1,3 @@
+#as: --32
+#ld: -shared -melf_i386
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/call2.s b/ld/testsuite/ld-i386/call2.s
new file mode 100644
index 0000000..57cd88f
--- /dev/null
+++ b/ld/testsuite/ld-i386/call2.s
@@ -0,0 +1,8 @@
+	.text
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	call	*foo@GOT
diff --git a/ld/testsuite/ld-i386/got1.dd b/ld/testsuite/ld-i386/got1.dd
new file mode 100644
index 0000000..e46153d
--- /dev/null
+++ b/ld/testsuite/ld-i386/got1.dd
@@ -0,0 +1,20 @@
+#...
+[a-f0-9]+ <main>:
+[ 	]*[a-f0-9]+:	83 ec 0c             	sub    \$0xc,%esp
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	addr16 call [a-f0-9]+ <foo>
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	call   \*0x[a-f0-9]+
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	call   \*0x[a-f0-9]+
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	lea   *0x[a-f0-9]+,%eax
+[ 	]*[a-f0-9]+:	ff d0                	call   \*%eax
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	mov   *0x[a-f0-9]+,%eax
+[ 	]*[a-f0-9]+:	ff d0                	call   \*%eax
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	mov   *0x[a-f0-9]+,%eax
+[ 	]*[a-f0-9]+:	ff d0                	call   \*%eax
+[ 	]*[a-f0-9]+:	[ a-f0-9]+    	lea   *0x[a-f0-9]+,%ecx
+[ 	]*[a-f0-9]+:	ff d1                	call   \*%ecx
+[ 	]*[a-f0-9]+:	83 ec 0c             	sub    \$0xc,%esp
+[ 	]*[a-f0-9]+:	6a 00                	push   \$0x0
+[ 	]*[a-f0-9]+:	6a 00                	push   \$0x0
+[ 	]*[a-f0-9]+:	[ a-f0-9]+       	jmp    [a-f0-9]+ <myexit>
+[ 	]*[a-f0-9]+:	90                   	nop
+#pass
diff --git a/ld/testsuite/ld-i386/got1.out b/ld/testsuite/ld-i386/got1.out
new file mode 100644
index 0000000..99d4f7f
--- /dev/null
+++ b/ld/testsuite/ld-i386/got1.out
@@ -0,0 +1,7 @@
+foo
+bar
+plt
+foo
+bar
+plt
+foo
diff --git a/ld/testsuite/ld-i386/got1a.S b/ld/testsuite/ld-i386/got1a.S
new file mode 100644
index 0000000..f3d5330
--- /dev/null
+++ b/ld/testsuite/ld-i386/got1a.S
@@ -0,0 +1,21 @@
+	.text
+	.globl	main
+	.type	main, @function
+main:
+	subl	$12, %esp
+	call	*foo@GOT
+	call	*bar@GOT
+	call	*plt@GOT
+	movl	foo@GOT, %eax
+	call	*%eax
+	movl	bar@GOT, %eax
+	call	*%eax
+	movl	plt@GOT, %eax
+	call	*%eax
+	movl	foo@GOT(%ebx), %ecx
+	call	*%ecx
+	subl	$12, %esp
+	pushl	$0
+	pushl	$0	# Push a dummy return address onto stack.
+	jmp	*myexit@GOT
+	.size	main, .-main
diff --git a/ld/testsuite/ld-i386/got1b.c b/ld/testsuite/ld-i386/got1b.c
new file mode 100644
index 0000000..cf0c78e
--- /dev/null
+++ b/ld/testsuite/ld-i386/got1b.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+foo (void)
+{
+  printf ("%s\n", __FUNCTION__);
+}
diff --git a/ld/testsuite/ld-i386/got1c.c b/ld/testsuite/ld-i386/got1c.c
new file mode 100644
index 0000000..05f5fc2
--- /dev/null
+++ b/ld/testsuite/ld-i386/got1c.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+
+void
+myexit (int status)
+{
+  exit (status);
+}
diff --git a/ld/testsuite/ld-i386/got1d.S b/ld/testsuite/ld-i386/got1d.S
new file mode 100644
index 0000000..a6d51c6
--- /dev/null
+++ b/ld/testsuite/ld-i386/got1d.S
@@ -0,0 +1,54 @@
+	.globl	bar
+	.type	bar, @function
+bar:
+	pushl	%ebx
+	call	__x86.get_pc_thunk.cx
+	addl	$_GLOBAL_OFFSET_TABLE_, %ecx
+	subl	$24, %esp
+	leal	__FUNCTION__.1862@GOTOFF(%ecx), %eax
+	movl	%eax, (%esp)
+	call	*puts@GOT(%ecx)
+	addl	$24, %esp
+	popl	%ebx
+	ret
+	.size	bar, .-bar
+
+	.globl	plt
+	.type	plt, @function
+plt:
+	pushl	%esi
+	pushl	%ebx
+	call	__x86.get_pc_thunk.bx
+1:
+	addl	$_GLOBAL_OFFSET_TABLE_, %ebx
+	subl	$20, %esp
+	leal	__FUNCTION__.1866@GOTOFF(%ebx), %esi
+	movl	%esi, (%esp)
+	call	*puts@GOT(%ebx)
+	addl	$20, %esp
+	popl	%ebx
+	popl	%esi
+	ret
+	.section	.rodata
+	.type	__FUNCTION__.1866, @object
+	.size	__FUNCTION__.1866, 4
+__FUNCTION__.1866:
+	.string	"plt"
+	.type	__FUNCTION__.1862, @object
+	.size	__FUNCTION__.1862, 4
+__FUNCTION__.1862:
+	.string	"bar"
+	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
+	.globl	__x86.get_pc_thunk.bx
+	.hidden	__x86.get_pc_thunk.bx
+	.type	__x86.get_pc_thunk.bx, @function
+__x86.get_pc_thunk.bx:
+	movl	(%esp), %ebx
+	ret
+	.section	.text.__x86.get_pc_thunk.cx,"axG",@progbits,__x86.get_pc_thunk.cx,comdat
+	.globl	__x86.get_pc_thunk.cx
+	.hidden	__x86.get_pc_thunk.cx
+	.type	__x86.get_pc_thunk.cx, @function
+__x86.get_pc_thunk.cx:
+	movl	(%esp), %ecx
+	ret
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 8cddfce..3d28dcc 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -293,6 +293,19 @@ run_dump_test "lea1e"
 run_dump_test "lea1f"
 run_dump_test "mov1a"
 run_dump_test "mov1b"
+run_dump_test "branch1"
+run_dump_test "call1"
+run_dump_test "call2"
+run_dump_test "jmp1"
+run_dump_test "jmp2"
+run_dump_test "load1"
+run_dump_test "load2"
+run_dump_test "load3"
+run_dump_test "load4a"
+run_dump_test "load4b"
+run_dump_test "load5a"
+run_dump_test "load5b"
+run_dump_test "load6"
 
 if { !([istarget "i?86-*-linux*"]
        || [istarget "i?86-*-gnu*"]
@@ -498,6 +511,22 @@ if { [isnative]
 	    "" \
 	    "pr19031.so" \
 	] \
+	[list \
+	    "Build got1d.so" \
+	    "-shared" \
+	    "" \
+	    { got1d.S } \
+	    "" \
+	    "got1d.so" \
+	] \
+	[list \
+	    "Build gotpc1" \
+	    "tmpdir/got1d.so" \
+	    "" \
+	    { got1a.S got1b.c got1c.c } \
+	    {{objdump {-dw} got1.dd}} \
+	    "got1" \
+	] \
     ]
 
     run_ld_link_exec_tests [] [list \
@@ -568,6 +597,14 @@ if { [isnative]
 	    "pr19031" \
 	    "pr19031.out" \
 	] \
+	[list \
+	    "Run got1" \
+	    "tmpdir/got1d.so" \
+	    "" \
+	    { got1a.S got1b.c got1c.c } \
+	    "got1" \
+	    "got1.out" \
+	] \
     ]
 }
 
diff --git a/ld/testsuite/ld-i386/jmp1.d b/ld/testsuite/ld-i386/jmp1.d
new file mode 100644
index 0000000..69383b2
--- /dev/null
+++ b/ld/testsuite/ld-i386/jmp1.d
@@ -0,0 +1,3 @@
+#as: --32
+#ld: -shared -melf_i386
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/jmp1.s b/ld/testsuite/ld-i386/jmp1.s
new file mode 100644
index 0000000..8c80696
--- /dev/null
+++ b/ld/testsuite/ld-i386/jmp1.s
@@ -0,0 +1,9 @@
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	jmp	*foo@GOT
diff --git a/ld/testsuite/ld-i386/jmp2.d b/ld/testsuite/ld-i386/jmp2.d
new file mode 100644
index 0000000..69383b2
--- /dev/null
+++ b/ld/testsuite/ld-i386/jmp2.d
@@ -0,0 +1,3 @@
+#as: --32
+#ld: -shared -melf_i386
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/jmp2.s b/ld/testsuite/ld-i386/jmp2.s
new file mode 100644
index 0000000..b4bc38d
--- /dev/null
+++ b/ld/testsuite/ld-i386/jmp2.s
@@ -0,0 +1,8 @@
+	.text
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	jmp	*foo@GOT
diff --git a/ld/testsuite/ld-i386/lea1c.d b/ld/testsuite/ld-i386/lea1c.d
index c84f413..54ec0de 100644
--- a/ld/testsuite/ld-i386/lea1c.d
+++ b/ld/testsuite/ld-i386/lea1c.d
@@ -9,6 +9,6 @@
 Disassembly of section .text:
 
 #...
-[ 	]*[a-f0-9]+:	8d 81 ([0-9a-f]{2} ){4} *	lea    -0x[a-f0-9]+\(%ecx\),%eax
-[ 	]*[a-f0-9]+:	8d 81 ([0-9a-f]{2} ){4} *	lea    0x[a-f0-9]+\(%ecx\),%eax
+[ 	]*[a-f0-9]+:	8d 05 ([0-9a-f]{2} ){4} *	lea    0x[a-f0-9]+,%eax
+[ 	]*[a-f0-9]+:	8d 05 ([0-9a-f]{2} ){4} *	lea    0x[a-f0-9]+,%eax
 #pass
diff --git a/ld/testsuite/ld-i386/load1.d b/ld/testsuite/ld-i386/load1.d
new file mode 100644
index 0000000..e93531e
--- /dev/null
+++ b/ld/testsuite/ld-i386/load1.d
@@ -0,0 +1,57 @@
+#as: --32
+#ld: -melf_i386
+#objdump: -dw --sym
+
+.*: +file format .*
+
+SYMBOL TABLE:
+#...
+0+8049170 l     O .data	0+1 bar
+#...
+0+8049171 g     O .data	0+1 foo
+#...
+
+Disassembly of section .text:
+
+0+8048074 <_start>:
+[ 	]*[a-f0-9]+:	8d 05 70 91 04 08    	lea    0x8049170,%eax
+[ 	]*[a-f0-9]+:	81 d0 70 91 04 08    	adc    \$0x8049170,%eax
+[ 	]*[a-f0-9]+:	81 c3 70 91 04 08    	add    \$0x8049170,%ebx
+[ 	]*[a-f0-9]+:	81 e1 70 91 04 08    	and    \$0x8049170,%ecx
+[ 	]*[a-f0-9]+:	81 fa 70 91 04 08    	cmp    \$0x8049170,%edx
+[ 	]*[a-f0-9]+:	81 cf 70 91 04 08    	or     \$0x8049170,%edi
+[ 	]*[a-f0-9]+:	81 de 70 91 04 08    	sbb    \$0x8049170,%esi
+[ 	]*[a-f0-9]+:	81 ed 70 91 04 08    	sub    \$0x8049170,%ebp
+[ 	]*[a-f0-9]+:	81 f4 70 91 04 08    	xor    \$0x8049170,%esp
+[ 	]*[a-f0-9]+:	f7 c1 70 91 04 08    	test   \$0x8049170,%ecx
+[ 	]*[a-f0-9]+:	8d 05 70 91 04 08    	lea    0x8049170,%eax
+[ 	]*[a-f0-9]+:	81 d0 70 91 04 08    	adc    \$0x8049170,%eax
+[ 	]*[a-f0-9]+:	81 c3 70 91 04 08    	add    \$0x8049170,%ebx
+[ 	]*[a-f0-9]+:	81 e1 70 91 04 08    	and    \$0x8049170,%ecx
+[ 	]*[a-f0-9]+:	81 fa 70 91 04 08    	cmp    \$0x8049170,%edx
+[ 	]*[a-f0-9]+:	81 cf 70 91 04 08    	or     \$0x8049170,%edi
+[ 	]*[a-f0-9]+:	81 de 70 91 04 08    	sbb    \$0x8049170,%esi
+[ 	]*[a-f0-9]+:	81 ed 70 91 04 08    	sub    \$0x8049170,%ebp
+[ 	]*[a-f0-9]+:	81 f4 70 91 04 08    	xor    \$0x8049170,%esp
+[ 	]*[a-f0-9]+:	f7 c1 70 91 04 08    	test   \$0x8049170,%ecx
+[ 	]*[a-f0-9]+:	8d 05 71 91 04 08    	lea    0x8049171,%eax
+[ 	]*[a-f0-9]+:	81 d0 71 91 04 08    	adc    \$0x8049171,%eax
+[ 	]*[a-f0-9]+:	81 c3 71 91 04 08    	add    \$0x8049171,%ebx
+[ 	]*[a-f0-9]+:	81 e1 71 91 04 08    	and    \$0x8049171,%ecx
+[ 	]*[a-f0-9]+:	81 fa 71 91 04 08    	cmp    \$0x8049171,%edx
+[ 	]*[a-f0-9]+:	81 cf 71 91 04 08    	or     \$0x8049171,%edi
+[ 	]*[a-f0-9]+:	81 de 71 91 04 08    	sbb    \$0x8049171,%esi
+[ 	]*[a-f0-9]+:	81 ed 71 91 04 08    	sub    \$0x8049171,%ebp
+[ 	]*[a-f0-9]+:	81 f4 71 91 04 08    	xor    \$0x8049171,%esp
+[ 	]*[a-f0-9]+:	f7 c1 71 91 04 08    	test   \$0x8049171,%ecx
+[ 	]*[a-f0-9]+:	8d 05 71 91 04 08    	lea    0x8049171,%eax
+[ 	]*[a-f0-9]+:	81 d0 71 91 04 08    	adc    \$0x8049171,%eax
+[ 	]*[a-f0-9]+:	81 c3 71 91 04 08    	add    \$0x8049171,%ebx
+[ 	]*[a-f0-9]+:	81 e1 71 91 04 08    	and    \$0x8049171,%ecx
+[ 	]*[a-f0-9]+:	81 fa 71 91 04 08    	cmp    \$0x8049171,%edx
+[ 	]*[a-f0-9]+:	81 cf 71 91 04 08    	or     \$0x8049171,%edi
+[ 	]*[a-f0-9]+:	81 de 71 91 04 08    	sbb    \$0x8049171,%esi
+[ 	]*[a-f0-9]+:	81 ed 71 91 04 08    	sub    \$0x8049171,%ebp
+[ 	]*[a-f0-9]+:	81 f4 71 91 04 08    	xor    \$0x8049171,%esp
+[ 	]*[a-f0-9]+:	f7 c1 71 91 04 08    	test   \$0x8049171,%ecx
+#pass
diff --git a/ld/testsuite/ld-i386/load1.s b/ld/testsuite/ld-i386/load1.s
new file mode 100644
index 0000000..a9f8460
--- /dev/null
+++ b/ld/testsuite/ld-i386/load1.s
@@ -0,0 +1,55 @@
+	.data
+	.type	bar, @object
+bar:
+	.byte	1
+	.size	bar, .-bar
+	.globl	foo
+	.type	foo, @object
+foo:
+	.byte	1
+	.size	foo, .-foo
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	movl	bar@GOT(%ecx), %eax
+	adcl	bar@GOT(%ecx), %eax
+	addl	bar@GOT(%ecx), %ebx
+	andl	bar@GOT(%ecx), %ecx
+	cmpl	bar@GOT(%ecx), %edx
+	orl	bar@GOT(%ecx), %edi
+	sbbl	bar@GOT(%ecx), %esi
+	subl	bar@GOT(%ecx), %ebp
+	xorl	bar@GOT(%ecx), %esp
+	testl	%ecx, bar@GOT(%ecx)
+	movl	bar@GOT, %eax
+	adcl	bar@GOT, %eax
+	addl	bar@GOT, %ebx
+	andl	bar@GOT, %ecx
+	cmpl	bar@GOT, %edx
+	orl	bar@GOT, %edi
+	sbbl	bar@GOT, %esi
+	subl	bar@GOT, %ebp
+	xorl	bar@GOT, %esp
+	testl	%ecx, bar@GOT
+	movl	foo@GOT(%ecx), %eax
+	adcl	foo@GOT(%ecx), %eax
+	addl	foo@GOT(%ecx), %ebx
+	andl	foo@GOT(%ecx), %ecx
+	cmpl	foo@GOT(%ecx), %edx
+	orl	foo@GOT(%ecx), %edi
+	sbbl	foo@GOT(%ecx), %esi
+	subl	foo@GOT(%ecx), %ebp
+	xorl	foo@GOT(%ecx), %esp
+	testl	%ecx, foo@GOT(%ecx)
+	movl	foo@GOT, %eax
+	adcl	foo@GOT, %eax
+	addl	foo@GOT, %ebx
+	andl	foo@GOT, %ecx
+	cmpl	foo@GOT, %edx
+	orl	foo@GOT, %edi
+	sbbl	foo@GOT, %esi
+	subl	foo@GOT, %ebp
+	xorl	foo@GOT, %esp
+	testl	%ecx, foo@GOT
+	.size	_start, .-_start
diff --git a/ld/testsuite/ld-i386/load2.d b/ld/testsuite/ld-i386/load2.d
new file mode 100644
index 0000000..87c2509
--- /dev/null
+++ b/ld/testsuite/ld-i386/load2.d
@@ -0,0 +1,3 @@
+#as: --32
+#ld: -melf_i386 -shared
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/load2.s b/ld/testsuite/ld-i386/load2.s
new file mode 100644
index 0000000..7aad5d0
--- /dev/null
+++ b/ld/testsuite/ld-i386/load2.s
@@ -0,0 +1,8 @@
+	.data
+	.type	foo, @object
+foo:
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	addl	foo@GOT, %ebx
diff --git a/ld/testsuite/ld-i386/load3.d b/ld/testsuite/ld-i386/load3.d
new file mode 100644
index 0000000..87c2509
--- /dev/null
+++ b/ld/testsuite/ld-i386/load3.d
@@ -0,0 +1,3 @@
+#as: --32
+#ld: -melf_i386 -shared
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/load3.s b/ld/testsuite/ld-i386/load3.s
new file mode 100644
index 0000000..d9b7083
--- /dev/null
+++ b/ld/testsuite/ld-i386/load3.s
@@ -0,0 +1,9 @@
+	.data
+	.globl	foo
+	.type	foo, @object
+foo:
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	addl	foo@GOT, %ebx
diff --git a/ld/testsuite/ld-i386/load4.s b/ld/testsuite/ld-i386/load4.s
new file mode 100644
index 0000000..fe2c4cd
--- /dev/null
+++ b/ld/testsuite/ld-i386/load4.s
@@ -0,0 +1,9 @@
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	movl	foo@GOT, %eax
diff --git a/ld/testsuite/ld-i386/load4a.d b/ld/testsuite/ld-i386/load4a.d
new file mode 100644
index 0000000..3aa56bd
--- /dev/null
+++ b/ld/testsuite/ld-i386/load4a.d
@@ -0,0 +1,4 @@
+#source: load4.s
+#as: --32
+#ld: -Bsymbolic -shared -melf_i386
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/load4b.d b/ld/testsuite/ld-i386/load4b.d
new file mode 100644
index 0000000..0f6f4e2
--- /dev/null
+++ b/ld/testsuite/ld-i386/load4b.d
@@ -0,0 +1,13 @@
+#source: load4.s
+#as: --32
+#ld: -melf_i386
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	8d 05 ([0-9a-f]{2} ){4} *	lea    0x[a-f0-9]+,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/load5.s b/ld/testsuite/ld-i386/load5.s
new file mode 100644
index 0000000..1ecd50c
--- /dev/null
+++ b/ld/testsuite/ld-i386/load5.s
@@ -0,0 +1,8 @@
+	.text
+	.type	foo, @function
+foo:
+	ret
+	.globl	_start
+	.type	_start, @function
+_start:
+	movl	foo@GOT, %eax
diff --git a/ld/testsuite/ld-i386/load5a.d b/ld/testsuite/ld-i386/load5a.d
new file mode 100644
index 0000000..88c225a
--- /dev/null
+++ b/ld/testsuite/ld-i386/load5a.d
@@ -0,0 +1,4 @@
+#source: load5.s
+#as: --32
+#ld: -Bsymbolic -shared -melf_i386
+#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object
diff --git a/ld/testsuite/ld-i386/load5b.d b/ld/testsuite/ld-i386/load5b.d
new file mode 100644
index 0000000..6db0b28
--- /dev/null
+++ b/ld/testsuite/ld-i386/load5b.d
@@ -0,0 +1,13 @@
+#source: load5.s
+#as: --32
+#ld: -melf_i386
+#objdump: -dw
+
+.*: +file format .*
+
+
+Disassembly of section .text:
+
+#...
+[ 	]*[a-f0-9]+:	8d 05 ([0-9a-f]{2} ){4} *	lea    0x[a-f0-9]+,%eax
+#pass
diff --git a/ld/testsuite/ld-i386/load6.d b/ld/testsuite/ld-i386/load6.d
new file mode 100644
index 0000000..69319cf
--- /dev/null
+++ b/ld/testsuite/ld-i386/load6.d
@@ -0,0 +1,28 @@
+#as: --32
+#ld: -shared -melf_i386
+#objdump: -dw
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+[a-f0-9]+ <_start>:
+[ 	]*[a-f0-9]+:	13 81 f8 ff ff ff    	adc    -0x8\(%ecx\),%eax
+[ 	]*[a-f0-9]+:	03 99 f8 ff ff ff    	add    -0x8\(%ecx\),%ebx
+[ 	]*[a-f0-9]+:	23 89 f8 ff ff ff    	and    -0x8\(%ecx\),%ecx
+[ 	]*[a-f0-9]+:	3b 91 f8 ff ff ff    	cmp    -0x8\(%ecx\),%edx
+[ 	]*[a-f0-9]+:	0b b9 f8 ff ff ff    	or     -0x8\(%ecx\),%edi
+[ 	]*[a-f0-9]+:	1b b1 f8 ff ff ff    	sbb    -0x8\(%ecx\),%esi
+[ 	]*[a-f0-9]+:	2b a9 f8 ff ff ff    	sub    -0x8\(%ecx\),%ebp
+[ 	]*[a-f0-9]+:	33 a1 f8 ff ff ff    	xor    -0x8\(%ecx\),%esp
+[ 	]*[a-f0-9]+:	85 89 f8 ff ff ff    	test   %ecx,-0x8\(%ecx\)
+[ 	]*[a-f0-9]+:	13 81 fc ff ff ff    	adc    -0x4\(%ecx\),%eax
+[ 	]*[a-f0-9]+:	03 99 fc ff ff ff    	add    -0x4\(%ecx\),%ebx
+[ 	]*[a-f0-9]+:	23 89 fc ff ff ff    	and    -0x4\(%ecx\),%ecx
+[ 	]*[a-f0-9]+:	3b 91 fc ff ff ff    	cmp    -0x4\(%ecx\),%edx
+[ 	]*[a-f0-9]+:	0b b9 fc ff ff ff    	or     -0x4\(%ecx\),%edi
+[ 	]*[a-f0-9]+:	1b b1 fc ff ff ff    	sbb    -0x4\(%ecx\),%esi
+[ 	]*[a-f0-9]+:	2b a9 fc ff ff ff    	sub    -0x4\(%ecx\),%ebp
+[ 	]*[a-f0-9]+:	33 a1 fc ff ff ff    	xor    -0x4\(%ecx\),%esp
+[ 	]*[a-f0-9]+:	85 89 fc ff ff ff    	test   %ecx,-0x4\(%ecx\)
+#pass
diff --git a/ld/testsuite/ld-i386/load6.s b/ld/testsuite/ld-i386/load6.s
new file mode 100644
index 0000000..eac3137
--- /dev/null
+++ b/ld/testsuite/ld-i386/load6.s
@@ -0,0 +1,33 @@
+	.data
+	.type	bar, @object
+bar:
+	.byte	1
+	.size	bar, .-bar
+	.globl	foo
+	.type	foo, @object
+foo:
+	.byte	1
+	.size	foo, .-foo
+	.text
+	.globl	_start
+	.type	_start, @function
+_start:
+	adcl	bar@GOT(%ecx), %eax
+	addl	bar@GOT(%ecx), %ebx
+	andl	bar@GOT(%ecx), %ecx
+	cmpl	bar@GOT(%ecx), %edx
+	orl	bar@GOT(%ecx), %edi
+	sbbl	bar@GOT(%ecx), %esi
+	subl	bar@GOT(%ecx), %ebp
+	xorl	bar@GOT(%ecx), %esp
+	testl	%ecx, bar@GOT(%ecx)
+	adcl	foo@GOT(%ecx), %eax
+	addl	foo@GOT(%ecx), %ebx
+	andl	foo@GOT(%ecx), %ecx
+	cmpl	foo@GOT(%ecx), %edx
+	orl	foo@GOT(%ecx), %edi
+	sbbl	foo@GOT(%ecx), %esi
+	subl	foo@GOT(%ecx), %ebp
+	xorl	foo@GOT(%ecx), %esp
+	testl	%ecx, foo@GOT(%ecx)
+	.size	_start, .-_start
diff --git a/ld/testsuite/ld-i386/plt-main1.rd b/ld/testsuite/ld-i386/plt-main1.rd
index d27589e..53c49d9 100644
--- a/ld/testsuite/ld-i386/plt-main1.rd
+++ b/ld/testsuite/ld-i386/plt-main1.rd
@@ -1,3 +1,3 @@
 #...
-[0-9a-f ]+R_386_GOT32 +0+ +bar
+[0-9a-f ]+R_386_GOT32X +0+ +bar
 #pass
diff --git a/ld/testsuite/ld-i386/plt-main3.rd b/ld/testsuite/ld-i386/plt-main3.rd
index 7b78818..417fb20 100644
--- a/ld/testsuite/ld-i386/plt-main3.rd
+++ b/ld/testsuite/ld-i386/plt-main3.rd
@@ -1,5 +1,5 @@
 #...
-[0-9a-f ]+R_386_GOT32 +0+ +bar
+[0-9a-f ]+R_386_GOT32X +0+ +bar
 #...
 [0-9a-f ]+R_386_PLT32 +0+ +bar
 #pass
diff --git a/ld/testsuite/ld-i386/plt-main4.rd b/ld/testsuite/ld-i386/plt-main4.rd
index 882a3ad..393fe29 100644
--- a/ld/testsuite/ld-i386/plt-main4.rd
+++ b/ld/testsuite/ld-i386/plt-main4.rd
@@ -1,5 +1,5 @@
 #...
-[0-9a-f ]+R_386_GOT32 +0+ +foo
+[0-9a-f ]+R_386_GOT32X +0+ +foo
 #...
 [0-9a-f ]+R_386_PLT32 +0+ +foo
 #pass
-- 
2.4.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]