i386: Allow "lea foo@GOT, %reg" in PIC
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 15 Feb 2017 19:39:30 +0000 (11:39 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 15 Feb 2017 19:39:48 +0000 (11:39 -0800)
"lea foo@GOT, %reg" is OK in PIC since it only loads the GOT offset
into register, which can be used later with a GOT base register to
get the value in the GOT entry.

bfd/

PR ld/21168
* elf32-i386.c (elf_i386_relocate_section): Allow
"lea foo@GOT, %reg" in PIC.

ld/

PR ld/21168
* testsuite/ld-i386/i386.exp: Run pr21168.
* testsuite/ld-i386/pr21168a.c: New file.
* testsuite/ld-i386/pr21168b.S: Likewise.

bfd/ChangeLog
bfd/elf32-i386.c
ld/ChangeLog
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-i386/pr21168a.c [new file with mode: 0644]
ld/testsuite/ld-i386/pr21168b.S [new file with mode: 0644]

index cbea9a9..789915c 100644 (file)
@@ -1,5 +1,11 @@
 2017-02-15  H.J. Lu  <hongjiu.lu@intel.com>
 
+       PR ld/21168
+       * elf32-i386.c (elf_i386_relocate_section): Allow
+       "lea foo@GOT, %reg" in PIC.
+
+2017-02-15  H.J. Lu  <hongjiu.lu@intel.com>
+
        PR ld/20244
        * elf32-i386.c (elf_i386_relocate_section): Properly get IFUNC
        symbol name when reporting R_386_GOT32/R_386_GOT32X relocation
index 3bee4ca..e6e70d8 100644 (file)
@@ -4074,7 +4074,9 @@ elf_i386_relocate_section (bfd *output_bfd,
                              - gotplt->output_section->vma
                              - gotplt->output_offset);
 
-             if ((*(contents + rel->r_offset - 1) & 0xc7) == 0x5)
+             if (rel->r_offset > 1
+                 && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5
+                 && *(contents + rel->r_offset - 2) != 0x8d)
                {
                  if (bfd_link_pic (info))
                    goto disallow_got32;
@@ -4345,13 +4347,15 @@ r_386_got32:
 
          relocation = (htab->elf.sgot->output_section->vma
                        + htab->elf.sgot->output_offset + off);
-         if ((*(contents + rel->r_offset - 1) & 0xc7) == 0x5)
+         if (rel->r_offset > 1
+             && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5
+             && *(contents + rel->r_offset - 2) != 0x8d)
            {
              if (bfd_link_pic (info))
                {
                  /* For PIC, disallow R_386_GOT32 without a base
-                    register since we don't know what the GOT base
-                    is.  */
+                    register, except for "lea foo@GOT, %reg", since
+                    we don't know what the GOT base is.  */
                  const char *name;
 
 disallow_got32:
index 3f88091..f875a8b 100644 (file)
@@ -1,5 +1,12 @@
 2017-02-15  H.J. Lu  <hongjiu.lu@intel.com>
 
+       PR ld/21168
+       * testsuite/ld-i386/i386.exp: Run pr21168.
+       * testsuite/ld-i386/pr21168a.c: New file.
+       * testsuite/ld-i386/pr21168b.S: Likewise.
+
+2017-02-15  H.J. Lu  <hongjiu.lu@intel.com>
+
        PR ld/20244
        * testsuite/ld-i386/i386.exp: Run pr20244-4a, pr20244-4b and
        pr20244-4c.
index 7680ff5..c489227 100644 (file)
@@ -835,6 +835,20 @@ if { [isnative]
            "-fPIC -O2 -g" \
            { ifunc-1a.c ifunc-1b.S ifunc-1c.S ifunc-1d.S } \
        ] \
+       [list \
+           "Build pr21168a.o" \
+           "" \
+           "" \
+           { pr21168a.c } \
+       ] \
+       [list \
+           "Build pr21168.so" \
+           "-shared" \
+           "" \
+           { pr21168b.S } \
+           "" \
+           "pr21168.so" \
+       ] \
     ]
 
     run_ld_link_exec_tests [list \
@@ -856,6 +870,14 @@ if { [isnative]
            "ifunc-1b" \
            "pass.out" \
        ] \
+       [list \
+           "Run pr21168" \
+           "tmpdir/pr21168a.o tmpdir/pr21168.so" \
+           "" \
+           { dummy.c } \
+           "pr21168" \
+           "pass.out" \
+       ] \
     ]
 }
 
diff --git a/ld/testsuite/ld-i386/pr21168a.c b/ld/testsuite/ld-i386/pr21168a.c
new file mode 100644 (file)
index 0000000..a6c0da1
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+int foo = 1;
+
+extern int *bar (void);
+extern int bar_ifunc (void);
+
+int
+main (void)
+{
+  if (bar () == &foo && bar_ifunc () == 0xbadbeef)
+    printf ("PASS\n");
+  return 0;
+}
diff --git a/ld/testsuite/ld-i386/pr21168b.S b/ld/testsuite/ld-i386/pr21168b.S
new file mode 100644 (file)
index 0000000..a4ea5c9
--- /dev/null
@@ -0,0 +1,29 @@
+       .text
+       .globl  bar
+       .type   bar, @function
+bar:
+       call    __x86.get_pc_thunk.ax
+       addl    $_GLOBAL_OFFSET_TABLE_, %eax
+       lea     foo@GOT, %ecx
+       mov     (%eax,%ecx,1), %eax
+       ret
+       .globl  bar_ifunc
+       .type   bar_ifunc, @function
+bar_ifunc:
+       call    __x86.get_pc_thunk.ax
+       addl    $_GLOBAL_OFFSET_TABLE_, %eax
+       lea     ifunc@GOT, %ecx
+       mov     (%eax,%ecx,1), %eax
+       ret
+       .type ifunc, @gnu_indirect_function
+ifunc:
+       mov     $0xbadbeef, %eax
+       ret
+       .section        .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
+       .globl  __x86.get_pc_thunk.ax
+       .hidden __x86.get_pc_thunk.ax
+       .type   __x86.get_pc_thunk.ax, @function
+__x86.get_pc_thunk.ax:
+       movl    (%esp), %eax
+       ret
+       .section        .note.GNU-stack,"",@progbits