]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - bfd/elf64-x86-64.c
x86-64: Move PIC check for PC-relative relocations back
[thirdparty/binutils-gdb.git] / bfd / elf64-x86-64.c
index e193f44e93f17d4270b1e5da6a7ceb1cd5f1e9e5..e5c8003a68e1dc71e84ec10fb434175e26df38ce 100644 (file)
@@ -1422,7 +1422,7 @@ elf_x86_64_need_pic (struct bfd_link_info *info,
            v = _("protected symbol ");
          else
            v = _("symbol ");
-         pic = _("; recompile with -fPIC");
+         pic = NULL;
          break;
        }
 
@@ -1432,15 +1432,24 @@ elf_x86_64_need_pic (struct bfd_link_info *info,
   else
     {
       name = bfd_elf_sym_name (input_bfd, symtab_hdr, isym, NULL);
-      pic = _("; recompile with -fPIC");
+      pic = NULL;
     }
 
   if (bfd_link_dll (info))
-    object = _("a shared object");
-  else if (bfd_link_pie (info))
-    object = _("a PIE object");
+    {
+      object = _("a shared object");
+      if (!pic)
+       pic = _("; recompile with -fPIC");
+    }
   else
-    object = _("a PDE object");
+    {
+      if (bfd_link_pie (info))
+       object = _("a PIE object");
+      else
+       object = _("a PDE object");
+      if (!pic)
+       pic = _("; recompile with -fPIE");
+    }
 
   /* xgettext:c-format */
   _bfd_error_handler (_("%pB: relocation %s against %s%s`%s' can "
@@ -1676,8 +1685,8 @@ convert:
            }
          else
            {
-             nop = link_info->call_nop_byte;
-             if (link_info->call_nop_as_suffix)
+             nop = htab->params->call_nop_byte;
+             if (htab->params->call_nop_as_suffix)
                {
                  nop_offset = irel->r_offset + 3;
                  disp = bfd_get_32 (abfd, contents + irel->r_offset);
@@ -1855,7 +1864,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
       const char *name;
       bfd_boolean size_reloc;
       bfd_boolean converted_reloc;
-      bfd_boolean do_check_pic;
 
       r_symndx = htab->r_sym (rel->r_info);
       r_type = ELF32_R_TYPE (rel->r_info);
@@ -1942,10 +1950,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
        {
          /* It is referenced by a non-shared object. */
          h->ref_regular = 1;
-
-         if (h->type == STT_GNU_IFUNC)
-           elf_tdata (info->output_bfd)->has_gnu_symbols
-             |= elf_gnu_symbol_ifunc;
        }
 
       converted_reloc = FALSE;
@@ -2131,13 +2135,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
          size_reloc = TRUE;
          goto do_size;
 
-       case R_X86_64_PC8:
-       case R_X86_64_PC16:
-       case R_X86_64_PC32:
-       case R_X86_64_PC32_BND:
-         do_check_pic = TRUE;
-         goto check_pic;
-
        case R_X86_64_32:
          if (!ABI_64_P (abfd))
            goto pointer;
@@ -2149,7 +2146,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
             run-time relocation overflow.  Don't error out for
             sections we don't care about, such as debug sections or
             when relocation overflow check is disabled.  */
-         if (!info->no_reloc_overflow_check
+         if (!htab->params->no_reloc_overflow_check
              && !converted_reloc
              && (bfd_link_pic (info)
                  || (bfd_link_executable (info)
@@ -2161,11 +2158,13 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
                                        &x86_64_elf_howto_table[r_type]);
          /* Fall through.  */
 
+       case R_X86_64_PC8:
+       case R_X86_64_PC16:
+       case R_X86_64_PC32:
+       case R_X86_64_PC32_BND:
        case R_X86_64_PC64:
        case R_X86_64_64:
 pointer:
-         do_check_pic = FALSE;
-check_pic:
          if (eh != NULL && (sec->flags & SEC_CODE) != 0)
            eh->zero_undefweak |= 0x2;
          /* We are called after all symbols have been resolved.  Only
@@ -2229,69 +2228,6 @@ check_pic:
                }
            }
 
-         if (do_check_pic)
-           {
-             /* Don't complain about -fPIC if the symbol is undefined
-                when building executable unless it is unresolved weak
-                symbol, references a dynamic definition in PIE or
-                -z nocopyreloc is used.  */
-             bfd_boolean no_copyreloc_p
-               = (info->nocopyreloc
-                  || (h != NULL
-                      && !h->root.linker_def
-                      && !h->root.ldscript_def
-                      && eh->def_protected
-                      && elf_has_no_copy_on_protected (h->root.u.def.section->owner)));
-             if ((sec->flags & SEC_ALLOC) != 0
-                 && (sec->flags & SEC_READONLY) != 0
-                 && h != NULL
-                 && ((bfd_link_executable (info)
-                      && ((h->root.type == bfd_link_hash_undefweak
-                           && (eh == NULL
-                               || !UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
-                                                                    eh)))
-                          || (bfd_link_pie (info)
-                              && !SYMBOL_DEFINED_NON_SHARED_P (h)
-                              && h->def_dynamic)
-                          || (no_copyreloc_p
-                              && h->def_dynamic
-                              && !(h->root.u.def.section->flags & SEC_CODE))))
-                     || bfd_link_dll (info)))
-               {
-                 bfd_boolean fail = FALSE;
-                 if (SYMBOL_REFERENCES_LOCAL_P (info, h))
-                   {
-                     /* Symbol is referenced locally.  Make sure it is
-                        defined locally.  */
-                     fail = !SYMBOL_DEFINED_NON_SHARED_P (h);
-                   }
-                 else if (bfd_link_pie (info))
-                   {
-                     /* We can only use PC-relative relocations in PIE
-                        from non-code sections.  */
-                     if (h->type == STT_FUNC
-                         && (sec->flags & SEC_CODE) != 0)
-                       fail = TRUE;
-                   }
-                 else if (no_copyreloc_p || bfd_link_dll (info))
-                   {
-                     /* Symbol doesn't need copy reloc and isn't
-                        referenced locally.  Don't allow PC-relative
-                        relocations against default and protected
-                        symbols since address of protected function
-                        and location of protected data may not be in
-                        the shared object.   */
-                     fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
-                             || ELF_ST_VISIBILITY (h->other) == STV_PROTECTED);
-                   }
-
-                 if (fail)
-                   return elf_x86_64_need_pic (info, abfd, sec, h,
-                                               symtab_hdr, isym,
-                                               &x86_64_elf_howto_table[r_type]);
-               }
-           }
-
          size_reloc = FALSE;
 do_size:
          if (NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type,
@@ -2373,9 +2309,7 @@ do_size:
          /* This relocation describes which C++ vtable entries are actually
             used.  Record for later use during GC.  */
        case R_X86_64_GNU_VTENTRY:
-         BFD_ASSERT (h != NULL);
-         if (h != NULL
-             && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+         if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
            goto error_return;
          break;
 
@@ -2494,6 +2428,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
       bfd_boolean relative_reloc;
       bfd_boolean converted_reloc;
       bfd_boolean need_copy_reloc_in_pie;
+      bfd_boolean no_copyreloc_p;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == (int) R_X86_64_GNU_VTINHERIT
@@ -3013,14 +2948,14 @@ skip_ifunc:
                       && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
                {
                  _bfd_error_handler
-             /* xgettext:c-format */
+                   /* xgettext:c-format */
                    (_("%pB: relocation R_X86_64_GOTOFF64 against protected %s"
                       " `%s' can not be used when making a shared object"),
                     input_bfd,
                     h->type == STT_FUNC ? "function" : "data",
                     h->root.root.string);
                  bfd_set_error (bfd_error_bad_value);
-             return FALSE;
+                 return FALSE;
                }
            }
 
@@ -3134,14 +3069,73 @@ use_plt:
        case R_X86_64_PC16:
        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,
+            references a dynamic definition in PIE or -z nocopyreloc
+            is used.  */
+         no_copyreloc_p
+           = (info->nocopyreloc
+              || (h != NULL
+                  && !h->root.linker_def
+                  && !h->root.ldscript_def
+                  && eh->def_protected
+                  && elf_has_no_copy_on_protected (h->root.u.def.section->owner)));
+
+         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
+                       && (eh == NULL
+                           || !UNDEFINED_WEAK_RESOLVED_TO_ZERO (info,
+                                                                eh)))
+                      || (bfd_link_pie (info)
+                          && !SYMBOL_DEFINED_NON_SHARED_P (h)
+                          && h->def_dynamic)
+                      || (no_copyreloc_p
+                          && h->def_dynamic
+                          && !(h->root.u.def.section->flags & SEC_CODE))))
+                 || bfd_link_dll (info)))
+           {
+             bfd_boolean fail = FALSE;
+             if (SYMBOL_REFERENCES_LOCAL_P (info, h))
+               {
+                 /* Symbol is referenced locally.  Make sure it is
+                    defined locally.  */
+                 fail = !SYMBOL_DEFINED_NON_SHARED_P (h);
+               }
+             else if (bfd_link_pie (info))
+               {
+                 /* We can only use PC-relative relocations in PIE
+                    from non-code sections.  */
+                 if (h->type == STT_FUNC
+                     && (sec->flags & SEC_CODE) != 0)
+                   fail = TRUE;
+               }
+             else if (no_copyreloc_p || bfd_link_dll (info))
+               {
+                 /* Symbol doesn't need copy reloc and isn't
+                    referenced locally.  Don't allow PC-relative
+                    relocations against default and protected
+                    symbols since address of protected function
+                    and location of protected data may not be in
+                    the shared object.   */
+                 fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+                         || ELF_ST_VISIBILITY (h->other) == STV_PROTECTED);
+               }
+
+             if (fail)
+               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.  */
-         if (h != NULL
-             && (input_section->flags & SEC_CODE) == 0
-             && bfd_link_pie (info)
-             && h->type == STT_FUNC
-             && !h->def_regular
-             && h->def_dynamic)
+         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.  */
 
