aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2017-02-15 11:39:30 -0800
committerH.J. Lu <hjl.tools@gmail.com>2017-02-15 11:39:48 -0800
commit2a5684011edabf5804abb9e11253a9747587b284 (patch)
tree8ed51e47a385a573a949b36a10451b8fd89ef080
parenta5def14f1ca70e14d9433cb229c9369fa3051598 (diff)
downloadfsf-binutils-gdb-2a5684011edabf5804abb9e11253a9747587b284.zip
fsf-binutils-gdb-2a5684011edabf5804abb9e11253a9747587b284.tar.gz
fsf-binutils-gdb-2a5684011edabf5804abb9e11253a9747587b284.tar.bz2
i386: Allow "lea foo@GOT, %reg" in PIC
"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.
-rw-r--r--bfd/ChangeLog6
-rw-r--r--bfd/elf32-i386.c12
-rw-r--r--ld/ChangeLog7
-rw-r--r--ld/testsuite/ld-i386/i386.exp22
-rw-r--r--ld/testsuite/ld-i386/pr21168a.c14
-rw-r--r--ld/testsuite/ld-i386/pr21168b.S29
6 files changed, 86 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index cbea9a9..789915c 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index 3bee4ca..e6e70d8 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -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:
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 3f88091..f875a8b 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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.
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index 7680ff5..c489227 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -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
index 0000000..a6c0da1
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr21168a.c
@@ -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
index 0000000..a4ea5c9
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr21168b.S
@@ -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