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] mapping input to output sections


Powerpc64 needs to map input .toc and .got sections to the output .got
section, as the following accomplishes with GNU ld:
  .got		: ALIGN(8) { *(.got .toc) }
I gather gold is supposed to operate without a linker script.  Is is
reasonable to move section_name_mapping[], section_name_mapping_count,
output_section_name() and match_file_name() from layout.cc to
target.cc so output_section_name() can be overridden in class
Target_powerpc?  Or is there a better way to do this sort of trick?

Index: gold/layout.h
===================================================================
RCS file: /cvs/src/src/gold/layout.h,v
retrieving revision 1.103
diff -u -p -r1.103 layout.h
--- gold/layout.h	2 May 2012 21:37:23 -0000	1.103
+++ gold/layout.h	13 Aug 2012 14:15:07 -0000
@@ -717,12 +717,6 @@ class Layout
 	    || strncmp(name, ".stab", sizeof(".stab") - 1) == 0);
   }
 
-  // Return true if RELOBJ is an input file whose base name matches
-  // FILE_NAME.  The base name must have an extension of ".o", and
-  // must be exactly FILE_NAME.o or FILE_NAME, one character, ".o".
-  static bool
-  match_file_name(const Relobj* relobj, const char* file_name);
-
   // Return whether section SHNDX in RELOBJ is a .ctors/.dtors section
   // with more than one word being mapped to a .init_array/.fini_array
   // section.
@@ -924,17 +918,6 @@ class Layout
   Layout(const Layout&);
   Layout& operator=(const Layout&);
 
-  // Mapping from input section names to output section names.
-  struct Section_name_mapping
-  {
-    const char* from;
-    int fromlen;
-    const char* to;
-    int tolen;
-  };
-  static const Section_name_mapping section_name_mapping[];
-  static const int section_name_mapping_count;
-
   // During a relocatable link, a list of group sections and
   // signatures.
   struct Group_signature
@@ -1049,12 +1032,6 @@ class Layout
   include_section(Sized_relobj_file<size, big_endian>* object, const char* name,
 		  const elfcpp::Shdr<size, big_endian>&);
 
-  // Return the output section name to use given an input section
-  // name.  Set *PLEN to the length of the name.  *PLEN must be
-  // initialized to the length of NAME.
-  static const char*
-  output_section_name(const Relobj*, const char* name, size_t* plen);
-
   // Return the number of allocated output sections.
   size_t
   allocated_output_section_count() const;
