// reloc.cc -- relocate input files for gold.
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright (C) 2006-2016 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
off_t sh_size = shdr.get_sh_size();
+ if (sh_size == 0)
+ continue;
+
unsigned int reloc_size;
if (sh_type == elfcpp::SHT_REL)
reloc_size = elfcpp::Elf_sizes<size>::rel_size;
// section data to the output file. The second one applies
// relocations.
- this->write_sections(pshdrs, of, &views);
+ this->write_sections(layout, pshdrs, of, &views);
// To speed up relocations, we set up hash tables for fast lookup of
// input offsets to output addresses.
this->initialize_input_to_output_maps();
+ // Make the views available through get_output_view() for the duration
+ // of this routine. This RAII class will reset output_views_ to NULL
+ // when the views go out of scope.
+ struct Set_output_views
+ {
+ Set_output_views(const Views** ppviews, const Views* pviews)
+ {
+ ppviews_ = ppviews;
+ *ppviews = pviews;
+ }
+
+ ~Set_output_views()
+ { *ppviews_ = NULL; }
+
+ const Views** ppviews_;
+ };
+ Set_output_views set_output_views(&this->output_views_, &views);
+
// Apply relocations.
this->relocate_sections(symtab, layout, pshdrs, of, &views);
{
if (views[i].view != NULL)
{
+ if (views[i].is_ctors_reverse_view)
+ this->reverse_words(views[i].view, views[i].view_size);
if (!views[i].is_postprocessing_view)
{
if (views[i].is_input_output_view)
template<int size, bool big_endian>
void
-Sized_relobj_file<size, big_endian>::write_sections(const unsigned char* pshdrs,
+Sized_relobj_file<size, big_endian>::write_sections(const Layout* layout,
+ const unsigned char* pshdrs,
Output_file* of,
Views* pviews)
{
pvs->address = posd->address();
pvs->is_input_output_view = false;
pvs->is_postprocessing_view = false;
+ pvs->is_ctors_reverse_view = false;
continue;
}
// Read and decompress the section.
section_size_type len;
const unsigned char* p = this->section_contents(i, &len, false);
- if (!decompress_input_section(p, len, view, view_size))
+ if (!decompress_input_section(p, len, view, view_size,
+ size, big_endian,
+ shdr.get_sh_flags()))
this->error(_("could not decompress section %s"),
this->section_name(i).c_str());
}
pvs->view_size = view_size;
pvs->is_input_output_view = output_offset == invalid_address;
pvs->is_postprocessing_view = os->requires_postprocessing();
+ pvs->is_ctors_reverse_view =
+ (!parameters->options().relocatable()
+ && view_size > size / 8
+ && (strcmp(os->name(), ".init_array") == 0
+ || strcmp(os->name(), ".fini_array") == 0)
+ && layout->is_ctors_in_init_array(this, i));
}
// Actually read the data.
&reloc_map);
}
+ Relocatable_relocs* rr = NULL;
+ if (parameters->options().emit_relocs()
+ || parameters->options().relocatable())
+ rr = this->relocatable_relocs(i);
+ relinfo.rr = rr;
+
if (!parameters->options().relocatable())
{
target->relocate_section(&relinfo, sh_type, prelocs, reloc_count, os,
output_offset == invalid_address,
view, address, view_size, reloc_map);
if (parameters->options().emit_relocs())
- this->emit_relocs(&relinfo, i, sh_type, prelocs, reloc_count,
- os, output_offset, view, address, view_size,
- (*pviews)[i].view, (*pviews)[i].view_size);
+ target->relocate_relocs(&relinfo, sh_type, prelocs, reloc_count,
+ os, output_offset,
+ view, address, view_size,
+ (*pviews)[i].view,
+ (*pviews)[i].view_size);
if (parameters->incremental())
this->incremental_relocs_write(&relinfo, sh_type, prelocs,
reloc_count, os, output_offset, of);
}
else
- {
- Relocatable_relocs* rr = this->relocatable_relocs(i);
- target->relocate_for_relocatable(&relinfo, sh_type, prelocs,
- reloc_count, os, output_offset, rr,
- view, address, view_size,
- (*pviews)[i].view,
- (*pviews)[i].view_size);
- }
- }
-}
-
-// Emit the relocs for --emit-relocs.
-
-template<int size, bool big_endian>
-void
-Sized_relobj_file<size, big_endian>::emit_relocs(
- const Relocate_info<size, big_endian>* relinfo,
- unsigned int i,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- typename elfcpp::Elf_types<size>::Elf_Addr offset_in_output_section,
- unsigned char* view,
- typename elfcpp::Elf_types<size>::Elf_Addr address,
- section_size_type view_size,
- unsigned char* reloc_view,
- section_size_type reloc_view_size)
-{
- if (sh_type == elfcpp::SHT_REL)
- this->emit_relocs_reltype<elfcpp::SHT_REL>(relinfo, i, prelocs,
- reloc_count, output_section,
- offset_in_output_section,
- view, address, view_size,
- reloc_view, reloc_view_size);
- else
- {
- gold_assert(sh_type == elfcpp::SHT_RELA);
- this->emit_relocs_reltype<elfcpp::SHT_RELA>(relinfo, i, prelocs,
- reloc_count, output_section,
- offset_in_output_section,
- view, address, view_size,
- reloc_view, reloc_view_size);
+ target->relocate_relocs(&relinfo, sh_type, prelocs, reloc_count,
+ os, output_offset,
+ view, address, view_size,
+ (*pviews)[i].view,
+ (*pviews)[i].view_size);
}
}
-// Emit the relocs for --emit-relocs, templatized on the type of the
-// relocation section.
+// Return the output view for section SHNDX.
template<int size, bool big_endian>
-template<int sh_type>
-void
-Sized_relobj_file<size, big_endian>::emit_relocs_reltype(
- const Relocate_info<size, big_endian>* relinfo,
- unsigned int i,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- typename elfcpp::Elf_types<size>::Elf_Addr offset_in_output_section,
- unsigned char* view,
- typename elfcpp::Elf_types<size>::Elf_Addr address,
- section_size_type view_size,
- unsigned char* reloc_view,
- section_size_type reloc_view_size)
+unsigned char*
+Sized_relobj_file<size, big_endian>::do_get_output_view(
+ unsigned int shndx,
+ section_size_type* plen) const
{
- const Relocatable_relocs* rr = this->relocatable_relocs(i);
- relocate_for_relocatable<size, big_endian, sh_type>(
- relinfo,
- prelocs,
- reloc_count,
- output_section,
- offset_in_output_section,
- rr,
- view,
- address,
- view_size,
- reloc_view,
- reloc_view_size);
+ gold_assert(this->output_views_ != NULL);
+ gold_assert(shndx < this->output_views_->size());
+ const View_size& v = (*this->output_views_)[shndx];
+ *plen = v.view_size;
+ return v.view;
}
// Write the incremental relocs.
std::string from;
std::string to;
parameters->target().calls_non_split(this, shndx, p->first, p->second,
+ prelocs, reloc_count,
view, view_size, &from, &to);
if (!from.empty())
{
continue;
bool is_ordinary;
- unsigned int sym_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
- &is_ordinary);
- if (!is_ordinary || sym_shndx != shndx)
+ Symbol_location loc;
+ loc.shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(),
+ &is_ordinary);
+ if (!is_ordinary)
+ continue;
+
+ loc.object = this;
+ loc.offset = isym.get_st_value();
+ parameters->target().function_location(&loc);
+
+ if (loc.shndx != shndx)
continue;
section_offset_type value =
- convert_to_section_size_type(isym.get_st_value());
+ convert_to_section_size_type(loc.offset);
section_size_type fnsize =
convert_to_section_size_type(isym.get_st_size());
}
}
+// Reverse the words in a section. Used for .ctors sections mapped to
+// .init_array sections. See ctors_sections_in_init_array in
+// layout.cc.
+
+template<int size, bool big_endian>
+void
+Sized_relobj_file<size, big_endian>::reverse_words(unsigned char* view,
+ section_size_type view_size)
+{
+ typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
+ Valtype* vview = reinterpret_cast<Valtype*>(view);
+ section_size_type vview_size = view_size / (size / 8);
+ for (section_size_type i = 0; i < vview_size / 2; ++i)
+ {
+ Valtype tmp = vview[i];
+ vview[i] = vview[vview_size - 1 - i];
+ vview[vview_size - 1 - i] = tmp;
+ }
+}
+
// Class Merged_symbol_value.
template<int size>
const Relobj* object,
unsigned int input_shndx)
{
- Object_merge_map* map = object->merge_map();
- map->initialize_input_to_output_map<size>(input_shndx,
- this->output_start_address_,
- &this->output_addresses_);
+ object->initialize_input_to_output_map<size>(input_shndx,
+ this->output_start_address_,
+ &this->output_addresses_);
}
// Get the output value corresponding to an input offset if we
typename elfcpp::Elf_types<size>::Elf_Addr input_offset) const
{
section_offset_type output_offset;
- bool found = object->merge_map()->get_output_offset(NULL, input_shndx,
- input_offset,
- &output_offset);
+ bool found = object->merge_output_offset(input_shndx, input_offset,
+ &output_offset);
// If this assertion fails, it means that some relocation was
// against a portion of an input merge section which we didn't map
const unsigned char* pshdrs,
Output_file* of,
Views* pviews);
+
+template
+unsigned char*
+Sized_relobj_file<32, false>::do_get_output_view(
+ unsigned int shndx,
+ section_size_type* plen) const;
#endif
#ifdef HAVE_TARGET_32_BIG
const unsigned char* pshdrs,
Output_file* of,
Views* pviews);
+
+template
+unsigned char*
+Sized_relobj_file<32, true>::do_get_output_view(
+ unsigned int shndx,
+ section_size_type* plen) const;
#endif
#ifdef HAVE_TARGET_64_LITTLE
const unsigned char* pshdrs,
Output_file* of,
Views* pviews);
+
+template
+unsigned char*
+Sized_relobj_file<64, false>::do_get_output_view(
+ unsigned int shndx,
+ section_size_type* plen) const;
#endif
#ifdef HAVE_TARGET_64_BIG
const unsigned char* pshdrs,
Output_file* of,
Views* pviews);
+
+template
+unsigned char*
+Sized_relobj_file<64, true>::do_get_output_view(
+ unsigned int shndx,
+ section_size_type* plen) const;
#endif
#ifdef HAVE_TARGET_32_LITTLE