GOLD: RFA: Add support for RX target

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

GOLD: RFA: Add support for RX target

Nick Clifton
Hi Ian,

  Here is a patch to add support for the Renesas RX target to GOLD.  It
  is functional, but it does not yet implement relaxation.  Other than
  that though it is good to go.

  OK to apply ?

Cheers
  Nick

./ChangeLog
2010-12-13  Nick Clifton  <[hidden email]>

        * configure.ac: Add RX to list of targets for which
        --enable-gold is valid.
        * configure: Regenerate.

elfcpp/ChangeLog
2010-12-13  Nick Clifton  <[hidden email]>

        * rx.h: New file.  Contains ELF definitions specific to the
        Renesas RX architecture.
        * elfcpp.h (enum EM): Add EM_RX.

gold/ChangeLog
2010-12-13  Nick Clifton  <[hidden email]>

        * rx.cc: New file.  Adds support for Renesas RX architecture.
        * Makefile.am (TARGETSOURCES): Add rx.cc.
        (ALL_TARGETOBJS): Add rx.$(OBJEXT)
        * Makefile.in: Regenerate.
        * configure.ac: Add RX as a default target.
        * configure: Regenerate.
        * configure.tgt: Add rx-*-* as a supported target.


Index: configure.ac
===================================================================
RCS file: /cvs/src/src/configure.ac,v
retrieving revision 1.122
diff -u -3 -p -r1.122 configure.ac
--- configure.ac 10 Dec 2010 14:50:10 -0000 1.122
+++ configure.ac 13 Dec 2010 09:40:51 -0000
@@ -367,7 +367,7 @@ case "${ENABLE_GOLD}" in
     if test "$is_elf" = "yes"; then
       # Check for target supported by gold.
       case "${target}" in
-        i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-*)
+        i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* | rx-*-*)
   configdirs="$configdirs gold"
   if test x${ENABLE_GOLD} = xdefault; then
     default_ld=gold
Index: elfcpp/elfcpp.h
===================================================================
RCS file: /cvs/src/src/elfcpp/elfcpp.h,v
retrieving revision 1.32
diff -u -3 -p -r1.32 elfcpp.h
--- elfcpp/elfcpp.h 12 Aug 2010 22:18:14 -0000 1.32
+++ elfcpp/elfcpp.h 13 Dec 2010 09:40:52 -0000
@@ -269,6 +269,8 @@ enum EM
   EM_UNICORE = 110,
   EM_ALTERA_NIOS2 = 113,
   EM_CRX = 114,
+  // Renesas RX.
+  EM_RX = 173,
   // The Morph MT.
   EM_MT = 0x2530,
   // DLX.
Index: gold/Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/Makefile.am,v
retrieving revision 1.62
diff -u -3 -p -r1.62 Makefile.am
--- gold/Makefile.am 27 Apr 2010 16:05:48 -0000 1.62
+++ gold/Makefile.am 13 Dec 2010 09:40:54 -0000
@@ -140,11 +140,11 @@ DEFFILES = arm-reloc.def
 EXTRA_DIST = yyscript.c yyscript.h
 
 TARGETSOURCES = \
- i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc
+ i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc rx.cc
 
 ALL_TARGETOBJS = \
  i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \
- arm.$(OBJEXT) arm-reloc-property.$(OBJEXT)
+ arm.$(OBJEXT) arm-reloc-property.$(OBJEXT) rx.$(OBJEXT)
 
 libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES)
 libgold_a_LIBADD = $(LIBOBJS)
Index: gold/configure.ac
===================================================================
RCS file: /cvs/src/src/gold/configure.ac,v
retrieving revision 1.60
diff -u -3 -p -r1.60 configure.ac
--- gold/configure.ac 23 Nov 2010 13:39:56 -0000 1.60
+++ gold/configure.ac 13 Dec 2010 09:40:55 -0000
@@ -188,6 +188,7 @@ for targ in $target $canon_targets; do
  AM_CONDITIONAL(DEFAULT_TARGET_ARM, test "$targ_obj" = "arm")
  AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386")
  AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc")
+ AM_CONDITIONAL(DEFAULT_TARGET_RX, test "$targ_obj" = "rx")
  AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc")
  AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64")
       fi
Index: gold/configure.tgt
===================================================================
RCS file: /cvs/src/src/gold/configure.tgt,v
retrieving revision 1.8
diff -u -3 -p -r1.8 configure.tgt
--- gold/configure.tgt 3 Feb 2010 05:36:55 -0000 1.8
+++ gold/configure.tgt 13 Dec 2010 09:40:55 -0000
@@ -120,6 +120,12 @@ arm*-*-*)
  targ_big_endian=false
  targ_extra_big_endian=true
  ;;
+rx-*-*)
+ targ_obj=rx
+ targ_machine=EM_RX
+ targ_size=32
+ targ_big_endian=true
+ ;;
 *)
   targ_obj=UNKNOWN
   ;;
