summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-02-14 03:50:40 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-02-14 03:50:55 -0800
commit451875b4f976a527395e9303224c7881b65e12ed (patch)
tree15ebc416aa1dd49b234ad02dfdf8a9ebe4f92f11
parentf98b2e334fcca666afaee3c6546b9fc91a4963d4 (diff)
downloadbinutils-gdb-451875b4f976a527395e9303224c7881b65e12ed.tar.gz
x86-64: Use PLT address for PC-relative reloc
Since PLT in PDE and PC-relative PLT in PIE can be used as function address, there is no need for dynamic PC-relative relocation against a dynamic function definition in PIE. Linker should resolve PC-relative reference to its PLT address. NB: i386 has non-PIC PLT and PIC PLT. Only non-PIC PLT in PDE can be used as function address. PIC PLT in PIE can't be used as function address. bfd/ PR ld/22842 * elf32-i386.c (elf_i386_check_relocs): Pass FALSE for non PC-relative PLT to NEED_DYNAMIC_RELOCATION_P. * elf64-x86-64.c (elf_x86_64_check_relocs): Create PLT for R_X86_64_PC32 reloc against dynamic function in data section. Pass TRUE for PC-relative PLT to NEED_DYNAMIC_RELOCATION_P. (elf_x86_64_relocate_section): Use PLT for R_X86_64_PC32 reloc against dynamic function in data section. * elfxx-x86.c (elf_x86_allocate_dynrelocs): Use PLT in PIE as function address only if pcrel_plt is true. (_bfd_x86_elf_link_hash_table_create): Set pcrel_plt. * elfxx-x86.h (NEED_DYNAMIC_RELOCATION_P): Add PCREL_PLT for PC-relative PLT. If PLT is PC-relative, don't generate dynamic PC-relative relocation against a function definition in data secton in PIE. Remove the obsolete comments. (elf_x86_link_hash_table): Add pcrel_plt. ld/ PR ld/22842 * testsuite/ld-i386/i386.exp: Run PR ld/22842 tests. * testsuite/ld-x86-64/x86-64.exp: Likewise. * testsuite/ld-i386/pr22842a.c: New file. * testsuite/ld-i386/pr22842b.S: Likewise. * testsuite/ld-x86-64/pr22842a.c: Likewise. * testsuite/ld-x86-64/pr22842a.rd: Likewise. * testsuite/ld-x86-64/pr22842b.S: Likewise. * testsuite/ld-x86-64/pr22842b.rd: Likewise.
-rw-r--r--bfd/ChangeLog19
-rw-r--r--bfd/elf32-i386.c2
-rw-r--r--bfd/elf64-x86-64.c24
-rw-r--r--bfd/elfxx-x86.c22
-rw-r--r--bfd/elfxx-x86.h50
-rw-r--r--ld/ChangeLog12
-rw-r--r--ld/testsuite/ld-i386/i386.exp16
-rw-r--r--ld/testsuite/ld-i386/pr22842a.c20
-rw-r--r--ld/testsuite/ld-i386/pr22842b.S41
-rw-r--r--ld/testsuite/ld-x86-64/pr22842a.c20
-rw-r--r--ld/testsuite/ld-x86-64/pr22842a.rd4
-rw-r--r--ld/testsuite/ld-x86-64/pr22842b.S20
-rw-r--r--ld/testsuite/ld-x86-64/pr22842b.rd4
-rw-r--r--ld/testsuite/ld-x86-64/x86-64.exp25
14 files changed, 251 insertions, 28 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 77cdfe86bc8..b3afd99cd50 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,22 @@
+2018-02-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/22842
+ * elf32-i386.c (elf_i386_check_relocs): Pass FALSE for non
+ PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
+ * elf64-x86-64.c (elf_x86_64_check_relocs): Create PLT for
+ R_X86_64_PC32 reloc against dynamic function in data section.
+ Pass TRUE for PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
+ (elf_x86_64_relocate_section): Use PLT for R_X86_64_PC32 reloc
+ against dynamic function in data section.
+ * elfxx-x86.c (elf_x86_allocate_dynrelocs): Use PLT in PIE as
+ function address only if pcrel_plt is true.
+ (_bfd_x86_elf_link_hash_table_create): Set pcrel_plt.
+ * elfxx-x86.h (NEED_DYNAMIC_RELOCATION_P): Add PCREL_PLT for
+ PC-relative PLT. If PLT is PC-relative, don't generate dynamic
+ PC-relative relocation against a function definition in data
+ secton in PIE. Remove the obsolete comments.
+ (elf_x86_link_hash_table): Add pcrel_plt.
+
2018-02-13 H.J. Lu <hongjiu.lu@intel.com>
* elfxx-x86.c (elf_x86_allocate_dynrelocs): Check bfd_link_dll,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index e74da3af620..1a4b53ae305 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1812,7 +1812,7 @@ do_relocation:
size_reloc = FALSE;
do_size:
- if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
+ if (NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
R_386_32))
{
struct elf_dyn_relocs *p;
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 0e4bb2e4a5f..00ed5d17a5a 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -2135,7 +2135,17 @@ pointer:
as pointer, make sure that PLT is used if foo is
a function defined in a shared library. */
if ((sec->flags & SEC_CODE) == 0)
- h->pointer_equality_needed = 1;
+ {
+ h->pointer_equality_needed = 1;
+ if (bfd_link_pie (info)
+ && h->type == STT_FUNC
+ && !h->def_regular
+ && h->def_dynamic)
+ {
+ h->needs_plt = 1;
+ h->plt.refcount = 1;
+ }
+ }
}
else if (r_type != R_X86_64_PC32_BND
&& r_type != R_X86_64_PC64)
@@ -2173,7 +2183,7 @@ pointer:
size_reloc = FALSE;
do_size:
- if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
+ if (NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type,
htab->pointer_r_type))
{
struct elf_dyn_relocs *p;
@@ -2968,6 +2978,7 @@ do_ifunc_pointer:
break;
}
+use_plt:
if (h->plt.offset != (bfd_vma) -1)
{
if (htab->plt_second != NULL)
@@ -3046,6 +3057,15 @@ do_ifunc_pointer:
return elf_x86_64_need_pic (info, input_bfd, input_section,
h, NULL, NULL, howto);
}
+ /* Since x86-64 has PC-relative PLT, we can use PLT in PIE
+ as function address. */
+ else if (h != NULL
+ && (input_section->flags & SEC_CODE) == 0
+ && bfd_link_pie (info)
+ && h->type == STT_FUNC
+ && !h->def_regular
+ && h->def_dynamic)
+ goto use_plt;
/* Fall through. */
case R_X86_64_8:
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index bd36707fc03..05d283b4fe5 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -179,6 +179,7 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
asection *s = htab->elf.splt;
asection *second_s = htab->plt_second;
asection *got_s = htab->plt_got;
+ bfd_boolean use_plt;
/* If this is the first .plt entry, make room for the special
first entry. The .plt section is used by prelink to undo
@@ -196,12 +197,19 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
/* If this symbol is not defined in a regular file, and we are
- not generating a shared library, then set the symbol to this
- location in the .plt. This is required to make function
- pointers compare as equal between the normal executable and
- the shared library. */
- if (! bfd_link_dll (info)
- && !h->def_regular)
+ generating PDE, then set the symbol to this location in the
+ .plt. This is required to make function pointers compare
+ as equal between PDE and the shared library.
+
+ NB: If PLT is PC-relative, we can use the .plt in PIE for
+ function address. */
+ if (h->def_regular)
+ use_plt = FALSE;
+ else if (htab->pcrel_plt)
+ use_plt = ! bfd_link_dll (info);
+ else
+ use_plt = bfd_link_pde (info);
+ if (use_plt)
{
if (use_plt_got)
{
@@ -771,6 +779,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
ret->dt_reloc_sz = DT_RELASZ;
ret->dt_reloc_ent = DT_RELAENT;
ret->got_entry_size = 8;
+ ret->pcrel_plt = TRUE;
ret->tls_get_addr = "__tls_get_addr";
}
if (ABI_64_P (abfd))
@@ -798,6 +807,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
ret->dt_reloc_ent = DT_RELENT;
ret->sizeof_reloc = sizeof (Elf32_External_Rel);
ret->got_entry_size = 4;
+ ret->pcrel_plt = FALSE;
ret->pointer_r_type = R_386_32;
ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
ret->dynamic_interpreter_size
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index 0162a90c6d3..f84fe01630b 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -76,14 +76,11 @@
into the shared library. However, if we are linking with -Bsymbolic,
we do not need to copy a reloc against a global symbol which is
defined in an object we are including in the link (i.e., DEF_REGULAR
- is set). At this point we have not seen all the input files, so it
- is possible that DEF_REGULAR is not set now but will be set later (it
- is never cleared). In case of a weak definition, DEF_REGULAR may be
- cleared later by a strong definition in a shared library. We account
- for that possibility below by storing information in the relocs_copied
- field of the hash table entry. A similar situation occurs when
- creating shared libraries and symbol visibility changes render the
- symbol local.
+ is set).
+
+ If PCREL_PLT is true, don't generate dynamic relocation in PIE for
+ PC-relative relocation against a dynamic function definition in data
+ section when PLT address can be used.
If on the other hand, we are creating an executable, we may need to
keep relocations for symbols satisfied by a dynamic library if we
@@ -91,23 +88,30 @@
We also need to generate dynamic pointer relocation against
STT_GNU_IFUNC symbol in the non-code section. */
-#define NEED_DYNAMIC_RELOCATION_P(INFO, H, SEC, R_TYPE, POINTER_TYPE) \
+#define NEED_DYNAMIC_RELOCATION_P(INFO, PCREL_PLT, H, SEC, R_TYPE, \
+ POINTER_TYPE) \
((bfd_link_pic (INFO) \
&& (! X86_PCREL_TYPE_P (R_TYPE) \
|| ((H) != NULL \
&& (! (bfd_link_pie (INFO) \
|| SYMBOLIC_BIND ((INFO), (H))) \
|| (H)->root.type == bfd_link_hash_defweak \
- || !(H)->def_regular)))) \
- || ((H) != NULL \
- && (H)->type == STT_GNU_IFUNC \
- && (R_TYPE) == POINTER_TYPE \
- && ((SEC)->flags & SEC_CODE) == 0) \
- || (ELIMINATE_COPY_RELOCS \
- && !bfd_link_pic (INFO) \
- && (H) != NULL \
- && ((H)->root.type == bfd_link_hash_defweak \
- || !(H)->def_regular)))
+ || (!(bfd_link_pie (INFO) \
+ && (PCREL_PLT) \
+ && (H)->plt.refcount > 0 \
+ && ((SEC)->flags & SEC_CODE) == 0 \
+ && (H)->type == STT_FUNC \
+ && (H)->def_dynamic) \
+ && !(H)->def_regular))))) \
+ || ((H) != NULL \
+ && (H)->type == STT_GNU_IFUNC \
+ && (R_TYPE) == POINTER_TYPE \
+ && ((SEC)->flags & SEC_CODE) == 0) \
+ || (ELIMINATE_COPY_RELOCS \
+ && !bfd_link_pic (INFO) \
+ && (H) != NULL \
+ && ((H)->root.type == bfd_link_hash_defweak \
+ || !(H)->def_regular)))
/* TRUE if dynamic relocation should be generated. Don't copy a
pc-relative relocation into the output file if the symbol needs
@@ -482,6 +486,14 @@ struct elf_x86_link_hash_table
/* TRUE if GOT is referenced. */
unsigned int got_referenced : 1;
+ /* TRUE if PLT is PC-relative. PLT in PDE and PC-relative PLT in PIE
+ can be used as function address.
+
+ NB: i386 has non-PIC PLT and PIC PLT. Only non-PIC PLT in PDE can
+ be used as function address. PIC PLT in PIE can't be used as
+ function address. */
+ unsigned int pcrel_plt : 1;
+
bfd_vma (*r_info) (bfd_vma, bfd_vma);
bfd_vma (*r_sym) (bfd_vma);
bfd_boolean (*is_reloc_section) (const char *);
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 42ddf8bf004..c8a967ab145 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,15 @@
+2018-02-14 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR ld/22842
+ * testsuite/ld-i386/i386.exp: Run PR ld/22842 tests.
+ * testsuite/ld-x86-64/x86-64.exp: Likewise.
+ * testsuite/ld-i386/pr22842a.c: New file.
+ * testsuite/ld-i386/pr22842b.S: Likewise.
+ * testsuite/ld-x86-64/pr22842a.c: Likewise.
+ * testsuite/ld-x86-64/pr22842a.rd: Likewise.
+ * testsuite/ld-x86-64/pr22842b.S: Likewise.
+ * testsuite/ld-x86-64/pr22842b.rd: Likewise.
+
2018-02-14 Maciej W. Rozycki <macro@mips.com>
* ldlex.h (ldlex_command): Remove prototype.
diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp
index e4ec07d0e97..ba2cce87ece 100644
--- a/ld/testsuite/ld-i386/i386.exp
+++ b/ld/testsuite/ld-i386/i386.exp
@@ -1273,6 +1273,14 @@ if { [isnative]
{} \
"pr21997-1.so" \
] \
+ [list \
+ "Build pr22842.so" \
+ "-shared" \
+ "-fPIC" \
+ { pr22842a.c } \
+ {} \
+ "pr22842.so" \
+ ] \
]
run_ld_link_exec_tests [list \
@@ -1371,6 +1379,14 @@ if { [isnative]
"pr21997-1-pie-2" \
"pass.out" \
] \
+ [list \
+ "Build pr22842" \
+ "-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
+ "" \
+ { pr22842b.S } \
+ "pr22842" \
+ "pass.out" \
+ ] \
]
if { [at_least_gcc_version 5 0] } {
diff --git a/ld/testsuite/ld-i386/pr22842a.c b/ld/testsuite/ld-i386/pr22842a.c
new file mode 100644
index 00000000000..52489bba2f9
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22842a.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+test (void)
+{
+ static int count;
+ if (count)
+ printf("PASS\n");
+ count++;
+}
+
+void
+foo (void (*bar) (void))
+{
+ if (bar != test)
+ abort ();
+ bar ();
+ test ();
+}
diff --git a/ld/testsuite/ld-i386/pr22842b.S b/ld/testsuite/ld-i386/pr22842b.S
new file mode 100644
index 00000000000..d959a5f34c4
--- /dev/null
+++ b/ld/testsuite/ld-i386/pr22842b.S
@@ -0,0 +1,41 @@
+ .text
+ .globl main
+ .type main, @function
+main:
+ leal 4(%esp), %ecx
+ andl $-16, %esp
+ pushl -4(%ecx)
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %ebx
+ pushl %ecx
+ call __x86.get_pc_thunk.bx
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ subl $12, %esp
+ movl bar@GOT(%ebx), %eax
+ addl (%eax), %eax
+ pushl %eax
+ call foo@PLT
+ addl $16, %esp
+ leal -8(%ebp), %esp
+ xorl %eax, %eax
+ popl %ecx
+ popl %ebx
+ popl %ebp
+ leal -4(%ecx), %esp
+ ret
+ .size main, .-main
+ .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
+
+ .data
+ .p2align 2
+bar:
+ .long test - .
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr22842a.c b/ld/testsuite/ld-x86-64/pr22842a.c
new file mode 100644
index 00000000000..52489bba2f9
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842a.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+test (void)
+{
+ static int count;
+ if (count)
+ printf("PASS\n");
+ count++;
+}
+
+void
+foo (void (*bar) (void))
+{
+ if (bar != test)
+ abort ();
+ bar ();
+ test ();
+}
diff --git a/ld/testsuite/ld-x86-64/pr22842a.rd b/ld/testsuite/ld-x86-64/pr22842a.rd
new file mode 100644
index 00000000000..d78ea2f7cca
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842a.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_X86_64_NONE.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22842b.S b/ld/testsuite/ld-x86-64/pr22842b.S
new file mode 100644
index 00000000000..f0659cd901e
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842b.S
@@ -0,0 +1,20 @@
+ .text
+ .globl main
+ .type main,@function
+main:
+ pushq %rax
+ movslq bar(%rip), %rax
+ leaq bar(%rip), %rdi
+ addq %rax, %rdi
+
+ callq foo
+ xorl %eax, %eax
+ popq %rcx
+ retq
+
+ .data
+ .p2align 2
+bar:
+ .long test - .
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/ld/testsuite/ld-x86-64/pr22842b.rd b/ld/testsuite/ld-x86-64/pr22842b.rd
new file mode 100644
index 00000000000..f1036d545cf
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22842b.rd
@@ -0,0 +1,4 @@
+#failif
+#...
+[0-9a-f ]+R_X86_64_PC32 +[0-9a-f]+ +test \+ 0
+#...
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index 8442663af17..2a46266e0dd 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1190,6 +1190,23 @@ if { [isnative] && [which $CC] != 0 } {
{{readelf -drW pr22791-2.rd}} \
"pr22791-2" \
] \
+ [list \
+ "Build pr22842.so" \
+ "-shared" \
+ "-fPIC" \
+ { pr22842a.c } \
+ {} \
+ "pr22842.so" \
+ ] \
+ [list \
+ "Build pr22842" \
+ "-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
+ "" \
+ { pr22842b.S } \
+ {{readelf -rW pr22842a.rd} \
+ {readelf -rW pr22842b.rd}} \
+ "pr22842" \
+ ] \
]
if {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1524,6 +1541,14 @@ if { [isnative] && [which $CC] != 0 } {
"pass.out" \
"$NOPIE_CFLAGS" \
] \
+ [list \
+ "Build pr22842" \
+ "-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
+ "" \
+ { pr22842b.S } \
+ "pr22842" \
+ "pass.out" \
+ ] \
]
# Run-time tests which require working ifunc attribute support.