x86-64: Check relocations with -z nocopyreloc
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 24 Aug 2017 13:34:19 +0000 (06:34 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Thu, 24 Aug 2017 13:34:38 +0000 (06:34 -0700)
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.

13 files changed:
bfd/ChangeLog
bfd/elf64-x86-64.c
ld/ChangeLog
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-i386/pr22001-1a.c [new file with mode: 0644]
ld/testsuite/ld-i386/pr22001-1b.c [new file with mode: 0644]
ld/testsuite/ld-i386/pr22001-1c.S [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr22001-1a.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr22001-1a.err [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr22001-1b.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr22001-1b.err [new file with mode: 0644]
ld/testsuite/ld-x86-64/pr22001-1c.c [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index a45b896..bb38920 100644 (file)
@@ -1,5 +1,12 @@
 2017-08-24  H.J. Lu  <hongjiu.lu@intel.com>
 
+       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  <hongjiu.lu@intel.com>
+
        * elf32-i386.c (elf_i386_check_relocs): Revert the last change.
        Undefined symbols may not have a type.
        * elf64-x86-64.c (elf_x86_64_check_relocs): Likewise.
index 84d63f4..e30428d 100644 (file)
@@ -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:
index e3faa79..0c44592 100644 (file)
@@ -1,3 +1,17 @@
+2017-08-24  H.J. Lu  <hongjiu.lu@intel.com>
+
+       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  <andrew.burgess@embecosm.com>
 
        PR 21961
index 3c5de02..c91a861 100644 (file)
@@ -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 (file)
index 0000000..2b55ea8
--- /dev/null
@@ -0,0 +1,13 @@
+int copy = 1;
+
+int
+get_copy ()
+{
+  return copy;
+}
+
+int *
+get_copy_p ()
+{
+  return &copy;
+}
diff --git a/ld/testsuite/ld-i386/pr22001-1b.c b/ld/testsuite/ld-i386/pr22001-1b.c
new file mode 100644 (file)
index 0000000..8eadd42
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+extern int copy;
+extern int get_copy (void);
+extern int* get_copy_p (void);
+
+int
+main ()
+{
+  if (copy == get_copy () && &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 (file)
index 0000000..2c1041d
--- /dev/null
@@ -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 (file)
index 0000000..2b55ea8
--- /dev/null
@@ -0,0 +1,13 @@
+int copy = 1;
+
+int
+get_copy ()
+{
+  return copy;
+}
+
+int *
+get_copy_p ()
+{
+  return &copy;
+}
diff --git a/ld/testsuite/ld-x86-64/pr22001-1a.err b/ld/testsuite/ld-x86-64/pr22001-1a.err
new file mode 100644 (file)
index 0000000..640aa07
--- /dev/null
@@ -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 (file)
index 0000000..a172236
--- /dev/null
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+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 (file)
index 0000000..9617e73
--- /dev/null
@@ -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 (file)
index 0000000..8fd925c
--- /dev/null
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern int copy;
+extern int* get_copy_p (void);
+
+int main()
+{
+  if (&copy == get_copy_p ())
+    printf ("PASS\n");
+
+  return 0;
+}
index 0b795df..6dc3665 100644 (file)
@@ -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.