*** /dev/null 2010-12-10 13:21:07.444000002 +0000
--- gold/rx.cc 2010-12-13 09:19:49.000000000 +0000
***************
*** 0 ****
--- 1,971 ----
+ // rx.cc -- Renesas RX target support for gold.
+
+ // Copyright 2010 Free Software Foundation, Inc.
+ // Written by Nick Clifton <[hidden email]>.
+ // Based on code in the gold sources written by Ian Lance Taylor
+ // <[hidden email]> and Doug Kwan <[hidden email]>.
+ // This file also contains borrowed and adapted code from
+ // bfd/elf32-rx.c.
+
+ // 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.
+
+ #include "gold.h"
+
+ #include <cstdio>
+ #include <cstring>
+ #include <limits>
+ #include <cstdio>
+ #include <string>
+ #include <algorithm>
+ #include <map>
+ #include <utility>
+ #include <set>
+
+ #include "elfcpp.h"
+ #include "parameters.h"
+ #include "reloc.h"
+ #include "rx.h"
+ #include "object.h"
+ #include "symtab.h"
+ #include "layout.h"
+ #include "output.h"
+ #include "copy-relocs.h"
+ #include "target.h"
+ #include "target-reloc.h"
+ #include "target-select.h"
+ #include "tls.h"
+ #include "defstd.h"
+ #include "gc.h"
+
+ namespace rx
+ {
+ using namespace gold;
+
+ // For convenience.
+ typedef elfcpp::Elf_types<32>::Elf_Addr RX_address;
+
+
+ // Note - this class is not templated on the endian-ness.  The RX architecture
+ // is basically little-endian, but with one troublesome exception.  It has
+ // separate data- and code- busses and the data-bus can be set to be
+ // big-endian.  Thus you can have little endian code executing with
+ // big-endian data.  Apart from special handling of relocs and the symbol
+ // table however this should not matter to the linker.  It does though because
+ // the assembler (gas) sets the data encoding of object files with big-endian
+ // data to ELFDATA2MSB.  GOLD automatically recognises this and happily
+ // byte-swaps bits of the object file as they are being read in and written
+ // out.  Since most of the contents of the object files are *not* big-endian,
+ // this causes all kinds of problems.  Working around this feature takes up
+ // much of the code below.
+  
+ class Target_rx : public Sized_target<32, false>
+ {
+  public:
+   typedef Output_data_reloc<elfcpp::SHT_RELA, true, 32, false> Reloc_section;
+
+   Target_rx(bool big_endian_data)
+     : Sized_target<32, false>(& rx_info)
+   { bed = big_endian_data; }
+
+   bool
+   uses_bigendian_data (void) const
+   { return bed; }
+  
+   // Relocate a section during a relocatable link.
+   void
+   relocate_for_relocatable(const Relocate_info<32, false>*,
+   unsigned int, const unsigned char*,
+   size_t, Output_section*, off_t,
+   const Relocatable_relocs*,
+   unsigned char*, RX_address,
+   section_size_type, unsigned char*,
+   section_size_type);
+
+   // Process the relocations to determine unreferenced sections for
+   // garbage collection.
+   void
+   gc_process_relocs(Symbol_table*, Layout*,
+    Sized_relobj<32, false>*,
+    unsigned int, unsigned int, const unsigned char*,
+    size_t, Output_section*, bool, size_t,
+    const unsigned char*);
+
+   // Scan the relocations to look for symbol adjustments.
+   void
+   scan_relocs(Symbol_table*, Layout*, Sized_relobj<32, false>*,
+      unsigned int, unsigned int, const unsigned char*,
+      size_t, Output_section*, bool, size_t,
+      const unsigned char*);
+
+   // Relocate a section.
+   void
+   relocate_section(const Relocate_info<32, false>*,
+   unsigned int, const unsigned char*, size_t,
+   Output_section*, bool, unsigned char*,
+   RX_address, section_size_type,
+   const Reloc_symbol_changes*);
+
+   // Scan the relocs during a relocatable link.
+   void
+   scan_relocatable_relocs(Symbol_table*, Layout*,
+  Sized_relobj<32, false>*,
+  unsigned int, unsigned int,
+  const unsigned char*, size_t,
+  Output_section*, bool, size_t,
+  const unsigned char*, Relocatable_relocs*);
+
+   // Return whether there is a GOT section.
+   bool
+   has_got_section() const
+   { return false; }
+
+   // Return the size of the GOT section.
+   section_size_type
+   got_size()
+   { return 0; }
+
+  
+  protected:
+   bool
+   do_may_relax() const
+   { return false; }
+
+   bool
+   do_relax(int, const Input_objects*, Symbol_table*, Layout*);
+
+   // Make an ELF object - two varieties, one for each type of ELF header.
+   Object*
+   do_make_elf_object(const std::string&, Input_file*, off_t,
+     const elfcpp::Ehdr<32, false>& ehdr);
+
+   Object*
+   do_make_elf_object(const std::string&, Input_file*, off_t,
+     const elfcpp::Ehdr<32, true>& ehdr);
+
+  private:
+   bool bed;
+
+   bool
+   check_type_and_flags (int, elfcpp::Elf_Word, const char *);
+  
+   // The class which scans relocations.
+   class Scan
+   {
+    public:
+     Scan()
+     { }
+
+     inline void
+     local(Symbol_table*, Layout*, Target_rx*, Sized_relobj<32, false>*,
+  unsigned int, Output_section*, const elfcpp::Rela<32, false>&,
+  unsigned int, const elfcpp::Sym<32, false>&);
+
+     inline void
+     global(Symbol_table*, Layout*, Target_rx*, Sized_relobj<32, false>*,
+   unsigned int, Output_section*, const elfcpp::Rela<32, false>&,
+   unsigned int, Symbol*);
+
+     inline bool
+     local_reloc_may_be_function_pointer(Symbol_table*, Layout*, Target_rx*,
+           Sized_relobj<32, false>*,
+                unsigned int, Output_section*,
+           const elfcpp::Rela<32, false>&,
+ unsigned int,
+           const elfcpp::Sym<32, false>&)
+     { return false; }
+
+     inline bool
+     global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
+ Target_rx* ,
+   Sized_relobj<32, false>* ,
+   unsigned int ,
+   Output_section* ,
+   const elfcpp::Rela<32, false>& ,
+ unsigned int , Symbol*)
+     { return false; }
+   };
+
+   // The class which implements relocation.
+   class Relocate
+   {
+    public:
+     Relocate()
+     { }
+
+     ~Relocate()
+     { }
+
+     // Do a relocation.  Return false if the caller should not issue
+     // any warnings about this relocation.
+     inline bool
+     relocate(const Relocate_info<32, false>*, Target_rx*,
+     Output_section*,  size_t,
+     const elfcpp::Rela<32, false>&,
+     unsigned int, const Sized_symbol<32>*,
+     const Symbol_value<32>*,
+     unsigned char*, RX_address, section_size_type);
+   };
+
+   // A class which returns the size required for a relocation type,
+   // used while scanning relocs during a relocatable link.
+   class Relocatable_size_for_reloc
+   {
+    public:
+     unsigned int
+     get_size_for_reloc(unsigned int, Relobj*);
+   };
+  
+   // Information about this specific target which
+   // we pass to the general Target structure.
+   static const Target::Target_info rx_info;
+ };
+
+ const Target::Target_info Target_rx::rx_info =
+ {
+   32, // size
+   false, // is_big_endian_data
+   elfcpp::EM_RX, // machine_code
+   false, // has_make_symbol
+   false, // has_resolve
+   false, // has_code_fill
+   true, // is_default_stack_executable
+   '\0', // wrap_char
+   NULL, // dynamic_linker
+   0x10000000, // default_text_segment_address
+   0x1000, // abi_pagesize (overridable by -z max-page-size)
+   0x1000, // common_pagesize (overridable by -z common-page-size)
+   elfcpp::SHN_UNDEF, // small_common_shndx
+   elfcpp::SHN_UNDEF, // large_common_shndx
+   0, // small_common_section_flags
+   0, // large_common_section_flags
+   NULL, // attributes_section
+   NULL // attributes_vendor
+ };
+
+ class RX_relocation_functions : public Relocate_functions<32, false>
+ {
+ private:
+   typedef elfcpp::Swap<32, false>::Valtype Valtype;
+
+   // Do a simple absolute relocation using a symbol value and the addend.
+   static inline void
+   abs(unsigned char*                    view,
+       const Sized_relobj<32, false>*    object,
+       const Symbol_value<32>*           psymval,
+       elfcpp::Swap<32, false>::Valtype  addend)
+   {
+     Valtype*  wv = reinterpret_cast<Valtype*>(view);
+     Valtype   reloc = psymval->value(object, addend);
+     elfcpp::Swap<32, false>::writeval(wv, reloc);
+   }
+
+   // Do a simple PC relative relocation with a symbol value, an
+   // addend, and the bits from the view not in the mask.  
+   static inline void
+   pcrel(unsigned char*                    view,
+ unsigned int                      right_shift,
+ elfcpp::Elf_Xword                 dst_mask,
+ const Sized_relobj<32, false>*    object,
+ const Symbol_value<32>*           psymval,
+ elfcpp::Swap<32, false>::Valtype  addend,
+ RX_address                        address)
+   {
+     Valtype* wv = reinterpret_cast<Valtype*>(view);
+     Valtype val = elfcpp::Swap<32, false>::readval(wv);
+     Valtype reloc = (psymval->value(object, addend) - address) >> right_shift;
+
+     val &= ~dst_mask;
+     reloc &= dst_mask;
+
+     elfcpp::Swap<32, false>::writeval(wv, val | reloc);
+   }
+
+   typedef RX_relocation_functions This_reloc;
+
+ public:
+   // R_RX_DIR32: (Symbol + Addend)
+   static inline void
+   dir32(unsigned char*                  view,
+ const Sized_relobj<32, false>*  object,
+ const Symbol_value<32>*         psymval,
+ RX_address                      addend)
+   {
+     This_reloc::abs(view, object, psymval, addend);
+   }
+
+   // R_RX_DIR24S_PCREL: (Symbol + Addend - Address) & 0x00ffffff
+   static inline void
+   dir24s_pcrel(unsigned char*                  view,
+       const Sized_relobj<32, false>*  object,
+       const Symbol_value<32>*         psymval,
+       RX_address                      addend,
+       RX_address                      address)
+   {
+     // Note - address holds the location of the start of
+     // the relocation, which is one byte after the start
+     // of the BSR instruction, hence the bias in the
+     // invocation below.
+     This_reloc::pcrel(view, 0, 0x00ffffff, object, psymval, addend,
+      address - 1);
+   }
+
+   // R_RX_DIR8S_PCREL: (Symbol + Addend - Address) & 0x000000ff
+   static inline void
+   dir8s_pcrel(unsigned char*                  view,
+      const Sized_relobj<32, false>*  object,
+      const Symbol_value<32>*         psymval,
+      RX_address                      addend,
+      RX_address                      address)
+   {
+     This_reloc::pcrel(view, 0, 0x000000ff, object, psymval, addend,
+      address - 1);
+   }
+ };
+
+ // Relaxation hook.
+
+ bool
+ Target_rx::do_relax(int                   ,
+    const Input_objects*  ,
+    Symbol_table*         ,
+    Layout*               )
+ {
+   return true;
+ }
+
+ // Perform a relocation.
+
+ inline bool
+ Target_rx::Relocate::relocate(
+     const Relocate_info<32, false>*  relinfo,
+     Target_rx*                       target,
+     Output_section *                 /* output_section */,
+     size_t                           relnum,
+     const elfcpp::Rela<32, false>&   rela,
+     unsigned int                     r_type,
+     const Sized_symbol<32>*          /* gsym */,
+     const Symbol_value<32>*          psymval,
+     unsigned char*                   view,
+     RX_address                       address,
+     section_size_type                /* view_size */)
+ {
+   typedef RX_relocation_functions Reloc;
+   elfcpp::Elf_Xword addend = rela.get_r_addend();
+
+   if (target->uses_bigendian_data ())
+     addend = elfcpp::Convert<32, true>::convert_host(addend);
+
+   switch (r_type)
+     {
+     case elfcpp::R_RX_DIR32:
+       Reloc::dir32(view, relinfo->object, psymval, addend);
+       break;
+     case elfcpp::R_RX_DIR24S_PCREL:
+       Reloc::dir24s_pcrel(view, relinfo->object, psymval, addend, address);
+       break;
+     case elfcpp::R_RX_DIR8S_PCREL:
+       Reloc::dir8s_pcrel(view, relinfo->object, psymval, addend, address);
+       break;
+
+       // XXX FIXME: Implement the remaining relocations.
+
+     default:
+       gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
+     _("unsupported reloc %u"),
+     r_type);
+       break;
+     }
+   return true;
+ }
+
+ // Scan a relocation for a local symbol.
+
+ inline void
+ Target_rx::Scan::local(Symbol_table*                   ,
+       Layout*                         ,
+       Target_rx*                      ,
+       Sized_relobj<32, false>*        object,
+       unsigned int                    ,
+       Output_section*                 ,
+       const elfcpp::Rela<32, false>&  ,
+       unsigned int                    r_type,
+       const elfcpp::Sym<32, false>&   )
+ {
+   switch (r_type)
+     {
+     case elfcpp::R_RX_DIR32:
+     case elfcpp::R_RX_DIR24S_PCREL:
+     case elfcpp::R_RX_DIR8S_PCREL:
+       break;
+
+     default:
+       gold_error(_("%s: unsupported reloc %u against local symbol"),
+ object->name().c_str(), r_type);
+       break;
+     }
+ }
+
+ // Scan a relocation for a global symbol.
+
+ inline void
+ Target_rx::Scan::global(Symbol_table*                   ,
+ Layout*                         ,
+ Target_rx*                      ,
+ Sized_relobj<32, false>*        object,
+ unsigned int                    ,
+ Output_section*                 ,
+ const elfcpp::Rela<32, false>&  ,
+ unsigned int                    r_type,
+ Symbol*                         gsym)
+ {
+   switch (r_type)
+     {
+     case elfcpp::R_RX_DIR32:
+     case elfcpp::R_RX_DIR24S_PCREL:
+     case elfcpp::R_RX_DIR8S_PCREL:
+       break;
+
+     default:
+       gold_error(_("%s: unsupported reloc %u against global symbol %s"),
+ object->name().c_str(), r_type, gsym->demangled_name().c_str());
+       break;
+     }
+ }
+
+ // Scan the relocs during a relocatable link.
+
+ void
+ Target_rx::scan_relocatable_relocs(Symbol_table*             symtab,
+   Layout*                   layout,
+   Sized_relobj<32, false>*  object,
+   unsigned int              data_shndx,
+   unsigned int              sh_type,
+   const unsigned char*      prelocs,
+   size_t                    reloc_count,
+   Output_section*           output_section,
+   bool                      needs_special_offset_handling,
+   size_t                    local_symbol_count,
+   const unsigned char*      plocal_symbols,
+   Relocatable_relocs*       rr)
+ {
+   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+   typedef gold::Default_scan_relocatable_relocs<elfcpp::SHT_RELA,
+     Relocatable_size_for_reloc> Scan_relocatable_relocs;
+
+   gold::scan_relocatable_relocs<32, false, elfcpp::SHT_RELA,
+       Scan_relocatable_relocs>(symtab,
+       layout,
+       object,
+       data_shndx,
+       prelocs,
+       reloc_count,
+       output_section,
+       needs_special_offset_handling,
+       local_symbol_count,
+       plocal_symbols,
+       rr);
+ }
+
+ // Relocate section data.
+
+ void
+ Target_rx::relocate_section(
+     const Relocate_info<32, false>*  relinfo,
+     unsigned int                     sh_type,
+     const unsigned char*             prelocs,
+     size_t                           reloc_count,
+     Output_section*                  output_section,
+     bool                             needs_special_offset_handling,
+     unsigned char*                   view,
+     RX_address                       address,
+     section_size_type                view_size,
+     const Reloc_symbol_changes*      reloc_symbol_changes)
+ {
+   typedef Target_rx::Relocate Rx_relocate;
+
+   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+   // See if we are relocating a relaxed input section.  If so, the view
+   // covers the whole output section and we need to adjust accordingly.
+   if (needs_special_offset_handling)
+     {
+       const Output_relaxed_input_section* poris =
+ output_section->find_relaxed_input_section(relinfo->object,
+   relinfo->data_shndx);
+       if (poris != NULL)
+ {
+  RX_address section_address = poris->address();
+  section_size_type section_size = poris->data_size();
+
+  gold_assert((section_address >= address)
+      && ((section_address + section_size)
+  <= (address + view_size)));
+
+  off_t offset = section_address - address;
+  view += offset;
+  address += offset;
+  view_size = section_size;
+ }
+     }
+
+   if (uses_bigendian_data ())
+     {
+       // This is a copy of the relocate_section() function in target-reloc.h,
+       // except with the additional calls to convert_host to fix up the
+       // extracted information.
+       // FIXME: There ought to be a better way to do this.
+
+       typedef Reloc_types<elfcpp::SHT_RELA, 32, false>::Reloc Reltype;
+       const int reloc_size = Reloc_types<elfcpp::SHT_RELA, 32, false>::reloc_size;
+       Relocate relocate;
+
+       Sized_relobj<32, false>* object = relinfo->object;
+       unsigned int local_count = object->local_symbol_count();
+
+       Comdat_behavior comdat_behavior = CB_UNDETERMINED;
+
+       for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+  Reltype reloc(prelocs);
+
+  section_offset_type offset =
+    convert_to_section_size_type(reloc.get_r_offset());
+
+  offset = elfcpp::Convert<32, true>::convert_host(offset);
+  
+  if (needs_special_offset_handling)
+    {
+      offset = output_section->output_offset(relinfo->object,
+     relinfo->data_shndx,
+     offset);
+      if (offset == -1)
+ continue;
+    }
+
+  elfcpp::Elf_types<32>::Elf_WXword r_info = reloc.get_r_info();
+
+  r_info = elfcpp::Convert<32, true>::convert_host(r_info);
+
+  unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
+  unsigned int r_type = elfcpp::elf_r_type<32>(r_info);
+
+  const Sized_symbol<32>* sym;
+  Symbol_value<32> symval;
+  const Symbol_value<32> *psymval;
+  bool is_defined_in_discarded_section;
+  unsigned int shndx;
+
+  if (r_sym < local_count
+      && (reloc_symbol_changes == NULL
+  || (*reloc_symbol_changes)[i] == NULL))
+    {
+      sym = NULL;
+      psymval = object->local_symbol(r_sym);
+
+      // If the local symbol belongs to a section we are discarding,
+      // and that section is a debug section, try to find the
+      // corresponding kept section and map this symbol to its
+      // counterpart in the kept section.  The symbol must not
+      // correspond to a section we are folding.
+      bool is_ordinary;
+
+      shndx = psymval->input_shndx(&is_ordinary);
+      is_defined_in_discarded_section =
+ (is_ordinary
+ && shndx != elfcpp::SHN_UNDEF
+ && !object->is_section_included(shndx)
+ && !relinfo->symtab->is_section_folded(object, shndx));
+    }
+  else
+    {
+      const Symbol* gsym;
+
+      if (reloc_symbol_changes != NULL
+  && (*reloc_symbol_changes)[i] != NULL)
+ gsym = (*reloc_symbol_changes)[i];
+      else
+ {
+  gsym = object->global_symbol(r_sym);
+  gold_assert(gsym != NULL);
+  if (gsym->is_forwarder())
+    gsym = relinfo->symtab->resolve_forwards(gsym);
+ }
+
+      sym = static_cast<const Sized_symbol<32>*>(gsym);
+      if (sym->has_symtab_index() && sym->symtab_index() != -1U)
+ symval.set_output_symtab_index(sym->symtab_index());
+      else
+ symval.set_no_output_symtab_entry();
+      symval.set_output_value(sym->value());
+      psymval = &symval;
+
+      is_defined_in_discarded_section =
+ (gsym->is_defined_in_discarded_section()
+ && gsym->is_undefined());
+      shndx = 0;
+    }
+
+  Symbol_value<32> symval2;
+  if (is_defined_in_discarded_section)
+    {
+      if (comdat_behavior == CB_UNDETERMINED)
+ {
+  std::string name = object->section_name(relinfo->data_shndx);
+  comdat_behavior = get_comdat_behavior(name.c_str());
+ }
+      if (comdat_behavior == CB_PRETEND)
+ {
+  // FIXME: This case does not work for global symbols.
+  // We have no place to store the original section index.
+  // Fortunately this does not matter for comdat sections,
+  // only for sections explicitly discarded by a linker
+  // script.
+  bool found;
+  elfcpp::Elf_types<32>::Elf_Addr value =
+    object->map_to_kept_section(shndx, &found);
+
+  if (found)
+    symval2.set_output_value(value + psymval->input_value());
+  else
+    symval2.set_output_value(0);
+ }
+      else
+ {
+  if (comdat_behavior == CB_WARNING)
+    gold_warning_at_location(relinfo, i, offset,
+     _("relocation refers to discarded "
+       "section"));
+  symval2.set_output_value(0);
+ }
+      symval2.set_no_output_symtab_entry();
+      psymval = &symval2;
+    }
+
+  if (!relocate.relocate(relinfo, this, output_section, i, reloc,
+ r_type, sym, psymval, view + offset,
+ address + offset, view_size))
+    continue;
+
+  if (offset < 0 || static_cast<section_size_type>(offset) >= view_size)
+    {
+      gold_error_at_location(relinfo, i, offset,
+     _("reloc has bad offset %zu"),
+     static_cast<size_t>(offset));
+      continue;
+    }
+
+  if (sym != NULL
+      && (sym->is_undefined() || sym->is_placeholder())
+      && sym->binding() != elfcpp::STB_WEAK
+      && !is_defined_in_discarded_section
+      && !this->is_defined_by_abi(sym)
+      && (!parameters->options().shared()       // -shared
+  || parameters->options().defs()))     // -z defs
+    gold_undefined_symbol_at_location(sym, relinfo, i, offset);
+  else if (sym != NULL
+   && sym->visibility() != elfcpp::STV_DEFAULT
+   && (sym->is_undefined() || sym->is_from_dynobj()))
+    visibility_error(sym);
+
+  if (sym != NULL && sym->has_warning())
+    relinfo->symtab->issue_warning(sym, relinfo, i, offset);
+ }
+     }
+   else
+     gold::relocate_section<32, false, Target_rx, elfcpp::SHT_RELA,
+     Rx_relocate>(relinfo, this, prelocs, reloc_count, output_section,
+ needs_special_offset_handling, view, address,
+ view_size, reloc_symbol_changes);
+ }
+
+ // Scan relocations for a section.
+
+ void
+ Target_rx::scan_relocs(Symbol_table*             symtab,
+       Layout*                   layout,
+       Sized_relobj<32, false>*  object,
+       unsigned int              data_shndx,
+       unsigned int              sh_type,
+       const unsigned char*      prelocs,
+       size_t                    reloc_count,
+       Output_section*           output_section,
+       bool                      needs_special_offset_handling,
+       size_t                    local_count,
+       const unsigned char*      plocal_symbols)
+ {
+   typedef Target_rx::Scan Scan;
+
+   if (sh_type == elfcpp::SHT_REL)
+     {
+       gold_error(_("%s: unsupported REL reloc section"),
+ object->name().c_str());
+       return;
+     }
+
+   if (uses_bigendian_data ())
+     {
+       // This is a copy of the scan_relocs() function in target-reloc.h,
+       // except with the additional calls to convert_host to fix up the
+       // extracted information.
+       // FIXME: There ought to be a better way to do this.
+
+       typedef Reloc_types<elfcpp::SHT_RELA, 32, false>::Reloc Reltype;
+       const int reloc_size = Reloc_types<elfcpp::SHT_RELA, 32, false>::reloc_size;
+       const int sym_size = elfcpp::Elf_sizes<32>::sym_size;
+       Scan scan;
+
+       for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
+ {
+  Reltype reloc(prelocs);
+
+  if (needs_special_offset_handling
+      && !output_section->is_input_address_mapped(object, data_shndx,
+  reloc.get_r_offset()))
+    continue;
+
+  elfcpp::Elf_types<32>::Elf_WXword r_info = reloc.get_r_info();
+
+  r_info = elfcpp::Convert<32, true>::convert_host(r_info);
+  
+  unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
+  unsigned int r_type = elfcpp::elf_r_type<32>(r_info);
+
+  if (r_sym < local_count)
+    {
+      gold_assert(plocal_symbols != NULL);
+      elfcpp::Sym<32, false> lsym(plocal_symbols + r_sym * sym_size);
+      unsigned int shndx = lsym.get_st_shndx();
+      bool is_ordinary;
+
+      shndx = elfcpp::Convert<16, true>::convert_host(shndx);
+
+      shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);      
+      if (is_ordinary
+  && shndx != elfcpp::SHN_UNDEF
+  && !object->is_section_included(shndx)
+  && !symtab->is_section_folded(object, shndx))
+      continue;
+
+      scan.local(symtab, layout, this, object, data_shndx,
+ output_section, reloc, r_type, lsym);
+    }
+  else
+    {
+      Symbol* gsym = object->global_symbol(r_sym);
+
+      gold_assert(gsym != NULL);
+      if (gsym->is_forwarder())
+ gsym = symtab->resolve_forwards(gsym);
+
+      scan.global(symtab, layout, this, object, data_shndx,
+  output_section, reloc, r_type, gsym);
+    }
+ }
+     }
+   else
+     gold::scan_relocs<32, false, Target_rx, elfcpp::SHT_RELA, Scan>
+       (symtab, layout, this, object, data_shndx, prelocs, reloc_count,
+        output_section, needs_special_offset_handling, local_count,
+        plocal_symbols);
+ }
+
+ // Process relocations for gc.
+
+ void
+ Target_rx::gc_process_relocs(Symbol_table*             /*symtab*/,
+     Layout*                   /*layout*/,
+     Sized_relobj<32, false>*  /*object*/,
+     unsigned int              /*data_shndx*/,
+     unsigned int              ,
+     const unsigned char*      /*prelocs*/,
+     size_t                    /*reloc_count*/,
+     Output_section*           /*output_section*/,
+     bool                      /*needs_special_offset_handling*/,
+     size_t                    /*local_symbol_count*/,
+     const unsigned char*      /*plocal_symbols*/)
+ {
+ #if 0
+   typedef Target_rx RX;
+   typedef Target_rx::Scan Scan;
+
+   gold::gc_process_relocs<32, false, RX, elfcpp::SHT_RELA, Scan>
+     (symtab, layout, this, object, data_shndx, prelocs,
+      reloc_count, output_section, needs_special_offset_handling,
+      local_symbol_count, plocal_symbols);
+ #endif
+ }
+
+ // Relocate a section during a relocatable link.
+
+ void
+ Target_rx::relocate_for_relocatable(
+     const Relocate_info<32, false>*  relinfo,
+     unsigned int                     sh_type,
+     const unsigned char*             prelocs,
+     size_t                           reloc_count,
+     Output_section*                  output_section,
+     off_t                            offset_in_output_section,
+     const Relocatable_relocs*        rr,
+     unsigned char*                   view,
+     RX_address                       view_address,
+     section_size_type                view_size,
+     unsigned char*                   reloc_view,
+     section_size_type                reloc_view_size)
+ {
+   gold_assert(sh_type == elfcpp::SHT_RELA);
+
+   gold::relocate_for_relocatable<32, false, elfcpp::SHT_RELA>
+     (relinfo, prelocs, reloc_count,output_section,
+      offset_in_output_section, rr, view, view_address,
+      view_size, reloc_view, reloc_view_size);
+ }
+
+
+ static const char *
+ flag_meaning(elfcpp::Elf_Word flags, elfcpp::Elf_Word other_flags)
+ {
+   switch (flags)
+     {
+     case elfcpp::E_FLAG_RX_64BIT_DOUBLES:
+       return "uses 64-bit doubles";
+     case elfcpp::E_FLAG_RX_DSP:
+       return "uses DSP instructions";
+     case elfcpp::E_FLAG_RX_64BIT_DOUBLES | elfcpp::E_FLAG_RX_DSP:
+       switch (other_flags)
+ {
+ case 0:
+  return "uses 64-bit doubles & DSP instructions";
+ case elfcpp::E_FLAG_RX_64BIT_DOUBLES:
+  return "uses DSP instructions";
+ case elfcpp::E_FLAG_RX_DSP:
+  return "uses 64-bit doubles";
+ default:
+  gold_unreachable();
+ }
+     case 0:
+       switch (other_flags)
+ {
+ case elfcpp::E_FLAG_RX_64BIT_DOUBLES | elfcpp::E_FLAG_RX_DSP:
+ case elfcpp::E_FLAG_RX_64BIT_DOUBLES:
+  return "uses 32-bit doubles";
+ case elfcpp::E_FLAG_RX_DSP:
+  return "synthesies DSP instructions";
+ default:
+  gold_unreachable();
+ }
+     default:
+       gold_unreachable();
+     }
+ }
+
+ bool
+ Target_rx::check_type_and_flags (int type, elfcpp::Elf_Word flags, const char * name)
+ {
+   static const char * saved_name = NULL;
+
+   if (type != elfcpp::ET_REL)
+     {
+       gold_error(_("%s: unsupported ELF file type %d"), name, type);
+       return false;
+     }
+
+   if (are_processor_specific_flags_set())
+     {
+       static elfcpp::Elf_Word previous_flags = -1;
+       elfcpp::Elf_Word set_flags = processor_specific_flags();
+
+       if (set_flags != flags
+  && previous_flags != flags)
+ {
+  // Make sure that we do not complain about this particular
+  // discrepancy more than once in a row.
+  previous_flags = flags;
+
+  gold_error(_("%s: %s whereas %s does not"),
+     name, flag_meaning(flags, set_flags), saved_name);
+
+  return false;
+ }
+     }
+   else if (flags)
+     {
+       set_processor_specific_flags(flags);
+       saved_name = name;
+     }
+
+   return true;
+ }
+
+ // Use do_make_elf_object to override the same function in the base class.
+ // We need to checks the ELF header flags before allowing the object to be
+ // made.
+ Object*
+ Target_rx::do_make_elf_object(const std::string&              name,
+      Input_file*                     input_file,
+      off_t                           offset,
+      const elfcpp::Ehdr<32, false>&  ehdr)
+ {
+   if (! check_type_and_flags (ehdr.get_e_type(),
+      ehdr.get_e_flags(),
+      name.c_str ()))
+     return NULL;
+
+   Sized_relobj<32, false>* obj =
+     new Sized_relobj<32, false>(name, input_file, offset, ehdr);
+   obj->setup();
+   return obj;
+ }
+
+ Object*
+ Target_rx::do_make_elf_object(const std::string&             name,
+      Input_file*                    input_file,
+      off_t                          offset,
+      const elfcpp::Ehdr<32, true>&  ehdr)
+ {
+   if (! check_type_and_flags (ehdr.get_e_type(),
+      ehdr.get_e_flags(),
+      name.c_str ()))
+     return NULL;
+
+   Sized_relobj<32, true>* obj =
+     new Sized_relobj<32, true>(name, input_file, offset, ehdr);
+   obj->setup();
+   return obj;
+ }
+
+
+ template<bool big_endian_data>
+ class Target_selector_rx : public Target_selector
+ {
+  public:
+   Target_selector_rx()
+     : Target_selector(elfcpp::EM_RX, 32, big_endian_data,
+      (big_endian_data ? "elf32-rx-be" : "elf32-rx-le"))
+   { }
+
+   Target*
+   do_instantiate_target()
+   { return new Target_rx(big_endian_data); }
+ };
+
+
+ Target_selector_rx<false> target_selector_rx;
+ Target_selector_rx<true>  target_selector_rxbe;
+
+ } // End rx namespace.
*** /dev/null 2010-12-10 13:21:07.444000002 +0000
--- elfcpp/rx.h 2010-12-13 09:25:50.000000000 +0000
***************
*** 0 ****
--- 1,139 ----
+ // rx.h -- ELF definitions specific to EM_RX  -*- C++ -*-
+
+ // Copyright 2010, Free Software Foundation, Inc.
+ // Written by Nick Clifton <[hidden email]>
+
+ // This file is part of elfcpp.
+    
+ // This program is free software; you can redistribute it and/or
+ // modify it under the terms of the GNU Library General Public License
+ // as published by the Free Software Foundation; either version 3, or
+ // (at your option) any later version.
+
+ // In addition to the permissions in the GNU Library General Public
+ // License, the Free Software Foundation gives you unlimited
+ // permission to link the compiled version of this file into
+ // combinations with other programs, and to distribute those
+ // combinations without any restriction coming from the use of this
+ // file.  (The Library Public License restrictions do apply in other
+ // respects; for example, they cover modification of the file, and
+ /// distribution when not linked into a combined executable.)
+
+ // 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
+ // Library General Public License for more details.
+
+ // You should have received a copy of the GNU Library 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 ELFCPP_RX_H
+ #define ELFCPP_RX_H
+
+ namespace elfcpp
+ {
+
+   // RX Relocations Codes
+   enum
+   {
+     R_RX_NONE =        0x00,
+     R_RX_DIR32 =       0x01,
+     R_RX_DIR24S =      0x02,
+     R_RX_DIR16 =       0x03,
+     R_RX_DIR16U =      0x04,
+     R_RX_DIR16S =      0x05,
+     R_RX_DIR8 =        0x06,
+     R_RX_DIR8U =       0x07,
+     R_RX_DIR8S =       0x08,
+     R_RX_DIR24S_PCREL = 0x9,
+     R_RX_DIR16S_PCREL = 0xa,
+     R_RX_DIR8S_PCREL = 0x0b,
+     R_RX_DIR16UL =     0x0c,
+     R_RX_DIR16UW =     0x0d,
+     R_RX_DIR8UL =      0x0e,
+     R_RX_DIR8UW =      0x0f,
+     R_RX_DIR32_REV =   0x10,
+     R_RX_DIR16_REV =   0x11,
+     R_RX_DIR3U_PCREL = 0x12,
+
+     // These are extensions added by Red Hat.
+     R_RX_RH_3_PCREL =  0x20, // Like R_RX_DIR8S_PCREL but only 3-bits.
+     R_RX_RH_16_OP =    0x21, // Like R_RX_DIR16 but for opcodes - always big endian.
+     R_RX_RH_24_OP =    0x22, // Like R_RX_DIR24S but for opcodes - always big endian.
+     R_RX_RH_32_OP =    0x23, // Like R_RX_DIR32 but for opcodes - always big endian.
+     R_RX_RH_24_UNS =   0x24, // Like R_RX_DIR24S but for unsigned values.
+     R_RX_RH_8_NEG =    0x25, // Like R_RX_DIR8 but -x is stored.
+     R_RX_RH_16_NEG =   0x26, // Like R_RX_DIR16 but -x is stored.
+     R_RX_RH_24_NEG =   0x27, // Like R_RX_DIR24S but -x is stored.
+     R_RX_RH_32_NEG =   0x28, // Like R_RX_DIR32 but -x is stored.
+     R_RX_RH_DIFF =     0x29, // Subtract from a previous relocation.
+     R_RX_RH_GPRELB =   0x2a, // Byte value, relative to __gp.
+     R_RX_RH_GPRELW =   0x2b, // Word value, relative to __gp.
+     R_RX_RH_GPRELL =   0x2c, // Long value, relative to __gp.
+     R_RX_RH_RELAX =    0x2d, // Marks opcodes suitable for linker relaxation.
+
+     // These are for complex relocs.
+     R_RX_ABS32 =       0x41,
+     R_RX_ABS24S =      0x42,
+     R_RX_ABS16 =       0x43,
+     R_RX_ABS16U =      0x44,
+     R_RX_ABS16S =      0x45,
+     R_RX_ABS8 =        0x46,
+     R_RX_ABS8U =       0x47,
+     R_RX_ABS8S =       0x48,
+     R_RX_ABS24S_PCREL = 0x49,
+     R_RX_ABS16S_PCREL = 0x4a,
+     R_RX_ABS8S_PCREL = 0x4b,
+     R_RX_ABS16UL =     0x4c,
+     R_RX_ABS16UW =     0x4d,
+     R_RX_ABS8UL =      0x4e,
+     R_RX_ABS8UW =      0x4f,
+     R_RX_ABS32_REV =   0x50,
+     R_RX_ABS16_REV =   0x51,
+  
+     R_RX_SYM =         0x80,
+     R_RX_OPneg =       0x81,
+     R_RX_OPadd =       0x82,
+     R_RX_OPsub =       0x83,
+     R_RX_OPmul =       0x84,
+     R_RX_OPdiv =       0x85,
+     R_RX_OPshla =      0x86,
+     R_RX_OPshra =      0x87,
+     R_RX_OPsctsize =   0x88,
+     R_RX_OPscttop =    0x8d,
+     R_RX_OPand =       0x90,
+     R_RX_OPor =        0x91,
+     R_RX_OPxor =       0x92,
+     R_RX_OPnot =       0x93,
+     R_RX_OPmod =       0x94,
+     R_RX_OPromtop =    0x95,
+     R_RX_OPramtop =    0x96,
+   };
+
+   // e_flags values defined for RX
+   enum
+   {
+     E_FLAG_RX_64BIT_DOUBLES = (1 << 0),
+     E_FLAG_RX_DSP    = (1 << 1),
+   };
+
+   // These define the addend field of R_RX_RH_RELAX relocations.
+   enum
+   {
+     RX_RELAXA_IMM6 = 0x00000010, // Imm8/16/24/32 at bit offset 6.
+     RX_RELAXA_IMM12 =   0x00000020, // Imm8/16/24/32 at bit offset 12.
+     RX_RELAXA_DSP4 = 0x00000040, // Dsp0/8/16 at bit offset 4.
+     RX_RELAXA_DSP6 = 0x00000080, // Dsp0/8/16 at bit offset 6.
+     RX_RELAXA_DSP14 = 0x00000100, // Dsp0/8/16 at bit offset 14.
+     RX_RELAXA_BRA = 0x00000200, // Any type of branch (must be decoded).
+     RX_RELAXA_RNUM = 0x0000000f, // Number of associated relocations.
+     RX_RELAXA_ALIGN =   0x10000000, // Start alignment; the remaining bits are the alignment value.
+     RX_RELAXA_ELIGN =   0x20000000, // End alignment; the remaining bits are the alignment value.
+     RX_RELAXA_ANUM = 0x00ffffff, // Alignment amount, in bytes (i.e. .balign).
+   };
+  
+ } // End namespace elfcpp.
+
+ #endif // !defined(ELFCPP_RX_H)
Reply | Threaded
Open this post in threaded view
|

