gdb/testsuite/
[binutils-gdb.git] / gold / object.cc
index 8751d550f1f2845fa8dfa001ffc8951aa94754bd..b034ee209acc311f13516cbaec15c1cc6a538b3f 100644 (file)
@@ -1371,6 +1371,17 @@ Sized_relobj<size, big_endian>::do_layout(Symbol_table* symtab,
        }
 
       Output_section* data_section = out_sections[data_shndx];
+      if (data_section == reinterpret_cast<Output_section*>(2))
+        {
+          // The layout for the data section was deferred, so we need
+          // to defer the relocation section, too.
+         const char* name = pnames + shdr.get_sh_name();
+          this->deferred_layout_relocs_.push_back(
+              Deferred_layout(i, name, pshdr, 0, elfcpp::SHT_NULL));
+         out_sections[i] = reinterpret_cast<Output_section*>(2);
+          out_section_offsets[i] = invalid_address;
+          continue;
+        }
       if (data_section == NULL)
        {
          out_sections[i] = NULL;
@@ -1461,11 +1472,46 @@ Sized_relobj<size, big_endian>::do_layout_deferred_sections(Layout* layout)
        ++deferred)
     {
       typename This::Shdr shdr(deferred->shdr_data_);
+      // If the section is not included, it is because the garbage collector
+      // decided it is not needed.  Avoid reverting that decision.
+      if (!this->is_section_included(deferred->shndx_))
+        continue;
+
       this->layout_section(layout, deferred->shndx_, deferred->name_.c_str(),
                            shdr, deferred->reloc_shndx_, deferred->reloc_type_);
     }
 
   this->deferred_layout_.clear();
+
+  // Now handle the deferred relocation sections.
+
+  Output_sections& out_sections(this->output_sections());
+  std::vector<Address>& out_section_offsets(this->section_offsets_);
+
+  for (deferred = this->deferred_layout_relocs_.begin();
+       deferred != this->deferred_layout_relocs_.end();
+       ++deferred)
+    {
+      unsigned int shndx = deferred->shndx_;
+      typename This::Shdr shdr(deferred->shdr_data_);
+      unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info());
+
+      Output_section* data_section = out_sections[data_shndx];
+      if (data_section == NULL)
+       {
+         out_sections[shndx] = NULL;
+          out_section_offsets[shndx] = invalid_address;
+         continue;
+       }
+
+      Relocatable_relocs* rr = new Relocatable_relocs();
+      this->set_relocatable_relocs(shndx, rr);
+
+      Output_section* os = layout->layout_reloc(this, shndx, shdr,
+                                               data_section, rr);
+      out_sections[shndx] = os;
+      out_section_offsets[shndx] = invalid_address;
+    }
 }
 
 // Add the symbols to the symbol table.
@@ -1822,7 +1868,12 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
                  const Output_section_data* posd =
                    os->find_relaxed_input_section(this, shndx);
                  if (posd != NULL)
-                   lv.set_output_value(posd->address());
+                   {
+                     Address relocatable_link_adjustment =
+                       relocatable ? os->address() : 0;
+                     lv.set_output_value(posd->address()
+                                         - relocatable_link_adjustment);
+                   }
                  else
                    lv.set_output_value(os->address());
                }
@@ -1830,9 +1881,14 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
                {
                  // We have to consider the addend to determine the
                  // value to use in a relocation.  START is the start
-                 // of this input section.
+                 // of this input section.  If we are doing a relocatable
+                 // link, use offset from start output section instead of
+                 // address.
+                 Address adjusted_start =
+                   relocatable ? start - os->address() : start;
                  Merged_symbol_value<size>* msv =
-                   new Merged_symbol_value<size>(lv.input_value(), start);
+                   new Merged_symbol_value<size>(lv.input_value(),
+                                                 adjusted_start);
                  lv.set_merged_symbol_value(msv);
                }
            }