This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GOLD: RFA: Add support for RX target


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  <nickc@redhat.com>

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

elfcpp/ChangeLog
2010-12-13  Nick Clifton  <nickc@redhat.com>

	* 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  <nickc@redhat.com>

	* 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 <nickc@redhat.com>.
+ // Based on code in the gold sources written by Ian Lance Taylor
+ // <iant@google.com> and Doug Kwan <dougkwan@google.com>.
+ // 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 <nickc@redhat.com>
+ 
+ // 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)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]