Index: gold/layout.cc
===================================================================
RCS file: /cvs/src/src/gold/layout.cc,v
retrieving revision 1.232
diff -u -p -r1.232 layout.cc
--- gold/layout.cc	7 Aug 2012 13:24:47 -0000	1.232
+++ gold/layout.cc	13 Aug 2012 14:15:06 -0000
@@ -939,7 +939,10 @@ Layout::choose_output_section(const Relo
   if (is_input_section
       && !this->script_options_->saw_sections_clause()
       && !parameters->options().relocatable())
-    name = Layout::output_section_name(relobj, name, &len);
+    {
+      Target* target = const_cast<Target*>(&parameters->target());
+      name = target->output_section_name(relobj, name, &len);
+    }
 
   Stringpool::Key name_key;
   name = this->namepool_.add_with_length(name, len, true, &name_key);
@@ -4636,185 +4639,6 @@ Layout::set_dynamic_symbol_size(const Sy
     gold_unreachable();
 }
 
-// The mapping of input section name prefixes to output section names.
-// In some cases one prefix is itself a prefix of another prefix; in
-// such a case the longer prefix must come first.  These prefixes are
-// based on the GNU linker default ELF linker script.
-
-#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
-#define MAPPING_INIT_EXACT(f, t) { f, 0, t, sizeof(t) - 1 }
-const Layout::Section_name_mapping Layout::section_name_mapping[] =
-{
-  MAPPING_INIT(".text.", ".text"),
-  MAPPING_INIT(".rodata.", ".rodata"),
-  MAPPING_INIT(".data.rel.ro.local.", ".data.rel.ro.local"),
-  MAPPING_INIT_EXACT(".data.rel.ro.local", ".data.rel.ro.local"),
-  MAPPING_INIT(".data.rel.ro.", ".data.rel.ro"),
-  MAPPING_INIT_EXACT(".data.rel.ro", ".data.rel.ro"),
-  MAPPING_INIT(".data.", ".data"),
-  MAPPING_INIT(".bss.", ".bss"),
-  MAPPING_INIT(".tdata.", ".tdata"),
-  MAPPING_INIT(".tbss.", ".tbss"),
-  MAPPING_INIT(".init_array.", ".init_array"),
-  MAPPING_INIT(".fini_array.", ".fini_array"),
-  MAPPING_INIT(".sdata.", ".sdata"),
-  MAPPING_INIT(".sbss.", ".sbss"),
-  // FIXME: In the GNU linker, .sbss2 and .sdata2 are handled
-  // differently depending on whether it is creating a shared library.
-  MAPPING_INIT(".sdata2.", ".sdata"),
-  MAPPING_INIT(".sbss2.", ".sbss"),
-  MAPPING_INIT(".lrodata.", ".lrodata"),
-  MAPPING_INIT(".ldata.", ".ldata"),
-  MAPPING_INIT(".lbss.", ".lbss"),
-  MAPPING_INIT(".gcc_except_table.", ".gcc_except_table"),
-  MAPPING_INIT(".gnu.linkonce.d.rel.ro.local.", ".data.rel.ro.local"),
-  MAPPING_INIT(".gnu.linkonce.d.rel.ro.", ".data.rel.ro"),
-  MAPPING_INIT(".gnu.linkonce.t.", ".text"),
-  MAPPING_INIT(".gnu.linkonce.r.", ".rodata"),
-  MAPPING_INIT(".gnu.linkonce.d.", ".data"),
-  MAPPING_INIT(".gnu.linkonce.b.", ".bss"),
-  MAPPING_INIT(".gnu.linkonce.s.", ".sdata"),
-  MAPPING_INIT(".gnu.linkonce.sb.", ".sbss"),
-  MAPPING_INIT(".gnu.linkonce.s2.", ".sdata"),
-  MAPPING_INIT(".gnu.linkonce.sb2.", ".sbss"),
-  MAPPING_INIT(".gnu.linkonce.wi.", ".debug_info"),
-  MAPPING_INIT(".gnu.linkonce.td.", ".tdata"),
-  MAPPING_INIT(".gnu.linkonce.tb.", ".tbss"),
-  MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"),
-  MAPPING_INIT(".gnu.linkonce.l.", ".ldata"),
-  MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"),
-  MAPPING_INIT(".ARM.extab", ".ARM.extab"),
-  MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
-  MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
-  MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
-};
-#undef MAPPING_INIT
-#undef MAPPING_INIT_EXACT
-
-const int Layout::section_name_mapping_count =
-  (sizeof(Layout::section_name_mapping)
-   / sizeof(Layout::section_name_mapping[0]));
-
-// Choose the output section name to use given an input section name.
-// Set *PLEN to the length of the name.  *PLEN is initialized to the
-// length of NAME.
-
-const char*
-Layout::output_section_name(const Relobj* relobj, const char* name,
-			    size_t* plen)
-{
-  // gcc 4.3 generates the following sorts of section names when it
-  // needs a section name specific to a function:
-  //   .text.FN
-  //   .rodata.FN
-  //   .sdata2.FN
-  //   .data.FN
-  //   .data.rel.FN
-  //   .data.rel.local.FN
-  //   .data.rel.ro.FN
-  //   .data.rel.ro.local.FN
-  //   .sdata.FN
-  //   .bss.FN
-  //   .sbss.FN
-  //   .tdata.FN
-  //   .tbss.FN
-
-  // The GNU linker maps all of those to the part before the .FN,
-  // except that .data.rel.local.FN is mapped to .data, and
-  // .data.rel.ro.local.FN is mapped to .data.rel.ro.  The sections
-  // beginning with .data.rel.ro.local are grouped together.
-
-  // For an anonymous namespace, the string FN can contain a '.'.
-
-  // Also of interest: .rodata.strN.N, .rodata.cstN, both of which the
-  // GNU linker maps to .rodata.
-
-  // The .data.rel.ro sections are used with -z relro.  The sections
-  // are recognized by name.  We use the same names that the GNU
-  // linker does for these sections.
-
-  // It is hard to handle this in a principled way, so we don't even
-  // try.  We use a table of mappings.  If the input section name is
-  // not found in the table, we simply use it as the output section
-  // name.
-
-  const Section_name_mapping* psnm = section_name_mapping;
-  for (int i = 0; i < section_name_mapping_count; ++i, ++psnm)
-    {
-      if (psnm->fromlen > 0)
-	{
-	  if (strncmp(name, psnm->from, psnm->fromlen) == 0)
-	    {
-	      *plen = psnm->tolen;
-	      return psnm->to;
-	    }
-	}
-      else
-	{
-	  if (strcmp(name, psnm->from) == 0)
-	    {
-	      *plen = psnm->tolen;
-	      return psnm->to;
-	    }
-	}
-    }
-
-  // As an additional complication, .ctors sections are output in
-  // either .ctors or .init_array sections, and .dtors sections are
-  // output in either .dtors or .fini_array sections.
-  if (is_prefix_of(".ctors.", name) || is_prefix_of(".dtors.", name))
-    {
-      if (parameters->options().ctors_in_init_array())
-	{
-	  *plen = 11;
-	  return name[1] == 'c' ? ".init_array" : ".fini_array";
-	}
-      else
-	{
-	  *plen = 6;
-	  return name[1] == 'c' ? ".ctors" : ".dtors";
-	}
-    }
-  if (parameters->options().ctors_in_init_array()
-      && (strcmp(name, ".ctors") == 0 || strcmp(name, ".dtors") == 0))
-    {
-      // To make .init_array/.fini_array work with gcc we must exclude
-      // .ctors and .dtors sections from the crtbegin and crtend
-      // files.
-      if (relobj == NULL
-	  || (!Layout::match_file_name(relobj, "crtbegin")
-	      && !Layout::match_file_name(relobj, "crtend")))
-	{
-	  *plen = 11;
-	  return name[1] == 'c' ? ".init_array" : ".fini_array";
-	}
-    }
-
-  return name;
-}
-
-// Return true if RELOBJ is an input file whose base name matches
-// FILE_NAME.  The base name must have an extension of ".o", and must
-// be exactly FILE_NAME.o or FILE_NAME, one character, ".o".  This is
-// to match crtbegin.o as well as crtbeginS.o without getting confused
-// by other possibilities.  Overall matching the file name this way is
-// a dreadful hack, but the GNU linker does it in order to better
-// support gcc, and we need to be compatible.
-
-bool
-Layout::match_file_name(const Relobj* relobj, const char* match)
-{
-  const std::string& file_name(relobj->name());
-  const char* base_name = lbasename(file_name.c_str());
-  size_t match_len = strlen(match);
-  if (strncmp(base_name, match, match_len) != 0)
-    return false;
-  size_t base_len = strlen(base_name);
-  if (base_len != match_len + 2 && base_len != match_len + 3)
-    return false;
-  return memcmp(base_name + base_len - 2, ".o", 2) == 0;
-}
-
 // Check if a comdat group or .gnu.linkonce section with the given
 // NAME is selected for the link.  If there is already a section,
 // *KEPT_SECTION is set to point to the existing section and the
Index: gold/target.h
===================================================================
RCS file: /cvs/src/src/gold/target.h,v
retrieving revision 1.66
diff -u -p -r1.66 target.h
--- gold/target.h	2 May 2012 21:37:23 -0000	1.66
+++ gold/target.h	13 Aug 2012 14:15:07 -0000
@@ -412,6 +412,19 @@ class Target
   define_standard_symbols(Symbol_table* symtab, Layout* layout)
   { this->do_define_standard_symbols(symtab, layout); }
 
+  // Return the output section name to use given an input section
+  // name.  Set *PLEN to the length of the name.  *PLEN must be
+  // initialized to the length of NAME.
+  const char*
+  output_section_name(const Relobj* relobj, const char* name, size_t* plen)
+  { return this->do_output_section_name(relobj, name, plen); }
+
+  // Return true if RELOBJ is an input file whose base name matches
+  // FILE_NAME.  The base name must have an extension of ".o", and
+  // must be exactly FILE_NAME.o or FILE_NAME, one character, ".o".
+  static bool
+  match_file_name(const Relobj* relobj, const char* file_name);
+
  protected:
   // This struct holds the constant information for a child class.  We
   // use a struct to avoid the overhead of virtual function calls for
@@ -655,6 +668,10 @@ class Target
   do_define_standard_symbols(Symbol_table*, Layout*)
   { }
 
+  // This may be overridden by the child class.
+  virtual const char*
+  do_output_section_name(const Relobj* relobj, const char* name, size_t* plen);
+
  private:
   // The implementations of the four do_make_elf_object virtual functions are
   // almost identical except for their sizes and endianness.  We use a template.
@@ -667,6 +684,17 @@ class Target
   Target(const Target&);
   Target& operator=(const Target&);
 
+  // Mapping from input section names to output section names.
+  struct Section_name_mapping
+  {
+    const char* from;
+    int fromlen;
+    const char* to;
+    int tolen;
+  };
+  static const Section_name_mapping section_name_mapping[];
+  static const int section_name_mapping_count;
+
   // The target information.
   const Target_info* pti_;
   // Processor-specific flags.
Index: gold/target.cc
===================================================================
RCS file: /cvs/src/src/gold/target.cc,v
retrieving revision 1.13
diff -u -p -r1.13 target.cc
--- gold/target.cc	20 Apr 2012 22:23:47 -0000	1.13
+++ gold/target.cc	13 Aug 2012 14:15:07 -0000
@@ -26,6 +26,7 @@
 #include "symtab.h"
 #include "output.h"
 #include "target.h"
+#include "libiberty.h"
 
 namespace gold
 {
@@ -59,6 +60,185 @@ Target::do_is_local_label_name(const cha
   return false;
 }
 
+// The mapping of input section name prefixes to output section names.
+// In some cases one prefix is itself a prefix of another prefix; in
+// such a case the longer prefix must come first.  These prefixes are
+// based on the GNU linker default ELF linker script.
+
+#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 }
+#define MAPPING_INIT_EXACT(f, t) { f, 0, t, sizeof(t) - 1 }
+const Target::Section_name_mapping Target::section_name_mapping[] =
+{
+  MAPPING_INIT(".text.", ".text"),
+  MAPPING_INIT(".rodata.", ".rodata"),
+  MAPPING_INIT(".data.rel.ro.local.", ".data.rel.ro.local"),
+  MAPPING_INIT_EXACT(".data.rel.ro.local", ".data.rel.ro.local"),
+  MAPPING_INIT(".data.rel.ro.", ".data.rel.ro"),
+  MAPPING_INIT_EXACT(".data.rel.ro", ".data.rel.ro"),
+  MAPPING_INIT(".data.", ".data"),
+  MAPPING_INIT(".bss.", ".bss"),
+  MAPPING_INIT(".tdata.", ".tdata"),
+  MAPPING_INIT(".tbss.", ".tbss"),
+  MAPPING_INIT(".init_array.", ".init_array"),
+  MAPPING_INIT(".fini_array.", ".fini_array"),
+  MAPPING_INIT(".sdata.", ".sdata"),
+  MAPPING_INIT(".sbss.", ".sbss"),
+  // FIXME: In the GNU linker, .sbss2 and .sdata2 are handled
+  // differently depending on whether it is creating a shared library.
+  MAPPING_INIT(".sdata2.", ".sdata"),
+  MAPPING_INIT(".sbss2.", ".sbss"),
+  MAPPING_INIT(".lrodata.", ".lrodata"),
+  MAPPING_INIT(".ldata.", ".ldata"),
+  MAPPING_INIT(".lbss.", ".lbss"),
+  MAPPING_INIT(".gcc_except_table.", ".gcc_except_table"),
+  MAPPING_INIT(".gnu.linkonce.d.rel.ro.local.", ".data.rel.ro.local"),
+  MAPPING_INIT(".gnu.linkonce.d.rel.ro.", ".data.rel.ro"),
+  MAPPING_INIT(".gnu.linkonce.t.", ".text"),
+  MAPPING_INIT(".gnu.linkonce.r.", ".rodata"),
+  MAPPING_INIT(".gnu.linkonce.d.", ".data"),
+  MAPPING_INIT(".gnu.linkonce.b.", ".bss"),
+  MAPPING_INIT(".gnu.linkonce.s.", ".sdata"),
+  MAPPING_INIT(".gnu.linkonce.sb.", ".sbss"),
+  MAPPING_INIT(".gnu.linkonce.s2.", ".sdata"),
+  MAPPING_INIT(".gnu.linkonce.sb2.", ".sbss"),
+  MAPPING_INIT(".gnu.linkonce.wi.", ".debug_info"),
+  MAPPING_INIT(".gnu.linkonce.td.", ".tdata"),
+  MAPPING_INIT(".gnu.linkonce.tb.", ".tbss"),
+  MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"),
+  MAPPING_INIT(".gnu.linkonce.l.", ".ldata"),
+  MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"),
+  MAPPING_INIT(".ARM.extab", ".ARM.extab"),
+  MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"),
+  MAPPING_INIT(".ARM.exidx", ".ARM.exidx"),
+  MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"),
+};
+#undef MAPPING_INIT
+#undef MAPPING_INIT_EXACT
+
+const int Target::section_name_mapping_count =
+  (sizeof(Target::section_name_mapping)
+   / sizeof(Target::section_name_mapping[0]));
+
+// Choose the output section name to use given an input section name.
+// Set *PLEN to the length of the name.  *PLEN is initialized to the
+// length of NAME.
+
+const char*
+Target::do_output_section_name(const Relobj* relobj, const char* name,
+			       size_t* plen)
+{
+  // gcc 4.3 generates the following sorts of section names when it
+  // needs a section name specific to a function:
+  //   .text.FN
+  //   .rodata.FN
+  //   .sdata2.FN
+  //   .data.FN
+  //   .data.rel.FN
+  //   .data.rel.local.FN
+  //   .data.rel.ro.FN
+  //   .data.rel.ro.local.FN
+  //   .sdata.FN
+  //   .bss.FN
+  //   .sbss.FN
+  //   .tdata.FN
+  //   .tbss.FN
+
+  // The GNU linker maps all of those to the part before the .FN,
+  // except that .data.rel.local.FN is mapped to .data, and
+  // .data.rel.ro.local.FN is mapped to .data.rel.ro.  The sections
+  // beginning with .data.rel.ro.local are grouped together.
+
+  // For an anonymous namespace, the string FN can contain a '.'.
+
+  // Also of interest: .rodata.strN.N, .rodata.cstN, both of which the
+  // GNU linker maps to .rodata.
+
+  // The .data.rel.ro sections are used with -z relro.  The sections
+  // are recognized by name.  We use the same names that the GNU
+  // linker does for these sections.
+
+  // It is hard to handle this in a principled way, so we don't even
+  // try.  We use a table of mappings.  If the input section name is
+  // not found in the table, we simply use it as the output section
+  // name.
+
+  const Section_name_mapping* psnm = section_name_mapping;
+  for (int i = 0; i < section_name_mapping_count; ++i, ++psnm)
+    {
+      if (psnm->fromlen > 0)
+	{
+	  if (strncmp(name, psnm->from, psnm->fromlen) == 0)
+	    {
+	      *plen = psnm->tolen;
+	      return psnm->to;
+	    }
+	}
+      else
+	{
+	  if (strcmp(name, psnm->from) == 0)
+	    {
+	      *plen = psnm->tolen;
+	      return psnm->to;
+	    }
+	}
+    }
+
+  // As an additional complication, .ctors sections are output in
+  // either .ctors or .init_array sections, and .dtors sections are
+  // output in either .dtors or .fini_array sections.
+  if (is_prefix_of(".ctors.", name) || is_prefix_of(".dtors.", name))
+    {
+      if (parameters->options().ctors_in_init_array())
+	{
+	  *plen = 11;
+	  return name[1] == 'c' ? ".init_array" : ".fini_array";
+	}
+      else
+	{
+	  *plen = 6;
+	  return name[1] == 'c' ? ".ctors" : ".dtors";
+	}
+    }
+  if (parameters->options().ctors_in_init_array()
+      && (strcmp(name, ".ctors") == 0 || strcmp(name, ".dtors") == 0))
+    {
+      // To make .init_array/.fini_array work with gcc we must exclude
+      // .ctors and .dtors sections from the crtbegin and crtend
+      // files.
+      if (relobj == NULL
+	  || (!Target::match_file_name(relobj, "crtbegin")
+	      && !Target::match_file_name(relobj, "crtend")))
+	{
+	  *plen = 11;
+	  return name[1] == 'c' ? ".init_array" : ".fini_array";
+	}
+    }
+
+  return name;
+}
+
+// Return true if RELOBJ is an input file whose base name matches
+// FILE_NAME.  The base name must have an extension of ".o", and must
+// be exactly FILE_NAME.o or FILE_NAME, one character, ".o".  This is
+// to match crtbegin.o as well as crtbeginS.o without getting confused
+// by other possibilities.  Overall matching the file name this way is
+// a dreadful hack, but the GNU linker does it in order to better
+// support gcc, and we need to be compatible.
+
+bool
+Target::match_file_name(const Relobj* relobj, const char* match)
+{
+  const std::string& file_name(relobj->name());
+  const char* base_name = lbasename(file_name.c_str());
+  size_t match_len = strlen(match);
+  if (strncmp(base_name, match, match_len) != 0)
+    return false;
+  size_t base_len = strlen(base_name);
+  if (base_len != match_len + 2 && base_len != match_len + 3)
+    return false;
+  return memcmp(base_name + base_len - 2, ".o", 2) == 0;
+}
+
 // Implementations of methods Target::do_make_elf_object are almost identical
 // except for the address sizes and endianities.  So we extract this
 // into a template.
Index: gold/output.cc
===================================================================
RCS file: /cvs/src/src/gold/output.cc,v
retrieving revision 1.168
diff -u -p -r1.168 output.cc
--- gold/output.cc	11 Aug 2012 04:41:28 -0000	1.168
+++ gold/output.cc	13 Aug 2012 14:15:07 -0000
@@ -3271,7 +3271,7 @@ class Output_section::Input_section_sort
   // in order to better support gcc, and we need to be compatible.
   bool
   match_file_name(const char* file_name) const
-  { return Layout::match_file_name(this->input_section_.relobj(), file_name); }
+  { return Target::match_file_name(this->input_section_.relobj(), file_name); }
 
   // Returns 1 if THIS should appear before S in section order, -1 if S
   // appears before THIS and 0 if they are not comparable.
Index: gold/powerpc.cc
===================================================================
RCS file: /cvs/src/src/gold/powerpc.cc,v
retrieving revision 1.46
diff -u -p -r1.46 powerpc.cc
--- gold/powerpc.cc	12 Aug 2012 03:07:32 -0000	1.46
+++ gold/powerpc.cc	13 Aug 2012 14:15:07 -0000
@@ -134,6 +125,17 @@ class Target_powerpc : public Sized_targ
 	      bool needs_special_offset_handling,
 	      size_t local_symbol_count,
 	      const unsigned char* plocal_symbols);
+
+  // Map input .toc section to output .got section.
+  const char*
+  do_output_section_name(const Relobj* relobj, const char* name, size_t* plen)
+  {
+    name = Target::do_output_section_name(relobj, name, plen);
+    if (size == 64 && strcmp (name, ".toc") == 0)
+      name = ".got";
+    return name;
+  }
+
   // Finalize the sections.
   void
   do_finalize_sections(Layout*, const Input_objects*, Symbol_table*);

-- 
Alan Modra
Australia Development Lab, IBM


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