Re: GOLD: RFA: Add support for RX target

Ian Lance Taylor
Nick Clifton <[hidden email]> writes:

> ./ChangeLog
> 2010-12-13  Nick Clifton  <[hidden email]>
>
> * configure.ac: Add RX to list of targets for which
> --enable-gold is valid.
>         * configure: Regenerate.
>
> elfcpp/ChangeLog
> 2010-12-13  Nick Clifton  <[hidden email]>
>
> * rx.h: New file.  Contains ELF definitions specific to the
> Renesas RX architecture.
>         * elfcpp.h (enum EM): Add EM_RX.
>
> gold/ChangeLog
> 2010-12-13  Nick Clifton  <[hidden email]>
>
> * rx.cc: New file.  Adds support for Renesas RX architecture.
>         * Makefile.am (TARGETSOURCES): Add rx.cc.
>         (ALL_TARGETOBJS): Add rx.$(OBJEXT)
>         * Makefile.in: Regenerate.
>         * configure.ac: Add RX as a default target.
>         * configure: Regenerate.
>         * configure.tgt: Add rx-*-* as a supported target.


> + #include <cstdio>
> + #include <cstring>
> + #include <limits>
> + #include <cstdio>
> + #include <string>
> + #include <algorithm>
> + #include <map>
> + #include <utility>
> + #include <set>

