From Andrew Chatham: exit on relocation error.
[deliverable/binutils-gdb.git] / gold / target-reloc.h
index f972b117d9afa049a11dee6b727674448ade68cb..2ebd3c97913c5c2b8ade9f87b2a8a2435ce534a8 100644 (file)
 // target-reloc.h -- target specific relocation support  -*- C++ -*-
 
+// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// This file is part of gold.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
 #ifndef GOLD_TARGET_RELOC_H
 #define GOLD_TARGET_RELOC_H
 
 #include "elfcpp.h"
+#include "object.h"
 #include "symtab.h"
+#include "reloc-types.h"
 
 namespace gold
 {
 
-// Pick the ELF relocation accessor class and the size based on
-// SH_TYPE, which is either SHT_REL or SHT_RELA.
-
-template<int sh_type, int size, bool big_endian>
-struct Reloc_types;
+// This function implements the generic part of reloc scanning.  This
+// is an inline function which takes a class whose operator()
+// implements the machine specific part of scanning.  We do it this
+// way to avoidmaking a function call for each relocation, and to
+// avoid repeating the generic code for each target.
 
-template<int size, bool big_endian>
-struct Reloc_types<elfcpp::SHT_REL, size, big_endian>
+template<int size, bool big_endian, typename Target_type, int sh_type,
+        typename Scan>
+inline void
+scan_relocs(
+    const General_options& options,
+    Symbol_table* symtab,
+    Layout* layout,
+    Target_type* target,
+    Sized_relobj<size, big_endian>* object,
+    unsigned int data_shndx,
+    const unsigned char* prelocs,
+    size_t reloc_count,
+    size_t local_count,
+    const unsigned char* plocal_syms,
+    Symbol** global_syms)
 {
-  typedef typename elfcpp::Rel<size, big_endian> Reloc;
-  static const int reloc_size = elfcpp::Elf_sizes<size>::rel_size;
-};
+  typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
+  const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
+  const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
+  Scan scan;
 
-template<int size, bool big_endian>
-struct Reloc_types<elfcpp::SHT_RELA, size, big_endian>
-{
-  typedef typename elfcpp::Rela<size, big_endian> Reloc;
-  static const int reloc_size = elfcpp::Elf_sizes<size>::rela_size;
-};
+  for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+    {
+      Reltype reloc(prelocs);
+
+      typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
+      unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+      unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+
+      if (r_sym < local_count)
+       {
+         gold_assert(plocal_syms != NULL);
+         typename elfcpp::Sym<size, big_endian> lsym(plocal_syms
+                                                     + r_sym * sym_size);
+         const unsigned int shndx = lsym.get_st_shndx();
+         if (shndx < elfcpp::SHN_LORESERVE
+             && shndx != elfcpp::SHN_UNDEF
+             && !object->is_section_included(lsym.get_st_shndx()))
+           {
+             // RELOC is a relocation against a local symbol in a
+             // section we are discarding.  We can ignore this
+             // relocation.  It will eventually become a reloc
+             // against the value zero.
+             //
+             // FIXME: We should issue a warning if this is an
+             // allocated section; is this the best place to do it?
+             // 
+             // FIXME: The old GNU linker would in some cases look
+             // for the linkonce section which caused this section to
+             // be discarded, and, if the other section was the same
+             // size, change the reloc to refer to the other section.
+             // That seems risky and weird to me, and I don't know of
+             // any case where it is actually required.
+
+             continue;
+           }
+
+         scan.local(options, symtab, layout, target, object, data_shndx,
+                    reloc, r_type, lsym);
+       }
+      else
+       {
+         Symbol* gsym = global_syms[r_sym - local_count];
+         gold_assert(gsym != NULL);
+         if (gsym->is_forwarder())
+           gsym = symtab->resolve_forwards(gsym);
+
+         scan.global(options, symtab, layout, target, object, data_shndx,
+                     reloc, r_type, gsym);
+       }
+    }
+}
 
-// This function implements the generic part of relocation handling.
-// This is an inline function which take a class whose operator()
+// This function implements the generic part of relocation processing.
+// This is an inline function which take a class whose relocate()
 // implements the machine specific part of relocation.  We do it this
 // way to avoid making a function call for each relocation, and to
 // avoid repeating the generic relocation handling code for each
 // target.
 
 // SIZE is the ELF size: 32 or 64.  BIG_ENDIAN is the endianness of
