Add support for .MIPS.options section.
authorVladimir Radosavljevic <Vladimir.Radosavljevic@imgtec.com>
Wed, 15 Mar 2017 22:47:58 +0000 (15:47 -0700)
committerCary Coutant <ccoutant@gmail.com>
Wed, 15 Mar 2017 23:51:35 +0000 (16:51 -0700)
gold/
        * mips.cc (class Mips_output_section_options): New class.
        (Target_mips::do_make_output_section): New method.

gold/ChangeLog
gold/mips.cc

index a36faa1d065dcaf1b471ee20ada6514eeae5545a..140114e207d5d6dd7043067eb99148237ec67205 100644 (file)
@@ -1,3 +1,8 @@
+2017-03-15  Vladimir Radosavljevic  <Vladimir.Radosavljevic@imgtec.com>
+
+        * mips.cc (class Mips_output_section_options): New class.
+        (Target_mips::do_make_output_section): New method.
+
 2017-03-15  Vladimir Radosavljevic  <Vladimir.Radosavljevic@imgtec.com>
 
         * mips.cc (Mips_relocate_functions::rel26): Don't print relocation
index c62ced3ef6b5b892981927095033393ee1e898f4..4ea2e1d9feb6bcaf64da5b4dbdaedb8236792467 100644 (file)
@@ -63,6 +63,9 @@ class Target_mips;
 template<int size, bool big_endian>
 class Mips_output_section_reginfo;
 
+template<int size, bool big_endian>
+class Mips_output_section_options;
+
 template<int size, bool big_endian>
 class Mips_output_data_la25_stub;
 
@@ -2821,6 +2824,31 @@ class Mips_output_section_reginfo : public Output_section_data
   Valtype cprmask4_;
 };
 
+// This class handles .MIPS.options output section.
+
+template<int size, bool big_endian>
+class Mips_output_section_options : public Output_section
+{
+ public:
+  Mips_output_section_options(const char* name, elfcpp::Elf_Word type,
+                              elfcpp::Elf_Xword flags,
+                              Target_mips<size, big_endian>* target)
+    : Output_section(name, type, flags), target_(target)
+  {
+    // After the input sections are written, we only need to update
+    // ri_gp_value field of ODK_REGINFO entries.
+    this->set_after_input_sections();
+  }
+
+ protected:
+  // Write out option section.
+  void
+  do_write(Output_file* of);
+
+ private:
+  Target_mips<size, big_endian>* target_;
+};
+
 // This class handles .MIPS.abiflags output section.
 
 template<int size, bool big_endian>
@@ -3635,6 +3663,18 @@ class Target_mips : public Sized_target<size, big_endian>
                      const elfcpp::Ehdr<size, !big_endian>&)
   { gold_unreachable(); }
 
+  // Make an output section.
+  Output_section*
+  do_make_output_section(const char* name, elfcpp::Elf_Word type,
+                         elfcpp::Elf_Xword flags)
+    {
+      if (type == elfcpp::SHT_MIPS_OPTIONS)
+        return new Mips_output_section_options<size, big_endian>(name, type,
+                                                                 flags, this);
+      else
+        return new Output_section(name, type, flags);
+    }
+
   // Adjust ELF file header.
   void
   do_adjust_elf_header(unsigned char* view, int len);
@@ -8177,6 +8217,44 @@ Mips_output_section_reginfo<size, big_endian>::do_write(Output_file* of)
   of->write_output_view(offset, data_size, view);
 }
 
+// Mips_output_section_options methods.
+
+template<int size, bool big_endian>
+void
+Mips_output_section_options<size, big_endian>::do_write(Output_file* of)
+{
+  off_t offset = this->offset();
+  const section_size_type oview_size =
+    convert_to_section_size_type(this->data_size());
+  unsigned char* view = of->get_output_view(offset, oview_size);
+  const unsigned char* end = view + oview_size;
+
+  while (view + 8 <= end)
+    {
+      unsigned char kind = elfcpp::Swap<8, big_endian>::readval(view);
+      unsigned char sz = elfcpp::Swap<8, big_endian>::readval(view + 1);
+      if (sz < 8)
+        {
+          gold_error(_("Warning: bad `%s' option size %u smaller "
+                       "than its header in output section"),
+                     this->name(), sz);
+          break;
+        }
+
+      // Only update ri_gp_value (GP register value) field of ODK_REGINFO entry.
+      if (this->target_->is_output_n64() && kind == elfcpp::ODK_REGINFO)
+        elfcpp::Swap<size, big_endian>::writeval(view + 32,
+                                                 this->target_->gp_value());
+      else if (kind == elfcpp::ODK_REGINFO)
+        elfcpp::Swap<size, big_endian>::writeval(view + 28,
+                                                 this->target_->gp_value());
+
+      view += sz;
+    }
+
+  of->write_output_view(offset, oview_size, view);
+}
+
 // Mips_output_section_abiflags methods.
 
 template<int size, bool big_endian>