You only have to #include <cstdio> once.


> + inline bool
> + Target_rx::Relocate::relocate(
> +     const Relocate_info<32, false>*  relinfo,
> +     Target_rx*                       target,
> +     Output_section *                 /* output_section */,
> +     size_t                           relnum,
> +     const elfcpp::Rela<32, false>&   rela,
> +     unsigned int                     r_type,
> +     const Sized_symbol<32>*          /* gsym */,
> +     const Symbol_value<32>*          psymval,
> +     unsigned char*                   view,
> +     RX_address                       address,
> +     section_size_type                /* view_size */)
> + {
> +   typedef RX_relocation_functions Reloc;
> +   elfcpp::Elf_Xword addend = rela.get_r_addend();
> +
> +   if (target->uses_bigendian_data ())

s/ ()/()/


> + void
> + Target_rx::relocate_section(
> +     const Relocate_info<32, false>*  relinfo,
> +     unsigned int                     sh_type,
> +     const unsigned char*             prelocs,
> +     size_t                           reloc_count,
> +     Output_section*                  output_section,
> +     bool                             needs_special_offset_handling,
> +     unsigned char*                   view,
> +     RX_address                       address,
> +     section_size_type                view_size,
> +     const Reloc_symbol_changes*      reloc_symbol_changes)
> + {
> +   typedef Target_rx::Relocate Rx_relocate;
> +
> +   gold_assert(sh_type == elfcpp::SHT_RELA);
> +
> +   // See if we are relocating a relaxed input section.  If so, the view
> +   // covers the whole output section and we need to adjust accordingly.
> +   if (needs_special_offset_handling)
> +     {
> +       const Output_relaxed_input_section* poris =
> + output_section->find_relaxed_input_section(relinfo->object,
> +   relinfo->data_shndx);
> +       if (poris != NULL)
> + {
> +  RX_address section_address = poris->address();
> +  section_size_type section_size = poris->data_size();
> +
> +  gold_assert((section_address >= address)
> +      && ((section_address + section_size)
> +  <= (address + view_size)));
> +
> +  off_t offset = section_address - address;
> +  view += offset;
> +  address += offset;
> +  view_size = section_size;
> + }
> +     }
> +
> +   if (uses_bigendian_data ())

This line should be
  if (this->uses_bigendian_data())

> +     {
> +       // This is a copy of the relocate_section() function in target-reloc.h,
> +       // except with the additional calls to convert_host to fix up the
> +       // extracted information.
> +       // FIXME: There ought to be a better way to do this.

Yes, there ought to be a better way to do this.  If your code is
correct, then it looks like the problem is that you have a little-endian
object but the reloc fields are written with big-endian data.  The
comment at the top of the file suggests that the symbol table is also
written with big-endian data, in which case I think this code is
insufficient.

Anyhow, if the reloc fields are consistenly written big-endian, then the
right approach is not to call convert_host, but instead to change

> +       typedef Reloc_types<elfcpp::SHT_RELA, 32, false>::Reloc Reltype;

to

> +       typedef Reloc_types<elfcpp::SHT_RELA, 32, true>::Reloc Reltype;

That will cause the reloc code to fetch values big-endian rather than
little-endian.

Now, if you need to have a little-endian Object with a big-endian
Reltype, then I think the right approach is to split relocate_section in
target-reloc.h so that it calls another template which takes, as a
parameter, the reloc type.  The normal case would instantiate this
template with Reloc_types<sh_type, size, big_endian>::Reloc.  The RX
case would call the new template with Reloc_types<sh_type, size,
true>::Reloc.

However, I'm not sure this is the right approach, because I'm not sure
it will handle the symbol table correctly.  It seems to me that you are
going to need use a big-endian Object rather than a little-endian
Object.  And if you do that, you might as well templatize the whole
Target, as Target_arm does.  Then instead of worrying about
relocate_section, you would handle the required conversions entirely in
the Relocate class.


> + // Process relocations for gc.
> +
> + void
> + Target_rx::gc_process_relocs(Symbol_table*             /*symtab*/,
> +     Layout*                   /*layout*/,
> +     Sized_relobj<32, false>*  /*object*/,
> +     unsigned int              /*data_shndx*/,
> +     unsigned int              ,
> +     const unsigned char*      /*prelocs*/,
> +     size_t                    /*reloc_count*/,
> +     Output_section*           /*output_section*/,
> +     bool                      /*needs_special_offset_handling*/,
> +     size_t                    /*local_symbol_count*/,
> +     const unsigned char*      /*plocal_symbols*/)
> + {
> + #if 0
> +   typedef Target_rx RX;
> +   typedef Target_rx::Scan Scan;
> +
> +   gold::gc_process_relocs<32, false, RX, elfcpp::SHT_RELA, Scan>
> +     (symtab, layout, this, object, data_shndx, prelocs,
> +      reloc_count, output_section, needs_special_offset_handling,
> +      local_symbol_count, plocal_symbols);
> + #endif
> + }

Should probably give an error here for now.

> + static const char *
> + flag_meaning(elfcpp::Elf_Word flags, elfcpp::Elf_Word other_flags)

I would prefer that this be a static function in Target_rx rather than a
file static function.  It amounts to the same thing in the end.

> + {
> +   switch (flags)
> +     {
> +     case elfcpp::E_FLAG_RX_64BIT_DOUBLES:
> +       return "uses 64-bit doubles";
> +     case elfcpp::E_FLAG_RX_DSP:
> +       return "uses DSP instructions";
> +     case elfcpp::E_FLAG_RX_64BIT_DOUBLES | elfcpp::E_FLAG_RX_DSP:
> +       switch (other_flags)
> + {
> + case 0:
> +  return "uses 64-bit doubles & DSP instructions";
> + case elfcpp::E_FLAG_RX_64BIT_DOUBLES:
> +  return "uses DSP instructions";
> + case elfcpp::E_FLAG_RX_DSP:
> +  return "uses 64-bit doubles";
> + default:
> +  gold_unreachable();

If I understand this correctly, this should not be gold_unreachable,
because the object file could contain any random data.  It should print
an error about unrecognized flags, or something like that, rather than
crash the linker.

> + }
> +     case 0:
> +       switch (other_flags)
> + {
> + case elfcpp::E_FLAG_RX_64BIT_DOUBLES | elfcpp::E_FLAG_RX_DSP:
> + case elfcpp::E_FLAG_RX_64BIT_DOUBLES:
> +  return "uses 32-bit doubles";
> + case elfcpp::E_FLAG_RX_DSP:
> +  return "synthesies DSP instructions";
> + default:
> +  gold_unreachable();
> + }
> +     default:
> +       gold_unreachable();

Same for these two calls to gold_unreachable.

> + bool
> + Target_rx::check_type_and_flags (int type, elfcpp::Elf_Word flags, const char * name)

s/ (/(/
s/char */char*/

Also the line might be too long.

> + {
> +   static const char * saved_name = NULL;

s/char */char*/

However, don't use a static variable here.  It should be a member of
Target_rx instead.

> +   if (are_processor_specific_flags_set())

Write as
    if (this->are_processor_specific_flags_set())

> +     {
> +       static elfcpp::Elf_Word previous_flags = -1;

Don't use a static variable here.  It should be a member of Target_rx
instead.

> +       elfcpp::Elf_Word set_flags = processor_specific_flags();

Use "this->".

> +       if (set_flags != flags
> +  && previous_flags != flags)
> + {
> +  // Make sure that we do not complain about this particular
> +  // discrepancy more than once in a row.
> +  previous_flags = flags;
> +
> +  gold_error(_("%s: %s whereas %s does not"),
> +     name, flag_meaning(flags, set_flags), saved_name);

This looks kind of hard to internationalize correctly.

> +   else if (flags)
> +     {
> +       set_processor_specific_flags(flags);

Use "this->".

> + // Use do_make_elf_object to override the same function in the base class.
> + // We need to checks the ELF header flags before allowing the object to be
> + // made.
> + Object*
> + Target_rx::do_make_elf_object(const std::string&              name,
> +      Input_file*                     input_file,
> +      off_t                           offset,
> +      const elfcpp::Ehdr<32, false>&  ehdr)
> + {
> +   if (! check_type_and_flags (ehdr.get_e_type(),
> +      ehdr.get_e_flags(),
> +      name.c_str ()))
> +     return NULL;

s/! check_type_and_flags/!this->check_type_and_flags/

> +
> +   Sized_relobj<32, false>* obj =
> +     new Sized_relobj<32, false>(name, input_file, offset, ehdr);
> +   obj->setup();
> +   return obj;
> + }
> +
> + Object*
> + Target_rx::do_make_elf_object(const std::string&             name,
> +      Input_file*                    input_file,
> +      off_t                          offset,
> +      const elfcpp::Ehdr<32, true>&  ehdr)
> + {
> +   if (! check_type_and_flags (ehdr.get_e_type(),
> +      ehdr.get_e_flags(),
> +      name.c_str ()))
> +     return NULL;

s/! check_type_and_flags/!this->check_type_and_flags/

> +
> +   Sized_relobj<32, true>* obj =
> +     new Sized_relobj<32, true>(name, input_file, offset, ehdr);
> +   obj->setup();
> +   return obj;
> + }

Hmmm, I see, so you do have a big-endian Sized_relobj.  But
Target_rx::relocate_section takes a little-endian Relocate_info.  I
guess I don't see how you are avoiding a type error when
Sized_relobj<size, big_endian>::do_relocate_sections calls
target->relocate_section.

Ian
Reply | Threaded
Open this post in threaded view
|

Re: GOLD: RFA: Add support for RX target

Ian Lance Taylor
DJ Delorie <[hidden email]> writes:

>> > +   if (target->uses_bigendian_data ())
>>
>> s/ ()/()/
>
> Why doesn't gold follow the GNU coding standards?

Because it follows C++ convention.  All C++ code does not have a space
between the function name and the left parenthesis.


>> > +   if (uses_bigendian_data ())
>>
>> This line should be
>>   if (this->uses_bigendian_data())
>
> Why?  This throws away the huge benefit of having the implied "this".

I don't personally like the implied this->.  I don't think it is a
benefit at all.  I think it is a recipe for confusion.  It is especially
a recipe for confusion in heavily templated code like gold, as name
lookup in templates does not behave as most programmers expect.  This
particular code is not templated at the moment, but it could be later.

In any case, this is the convention used throughout the gold code, and
there is no reason for the rx code to be different.


>> Yes, there ought to be a better way to do this.  If your code is
>> correct, then it looks like the problem is that you have a little-endian
>> object but the reloc fields are written with big-endian data.
>
> The RX chip has selectable endianness for data, but always uses the
> same endianness for opcode fields.  Unfortunately, the opcode LINE
> fetch *does* go through the data endianness swapper, so you have to
> compensate for that when generating the final ELF image.  I.e. opcode
> *fields* are not swapped, but the opcode *section* *is*.
>
> As an aside, the external bus unit allows you to *further* specify
> endianness (as same vs swapped) on a per-chip-select basis, for
> external peripherals.  So executing from external RAM may involve up
> to three swaps (linker, bus, fetch) before an opcode is executed.

That sounds quite confusing, but I'm sure we can make it work.  We
should not have to do any code copying here.  Also, calls to
convert_host are most likely incorrect--note that no code in gold calls
it.  In general the right thing should happen by using the right value
for the big_endian template parameter.

Ian
Reply | Threaded
Open this post in threaded view
|

Re: GOLD: RFA: Add support for RX target

Nick Clifton
In reply to this post by Ian Lance Taylor
Hi Ian,

   Thanks for the patch review.  Attached is a revised version which
addresses all of your comments except one:


>> +       // This is a copy of the relocate_section() function in target-reloc.h,
>> +       // except with the additional calls to convert_host to fix up the
>> +       // extracted information.
>> +       // FIXME: There ought to be a better way to do this.
>
> Yes, there ought to be a better way to do this.  If your code is
> correct, then it looks like the problem is that you have a little-endian
> object but the reloc fields are written with big-endian data.  The
> comment at the top of the file suggests that the symbol table is also
> written with big-endian data, in which case I think this code is
> insufficient.
>
> Anyhow, if the reloc fields are consistenly written big-endian, then the
> right approach is not to call convert_host, but instead to change
>
>> +       typedef Reloc_types<elfcpp::SHT_RELA, 32, false>::Reloc Reltype;
>
> to
>
>> +       typedef Reloc_types<elfcpp::SHT_RELA, 32, true>::Reloc Reltype;
>
> That will cause the reloc code to fetch values big-endian rather than
> little-endian.
I found it very hard to get the reloc code work correctly for the RX but
the current version does that.  I did think about splitting up
relocate_section in target-reloc.h but I did not want to interfere with
already working code just for the vagaries of this one target.  (Plus I
was not sure that I would not introduce new bugs this way.  That and the
fact that big-endian data/little-endian code is a rare case for the RX).

So, if it is OK with you I would like to leave the code as it currently
is.  It may be less efficient, but it does work.

Is this revised version OK ?

Cheers
   Nick

rx.gold.patch.2 (42K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: GOLD: RFA: Add support for RX target

Ian Lance Taylor-3
Nick Clifton <[hidden email]> writes:

>>> +       // This is a copy of the relocate_section() function in target-reloc.h,
>>> +       // except with the additional calls to convert_host to fix up the
>>> +       // extracted information.
>>> +       // FIXME: There ought to be a better way to do this.
>>
>> Yes, there ought to be a better way to do this.  If your code is
>> correct, then it looks like the problem is that you have a little-endian
>> object but the reloc fields are written with big-endian data.  The
>> comment at the top of the file suggests that the symbol table is also
>> written with big-endian data, in which case I think this code is
>> insufficient.
>>
>> Anyhow, if the reloc fields are consistenly written big-endian, then the
>> right approach is not to call convert_host, but instead to change
>>
>>> +       typedef Reloc_types<elfcpp::SHT_RELA, 32, false>::Reloc Reltype;
>>
>> to
>>
>>> +       typedef Reloc_types<elfcpp::SHT_RELA, 32, true>::Reloc Reltype;
>>
>> That will cause the reloc code to fetch values big-endian rather than
>> little-endian.
>
> I found it very hard to get the reloc code work correctly for the RX
> but the current version does that.  I did think about splitting up
> relocate_section in target-reloc.h but I did not want to interfere
> with already working code just for the vagaries of this one target.
> (Plus I was not sure that I would not introduce new bugs this way.
> That and the fact that big-endian data/little-endian code is a rare
> case for the RX).
>
> So, if it is OK with you I would like to leave the code as it
> currently is.  It may be less efficient, but it does work.

My real concern is not efficiency, it's the copying of the code in
target-reloc.h.  That code has been tweaked several times and will
undoubtedly be tweaked again.  If it is copied into rx.cc, then the copy
will not be tweaked.  That's a bad road to walk down and I really don't
want to start.  I would much rather have you change the code in
target-reloc.h a little bit than have a copy of that code in rx.cc.

Also all the calls to convert_host but one are for fields fetched from a
elfcpp::Rela, and as far as I can tell all fields fetched from the Rela
are passed to convert_host.  That tells me that the calls to
convert_host are wrong, and that correct code would use a different
endianness for a Rela, and would be templatized on the right class.  I
know that the endianness handling in gold can be difficult to penetrate,
but I really think it is worth understanding.  It's basically a
heirarchy of type-checked macros.


Looking at your code, I don't understand this line in scan_relocs:

+      shndx = elfcpp::Convert<16, true>::convert_host(shndx);

That is swapping a section index read from a local symbol.  If that
swapping is correct, then it seems to me that there must be a lot of
other code which will be reading the wrong local symbol index.  I don't
understand how that code could be working.

Ian