-// the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.  RELOC
-// implements operator() to do a relocation.
-
-// OBJECT is the object for we are processing relocs.  SH_TYPE is the
-// type of relocation: SHT_REL or SHT_RELA.  PRELOCS points to the
-// relocation data.  RELOC_COUNT is the number of relocs.  LOCAL_COUNT
-// is the number of local symbols.  LOCAL_VALUES holds the values of
-// the local symbols.  GLOBAL_SYMS points to the global symbols.  VIEW
-// is the section data, VIEW_ADDRESS is its memory address, and
-// VIEW_SIZE is the size.
-
-template<int size, bool big_endian, int sh_type, typename Relocate>
+// the data.  SH_TYPE is the section type: SHT_REL or SHT_RELA.
+// RELOCATE implements operator() to do a relocation.
+
+// PRELOCS points to the relocation data.  RELOC_COUNT is the number
+// of relocs.  VIEW is the section data, VIEW_ADDRESS is its memory
+// address, and VIEW_SIZE is the size.
+
+template<int size, bool big_endian, typename Target_type, int sh_type,
+        typename Relocate>
 inline void
 relocate_section(
-    const Symbol_table* symtab,
-    Sized_object<size, big_endian>* object,
+    const Relocate_info<size, big_endian>* relinfo,
+    Target_type* target,
     const unsigned char* prelocs,
     size_t reloc_count,
-    size_t local_count,
-    const typename elfcpp::Elf_types<size>::Elf_Addr* local_values,
-    Symbol** global_syms,
     unsigned char* view,
     typename elfcpp::Elf_types<size>::Elf_Addr view_address,
     off_t view_size)
@@ -66,52 +141,70 @@ relocate_section(
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
   Relocate relocate;
 
+  unsigned int local_count = relinfo->local_symbol_count;
+  const typename Sized_relobj<size, big_endian>::Local_values* local_values =
+    relinfo->local_values;
+  const Symbol* const * global_syms = relinfo->symbols;
+
   for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
     {
       Reltype reloc(prelocs);
 
       off_t offset = reloc.get_r_offset();
-      if (offset < 0 || offset >= view_size)
-       {
-         fprintf(stderr, _("%s: %s: reloc %zu has bad offset %lu\n"),
-                 program_name, object->name().c_str(), i,
-                 static_cast<unsigned long>(offset));
-         gold_exit(false);
-       }
 
       typename elfcpp::Elf_types<size>::Elf_WXword r_info = reloc.get_r_info();
       unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
       unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
 
-      Sized_symbol<size>* sym;
-      typename elfcpp::Elf_types<size>::Elf_Addr value;
+      const Sized_symbol<size>* sym;
 
+      Symbol_value<size> symval;
+      const Symbol_value<size> *psymval;
       if (r_sym < local_count)
        {
          sym = NULL;
-         value = local_values[r_sym];
+         psymval = &(*local_values)[r_sym];
        }
       else
        {
-         Symbol* gsym = global_syms[r_sym - local_count];
-         assert(gsym != NULL);
+         const Symbol* gsym = global_syms[r_sym - local_count];
+         gold_assert(gsym != NULL);
          if (gsym->is_forwarder())
-           gsym = symtab->resolve_forwards(gsym);
+           gsym = relinfo->symtab->resolve_forwards(gsym);
+
+         sym = static_cast<const Sized_symbol<size>*>(gsym);
+         if (sym->has_symtab_index())
+           symval.set_output_symtab_index(sym->symtab_index());
+         else
+           symval.set_no_output_symtab_entry();
+         symval.set_output_value(sym->value());
+         psymval = &symval;
+       }
 
-         sym = static_cast<Sized_symbol<size>*>(gsym);
-         value = sym->value();
+      if (!relocate.relocate(relinfo, target, i, reloc, r_type, sym, psymval,
+                            view + offset, view_address + offset, view_size))
+       continue;
 
-         if (sym->shnum() == elfcpp::SHN_UNDEF
-             && sym->binding() != elfcpp::STB_WEAK)
-           {
-             fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
-                     program_name, object->name().c_str(), sym->name());
-             // gold_exit(false);
-           }
+      if (offset < 0 || offset >= view_size)
+       {
+         fprintf(stderr, _("%s: %s: reloc has bad offset %zu\n"),
+                 program_name, relinfo->location(i, offset).c_str(),
+                 static_cast<size_t>(offset));
+         gold_exit(false);
+       }
+
+      if (sym != NULL
+         && sym->is_undefined()
+         && sym->binding() != elfcpp::STB_WEAK)
+       {
+         fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"),
+                 program_name, relinfo->location(i, offset).c_str(),
+                 sym->name());
+         gold_exit(false);
        }
 
-      relocate(object, reloc, r_type, sym, value, view + offset,
-              view_address + offset);
+      if (sym != NULL && sym->has_warning())
+       relinfo->symtab->issue_warning(sym, relinfo->location(i, offset));
     }
 }
 
This page took 0.026222 seconds and 4 git commands to generate.