@@ -3206,7 +3200,7 @@ direct:
                     convert R_X86_64_32 to dynamic R_X86_64_RELATIVE.  */
                  if (r_type == htab->pointer_r_type
                      || (r_type == R_X86_64_32
-                         && info->no_reloc_overflow_check))
+                         && htab->params->no_reloc_overflow_check))
                    {
                      relocate = TRUE;
                      outrel.r_info = htab->r_info (0, R_X86_64_RELATIVE);
@@ -3361,20 +3355,39 @@ direct:
                    {
                      if (contents[roff + 5] == 0xb8)
                        {
+                         if (roff < 3
+                             || (roff - 3 + 22) > input_section->size)
+                           {
+corrupt_input:
+                             info->callbacks->einfo
+                               (_("%F%P: corrupt input: %pB\n"),
+                                input_bfd);
+                             return FALSE;
+                           }
                          memcpy (contents + roff - 3,
                                  "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80"
                                  "\0\0\0\0\x66\x0f\x1f\x44\0", 22);
                          largepic = 1;
                        }
                      else
-                       memcpy (contents + roff - 4,
-                               "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
-                               16);
+                       {
+                         if (roff < 4
+                             || (roff - 4 + 16) > input_section->size)
+                           goto corrupt_input;
+                         memcpy (contents + roff - 4,
+                                 "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+                                 16);
+                       }
                    }
                  else
-                   memcpy (contents + roff - 3,
-                           "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
-                           15);
+                   {
+                     if (roff < 3
+                         || (roff - 3 + 15) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + roff - 3,
+                             "\x64\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0",
+                             15);
+                   }
                  bfd_put_32 (output_bfd,
                              elf_x86_64_tpoff (info, relocation),
                              contents + roff + 8 + largepic);
@@ -3395,6 +3408,8 @@ direct:
 
                  unsigned int val, type;
 
+                 if (roff < 3)
+                   goto corrupt_input;
                  type = bfd_get_8 (input_bfd, contents + roff - 3);
                  val = bfd_get_8 (input_bfd, contents + roff - 1);
                  bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1),
@@ -3441,7 +3456,11 @@ direct:
                  if (roff >= 3)
                    val = bfd_get_8 (input_bfd, contents + roff - 3);
                  else
-                   val = 0;
+                   {
+                     if (roff < 2)
+                       goto corrupt_input;
+                     val = 0;
+                   }
                  type = bfd_get_8 (input_bfd, contents + roff - 2);
                  reg = bfd_get_8 (input_bfd, contents + roff - 1);
                  reg >>= 3;
@@ -3449,11 +3468,19 @@ direct:
                    {
                      /* movq */
                      if (val == 0x4c)
-                       bfd_put_8 (output_bfd, 0x49,
-                                  contents + roff - 3);
+                       {
+                         if (roff < 3)
+                           goto corrupt_input;
+                         bfd_put_8 (output_bfd, 0x49,
+                                    contents + roff - 3);
+                       }
                      else if (!ABI_64_P (output_bfd) && val == 0x44)
-                       bfd_put_8 (output_bfd, 0x41,
-                                  contents + roff - 3);
+                       {
+                         if (roff < 3)
+                           goto corrupt_input;
+                         bfd_put_8 (output_bfd, 0x41,
+                                    contents + roff - 3);
+                       }
                      bfd_put_8 (output_bfd, 0xc7,
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0xc0 | reg,
@@ -3464,11 +3491,19 @@ direct:
                      /* addq/addl -> addq/addl - addressing with %rsp/%r12
                         is special  */
                      if (val == 0x4c)
-                       bfd_put_8 (output_bfd, 0x49,
-                                  contents + roff - 3);
+                       {
+                         if (roff < 3)
+                           goto corrupt_input;
+                         bfd_put_8 (output_bfd, 0x49,
+                                    contents + roff - 3);
+                       }
                      else if (!ABI_64_P (output_bfd) && val == 0x44)
-                       bfd_put_8 (output_bfd, 0x41,
-                                  contents + roff - 3);
+                       {
+                         if (roff < 3)
+                           goto corrupt_input;
+                         bfd_put_8 (output_bfd, 0x41,
+                                    contents + roff - 3);
+                       }
                      bfd_put_8 (output_bfd, 0x81,
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0xc0 | reg,
@@ -3478,11 +3513,19 @@ direct:
                    {
                      /* addq/addl -> leaq/leal */
                      if (val == 0x4c)
-                       bfd_put_8 (output_bfd, 0x4d,
-                                  contents + roff - 3);
+                       {
+                         if (roff < 3)
+                           goto corrupt_input;
+                         bfd_put_8 (output_bfd, 0x4d,
+                                    contents + roff - 3);
+                       }
                      else if (!ABI_64_P (output_bfd) && val == 0x44)
-                       bfd_put_8 (output_bfd, 0x45,
-                                  contents + roff - 3);
+                       {
+                         if (roff < 3)
+                           goto corrupt_input;
+                         bfd_put_8 (output_bfd, 0x45,
+                                    contents + roff - 3);
+                       }
                      bfd_put_8 (output_bfd, 0x8d,
                                 contents + roff - 2);
                      bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3),
@@ -3652,20 +3695,33 @@ direct:
                    {
                      if (contents[roff + 5] == 0xb8)
                        {
+                         if (roff < 3
+                             || (roff - 3 + 22) > input_section->size)
+                           goto corrupt_input;
                          memcpy (contents + roff - 3,
                                  "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05"
                                  "\0\0\0\0\x66\x0f\x1f\x44\0", 22);
                          largepic = 1;
                        }
                      else
-                       memcpy (contents + roff - 4,
-                               "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
-                               16);
+                       {
+                         if (roff < 4
+                             || (roff - 4 + 16) > input_section->size)
+                           goto corrupt_input;
+                         memcpy (contents + roff - 4,
+                                 "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+                                 16);
+                       }
                    }
                  else
-                   memcpy (contents + roff - 3,
-                           "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
-                           15);
+                   {
+                     if (roff < 3
+                         || (roff - 3 + 15) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + roff - 3,
+                             "\x64\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0",
+                             15);
+                   }
 
                  relocation = (htab->elf.sgot->output_section->vma
                                + htab->elf.sgot->output_offset + off
@@ -3694,6 +3750,8 @@ direct:
                     turn a leaq into a movq in the form we use it, it
                     suffices to change the second byte from 0x8d to
                     0x8b.  */
+                 if (roff < 2)
+                   goto corrupt_input;
                  bfd_put_8 (output_bfd, 0x8b, contents + roff - 2);
 
                  bfd_put_32 (output_bfd,
@@ -3762,28 +3820,58 @@ direct:
              BFD_ASSERT (r_type == R_X86_64_TPOFF32);
              if (ABI_64_P (output_bfd))
                {
+                 if ((rel->r_offset + 5) >= input_section->size)
+                   goto corrupt_input;
                  if (contents[rel->r_offset + 5] == 0xb8)
-                   memcpy (contents + rel->r_offset - 3,
-                           "\x66\x66\x66\x66\x2e\x0f\x1f\x84\0\0\0\0\0"
-                           "\x64\x48\x8b\x04\x25\0\0\0", 22);
+                   {
+                     if (rel->r_offset < 3
+                         || (rel->r_offset - 3 + 22) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + rel->r_offset - 3,
+                             "\x66\x66\x66\x66\x2e\x0f\x1f\x84\0\0\0\0\0"
+                             "\x64\x48\x8b\x04\x25\0\0\0", 22);
+                   }
                  else if (contents[rel->r_offset + 4] == 0xff
                           || contents[rel->r_offset + 4] == 0x67)
-                   memcpy (contents + rel->r_offset - 3,
-                           "\x66\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0",
-                           13);
+                   {
+                     if (rel->r_offset < 3
+                         || (rel->r_offset - 3 + 13) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + rel->r_offset - 3,
+                             "\x66\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0",
+                             13);
+
+                   }
                  else
-                   memcpy (contents + rel->r_offset - 3,
-                           "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+                   {
+                     if (rel->r_offset < 3
+                         || (rel->r_offset - 3 + 12) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + rel->r_offset - 3,
+                             "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12);
+                   }
                }
              else
                {
+                 if ((rel->r_offset + 4) >= input_section->size)
+                   goto corrupt_input;
                  if (contents[rel->r_offset + 4] == 0xff)
-                   memcpy (contents + rel->r_offset - 3,
-                           "\x66\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0",
-                           13);
+                   {
+                     if (rel->r_offset < 3
+                         || (rel->r_offset - 3 + 13) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + rel->r_offset - 3,
+                             "\x66\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0",
+                             13);
+                   }
                  else
-                   memcpy (contents + rel->r_offset - 3,
-                           "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
+                   {
+                     if (rel->r_offset < 3
+                         || (rel->r_offset - 3 + 12) > input_section->size)
+                       goto corrupt_input;
+                     memcpy (contents + rel->r_offset - 3,
+                             "\x0f\x1f\x40\x00\x64\x8b\x04\x25\0\0\0", 12);
+                   }
                }
              /* Skip R_X86_64_PC32, R_X86_64_PLT32, R_X86_64_GOTPCRELX
                 and R_X86_64_PLTOFF64.  */
@@ -4954,7 +5042,13 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info)
 
   if (get_elf_x86_backend_data (info->output_bfd)->target_os != is_nacl)
     {
-      if (info->bndplt)
+      const struct elf_backend_data *bed
+       = get_elf_backend_data (info->output_bfd);
+      struct elf_x86_link_hash_table *htab
+       = elf_x86_hash_table (info, bed->target_id);
+      if (!htab)
+       abort ();
+      if (htab->params->bndplt)
        {
          init_table.lazy_plt = &elf_x86_64_lazy_bnd_plt;
          init_table.non_lazy_plt = &elf_x86_64_non_lazy_bnd_plt;