From 7073b5b9edc9e06974bd733b7e4b3845d6d6f690 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 24 Aug 2017 06:34:19 -0700 Subject: [PATCH] x86-64: Check relocations with -z nocopyreloc On x86-64, when -z nocopyreloc is used to build executable, relocations may overflow at run-time or may not be resolved without PIC. This patch checks these conditions and issues an error with suggestion for -fPIC. bfd/ PR ld/22001 * elf64-x86-64.c (elf_x86_64_relocate_section): Check for R_X86_64_PC32 relocation run-time overflow and unresolvable R_X86_64_32S relocation with -z nocopyreloc. ld/ PR ld/22001 * testsuite/ld-i386/i386.exp: Run -z nocopyreloc tests. * testsuite/ld-x86-64/x86-64.exp: Likewise. * ld/testsuite/ld-i386/pr22001-1a.c: New file. * ld/testsuite/ld-i386/pr22001-1b.c: Likewise. * ld/testsuite/ld-i386/pr22001-1c.S: Likewise. * ld/testsuite/ld-x86-64/pr22001-1a.c: Likewise. * ld/testsuite/ld-x86-64/pr22001-1a.err: Likewise. * ld/testsuite/ld-x86-64/pr22001-1b.c: Likewise. * ld/testsuite/ld-x86-64/pr22001-1b.err: Likewise. * ld/testsuite/ld-x86-64/pr22001-1c.c: Likewise. --- bfd/ChangeLog | 7 ++++ bfd/elf64-x86-64.c | 39 +++++++++++------ ld/ChangeLog | 14 +++++++ ld/testsuite/ld-i386/i386.exp | 55 ++++++++++++++++++++++++ ld/testsuite/ld-i386/pr22001-1a.c | 13 ++++++ ld/testsuite/ld-i386/pr22001-1b.c | 14 +++++++ ld/testsuite/ld-i386/pr22001-1c.S | 51 +++++++++++++++++++++++ ld/testsuite/ld-x86-64/pr22001-1a.c | 13 ++++++ ld/testsuite/ld-x86-64/pr22001-1a.err | 2 + ld/testsuite/ld-x86-64/pr22001-1b.c | 13 ++++++ ld/testsuite/ld-x86-64/pr22001-1b.err | 2 + ld/testsuite/ld-x86-64/pr22001-1c.c | 12 ++++++ ld/testsuite/ld-x86-64/x86-64.exp | 60 +++++++++++++++++++++++++++ 13 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 ld/testsuite/ld-i386/pr22001-1a.c create mode 100644 ld/testsuite/ld-i386/pr22001-1b.c create mode 100644 ld/testsuite/ld-i386/pr22001-1c.S create mode 100644 ld/testsuite/ld-x86-64/pr22001-1a.c create mode 100644 ld/testsuite/ld-x86-64/pr22001-1a.err create mode 100644 ld/testsuite/ld-x86-64/pr22001-1b.c create mode 100644 ld/testsuite/ld-x86-64/pr22001-1b.err create mode 100644 ld/testsuite/ld-x86-64/pr22001-1c.c diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a45b896e520..bb389205217 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2017-08-24 H.J. Lu + + PR ld/22001 + * elf64-x86-64.c (elf_x86_64_relocate_section): Check for + R_X86_64_PC32 relocation run-time overflow and unresolvable + R_X86_64_32S relocation with -z nocopyreloc. + 2017-08-24 H.J. Lu * elf32-i386.c (elf_i386_check_relocs): Revert the last change. diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 84d63f404e1..e30428d6d80 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -4942,13 +4942,17 @@ do_ifunc_pointer: case R_X86_64_PC32: case R_X86_64_PC32_BND: /* Don't complain about -fPIC if the symbol is undefined when - building executable unless it is unresolved weak symbol. */ + building executable unless it is unresolved weak symbol or + -z nocopyreloc is used. */ if ((input_section->flags & SEC_ALLOC) != 0 && (input_section->flags & SEC_READONLY) != 0 && h != NULL && ((bfd_link_executable (info) - && h->root.type == bfd_link_hash_undefweak - && !resolved_to_zero) + && ((h->root.type == bfd_link_hash_undefweak + && !resolved_to_zero) + || (info->nocopyreloc + && h->def_dynamic + && !(h->root.u.def.section->flags & SEC_CODE)))) || bfd_link_dll (info))) { bfd_boolean fail = FALSE; @@ -5717,15 +5721,26 @@ direct: && _bfd_elf_section_offset (output_bfd, info, input_section, rel->r_offset) != (bfd_vma) -1) { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), - input_bfd, - input_section, - rel->r_offset, - howto->name, - h->root.root.string); - return FALSE; + switch (r_type) + { + case R_X86_64_32S: + if (info->nocopyreloc + && !(h->root.u.def.section->flags & SEC_CODE)) + return elf_x86_64_need_pic (info, input_bfd, input_section, + h, NULL, NULL, howto); + /* Fall through. */ + + default: + _bfd_error_handler + /* xgettext:c-format */ + (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), + input_bfd, + input_section, + rel->r_offset, + howto->name, + h->root.root.string); + return FALSE; + } } do_relocation: diff --git a/ld/ChangeLog b/ld/ChangeLog index e3faa792f5d..0c445920232 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,17 @@ +2017-08-24 H.J. Lu + + PR ld/22001 + * testsuite/ld-i386/i386.exp: Run -z nocopyreloc tests. + * testsuite/ld-x86-64/x86-64.exp: Likewise. + * ld/testsuite/ld-i386/pr22001-1a.c: New file. + * ld/testsuite/ld-i386/pr22001-1b.c: Likewise. + * ld/testsuite/ld-i386/pr22001-1c.S: Likewise. + * ld/testsuite/ld-x86-64/pr22001-1a.c: Likewise. + * ld/testsuite/ld-x86-64/pr22001-1a.err: Likewise. + * ld/testsuite/ld-x86-64/pr22001-1b.c: Likewise. + * ld/testsuite/ld-x86-64/pr22001-1b.err: Likewise. + * ld/testsuite/ld-x86-64/pr22001-1c.c: Likewise. + 2017-08-17 Andrew Burgess PR 21961 diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index 3c5de021b2b..c91a8611f37 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -1245,6 +1245,17 @@ if { [isnative] if { [isnative] && [istarget "i?86-*-*"] && [which $CC] != 0 } { + run_cc_link_tests [list \ + [list \ + "Build pr22001-1.so" \ + "-shared" \ + "" \ + { pr22001-1a.c } \ + {} \ + "pr22001-1.so" \ + ] \ + ] + run_ld_link_exec_tests [list \ [list \ "Run weakundef1 without PIE" \ @@ -1255,7 +1266,51 @@ if { [isnative] "pass.out" \ "$NOPIE_CFLAGS" \ ] \ + [list \ + "Run pr22001-1" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1b.c } \ + "pr22001-1" \ + "pass.out" \ + "$NOPIE_CFLAGS" \ + ] \ + [list \ + "Run pr22001-1 (PIE 1)" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1c.S } \ + "pr22001-1-pie-1" \ + "pass.out" \ + ] \ + [list \ + "Run pr22001-1 (PIE 2)" \ + "-pie -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1c.S } \ + "pr22001-1-pie-2" \ + "pass.out" \ + ] \ + [list \ + "Run pr22001-1 (PIC 1)" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1b.c } \ + "pr22001-1-pic-1" \ + "pass.out" \ + "-fPIC" \ + ] \ + [list \ + "Run pr22001-1 (PIC 2)" \ + "-pie -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1b.c } \ + "pr22001-1-pic-2" \ + "pass.out" \ + "-fPIC" \ + ] \ ] + if { [at_least_gcc_version 5 0] } { run_ld_link_exec_tests [list \ [list \ diff --git a/ld/testsuite/ld-i386/pr22001-1a.c b/ld/testsuite/ld-i386/pr22001-1a.c new file mode 100644 index 00000000000..2b55ea8efbf --- /dev/null +++ b/ld/testsuite/ld-i386/pr22001-1a.c @@ -0,0 +1,13 @@ +int copy = 1; + +int +get_copy () +{ + return copy; +} + +int * +get_copy_p () +{ + return © +} diff --git a/ld/testsuite/ld-i386/pr22001-1b.c b/ld/testsuite/ld-i386/pr22001-1b.c new file mode 100644 index 00000000000..8eadd42109f --- /dev/null +++ b/ld/testsuite/ld-i386/pr22001-1b.c @@ -0,0 +1,14 @@ +#include + +extern int copy; +extern int get_copy (void); +extern int* get_copy_p (void); + +int +main () +{ + if (copy == get_copy () && © == get_copy_p ()) + printf ("PASS\n"); + + return 0; +} diff --git a/ld/testsuite/ld-i386/pr22001-1c.S b/ld/testsuite/ld-i386/pr22001-1c.S new file mode 100644 index 00000000000..2c1041dba77 --- /dev/null +++ b/ld/testsuite/ld-i386/pr22001-1c.S @@ -0,0 +1,51 @@ + .section .rodata.str1.1,"aMS",@progbits,1 +.LC0: + .string "PASS" + .section .text.startup,"ax",@progbits + .p2align 4,,15 + .globl main + .type main, @function +main: + leal 4(%esp), %ecx + andl $-16, %esp + pushl -4(%ecx) + pushl %ebp + movl %esp, %ebp + pushl %esi + pushl %ebx + pushl %ecx + call __x86.get_pc_thunk.bx + addl $_GLOBAL_OFFSET_TABLE_, %ebx + subl $12, %esp + call get_copy@PLT + movl copy@GOT(%ebx), %esi + cmpl (%esi), %eax + je .L7 +.L3: + leal -12(%ebp), %esp + xorl %eax, %eax + popl %ecx + popl %ebx + popl %esi + popl %ebp + leal -4(%ecx), %esp + ret +.L7: + call get_copy_p@PLT + cmpl %esi, %eax + jne .L3 + leal .LC0@GOTOFF(%ebx), %eax + subl $12, %esp + pushl %eax + call puts@PLT + addl $16, %esp + jmp .L3 + .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 + .section .note.GNU-stack,"",@progbits diff --git a/ld/testsuite/ld-x86-64/pr22001-1a.c b/ld/testsuite/ld-x86-64/pr22001-1a.c new file mode 100644 index 00000000000..2b55ea8efbf --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr22001-1a.c @@ -0,0 +1,13 @@ +int copy = 1; + +int +get_copy () +{ + return copy; +} + +int * +get_copy_p () +{ + return © +} diff --git a/ld/testsuite/ld-x86-64/pr22001-1a.err b/ld/testsuite/ld-x86-64/pr22001-1a.err new file mode 100644 index 00000000000..640aa072b86 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr22001-1a.err @@ -0,0 +1,2 @@ +.*relocation R_X86_64_PC32 against symbol `copy' can not be used when making a P(D|I)E object; recompile with -fPIC +#... diff --git a/ld/testsuite/ld-x86-64/pr22001-1b.c b/ld/testsuite/ld-x86-64/pr22001-1b.c new file mode 100644 index 00000000000..a172236f4f2 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr22001-1b.c @@ -0,0 +1,13 @@ +#include + +extern int copy; +extern int get_copy (void); + +int +main () +{ + if (copy == get_copy ()) + printf ("PASS\n"); + + return 0; +} diff --git a/ld/testsuite/ld-x86-64/pr22001-1b.err b/ld/testsuite/ld-x86-64/pr22001-1b.err new file mode 100644 index 00000000000..9617e73f58c --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr22001-1b.err @@ -0,0 +1,2 @@ +.*relocation R_X86_64_32S against symbol `copy' can not be used when making a P(D|I)E object; recompile with -fPIC +#... diff --git a/ld/testsuite/ld-x86-64/pr22001-1c.c b/ld/testsuite/ld-x86-64/pr22001-1c.c new file mode 100644 index 00000000000..8fd925c8f76 --- /dev/null +++ b/ld/testsuite/ld-x86-64/pr22001-1c.c @@ -0,0 +1,12 @@ +#include + +extern int copy; +extern int* get_copy_p (void); + +int main() +{ + if (© == get_copy_p ()) + printf ("PASS\n"); + + return 0; +} diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 0b795df60bb..6dc36657121 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -1040,6 +1040,30 @@ if { [isnative] && [which $CC] != 0 } { {{readelf {-n} property-7.r}} \ "property-7b.o" \ ] \ + [list \ + "Build pr22001-1.so" \ + "-shared" \ + "-fPIC" \ + { pr22001-1a.c } \ + {} \ + "pr22001-1.so" \ + ] \ + [list \ + "Build pr22001-1a" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "$NOPIE_CFLAGS" \ + { pr22001-1b.c } \ + {{error_output "pr22001-1a.err"}} \ + "pr22001-1a" \ + ] \ + [list \ + "Build pr22001-1b" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "$NOPIE_CFLAGS" \ + { pr22001-1c.c } \ + {{error_output "pr22001-1b.err"}} \ + "pr22001-1b" \ + ] \ ] run_ld_link_exec_tests [list \ @@ -1216,6 +1240,42 @@ if { [isnative] && [which $CC] != 0 } { {property-x86-2.S property-x86-1.S pass.c property-stack.S} \ "property-5-static" "pass.out" \ ] \ + [list \ + "Run pr22001-1a (PIC 1)" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1b.c } \ + "pr22001-1a-pic-1" \ + "pass.out" \ + "-fPIC" \ + ] \ + [list \ + "Run pr22001-1a (PIC 2)" \ + "-pie -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1b.c } \ + "pr22001-1a-pic-2" \ + "pass.out" \ + "-fPIC" \ + ] \ + [list \ + "Run pr22001-1b (PIC 1)" \ + "$NOPIE_LDFLAGS -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1c.c } \ + "pr22001-1b-pic-1" \ + "pass.out" \ + "-fPIC" \ + ] \ + [list \ + "Run pr22001-1b (PIC 2)" \ + "-pie -Wl,-z,nocopyreloc,--no-as-needed tmpdir/pr22001-1.so" \ + "" \ + { pr22001-1c.c } \ + "pr22001-1b-pic-2" \ + "pass.out" \ + "-fPIC" \ + ] \ ] # Run-time tests which require working ifunc attribute support. -- 2.30.2