aboutsummaryrefslogtreecommitdiff
path: root/gold/reloc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gold/reloc.cc')
-rw-r--r--gold/reloc.cc260
1 files changed, 260 insertions, 0 deletions
diff --git a/gold/reloc.cc b/gold/reloc.cc
new file mode 100644
index 0000000..905eeae
--- /dev/null
+++ b/gold/reloc.cc
@@ -0,0 +1,260 @@
+// reloc.cc -- relocate input files for gold.
+
+#include "gold.h"
+
+#include "workqueue.h"
+#include "object.h"
+#include "output.h"
+#include "reloc.h"
+
+namespace gold
+{
+
+// Relocate_task methods.
+
+// These tasks are always runnable.
+
+Task::Is_runnable_type
+Relocate_task::is_runnable(Workqueue*)
+{
+ return IS_RUNNABLE;
+}
+
+// We want to lock the file while we run. We want to unblock
+// FINAL_BLOCKER when we are done.
+
+class Relocate_task::Relocate_locker : public Task_locker
+{
+ public:
+ Relocate_locker(Task_token& token, Workqueue* workqueue,
+ Object* object)
+ : blocker_(token, workqueue), objlock_(*object)
+ { }
+
+ private:
+ Task_locker_block blocker_;
+ Task_locker_obj<Object> objlock_;
+};
+
+Task_locker*
+Relocate_task::locks(Workqueue* workqueue)
+{
+ return new Relocate_locker(*this->final_blocker_, workqueue,
+ this->object_);
+}
+
+// Run the task.
+
+void
+Relocate_task::run(Workqueue*)
+{
+ this->object_->relocate(this->options_, this->symtab_, this->sympool_,
+ this->of_);
+}
+
+// Relocate the input sections and write out the local symbols.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::do_relocate(const General_options&,
+ const Symbol_table* symtab,
+ const Stringpool* sympool,
+ Output_file* of)
+{
+ unsigned int shnum = this->shnum();
+
+ // Read the section headers.
+ const unsigned char* pshdrs = this->get_view(this->shoff_,
+ shnum * This::shdr_size);
+
+ Views views;
+ views.resize(shnum);
+
+ // Make two passes over the sections. The first one copies the
+ // section data to the output file. The second one applies
+ // relocations.
+
+ this->write_sections(pshdrs, of, &views);
+
+ // Apply relocations.
+
+ this->relocate_sections(symtab, pshdrs, &views);
+
+ // Write out the accumulated views.
+ for (unsigned int i = 1; i < shnum; ++i)
+ {
+ if (views[i].view != NULL)
+ of->write_output_view(views[i].offset, views[i].view_size,
+ views[i].view);
+ }
+
+ // Write out the local symbols.
+ this->write_local_symbols(of, sympool);
+}
+
+// Write section data to the output file. PSHDRS points to the
+// section headers. Record the views in *PVIEWS for use when
+// relocating.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::write_sections(const unsigned char* pshdrs,
+ Output_file* of,
+ Views* pviews)
+{
+ unsigned int shnum = this->shnum();
+ std::vector<Map_to_output>& map_sections(this->map_to_output());
+
+ const unsigned char* p = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ {
+ View_size* pvs = &(*pviews)[i];
+
+ pvs->view = NULL;
+
+ const Output_section* os = map_sections[i].output_section;
+ if (os == NULL)
+ continue;
+
+ typename This::Shdr shdr(p);
+
+ if (shdr.get_sh_type() == elfcpp::SHT_NOBITS)
+ continue;
+
+ assert(map_sections[i].offset >= 0
+ && map_sections[i].offset < os->data_size());
+ off_t start = os->offset() + map_sections[i].offset;
+ off_t sh_size = shdr.get_sh_size();
+
+ unsigned char* view = of->get_output_view(start, sh_size);
+ this->input_file()->file().read(shdr.get_sh_offset(),
+ sh_size,
+ view);
+ pvs->view = view;
+ pvs->address = os->address() + map_sections[i].offset;
+ pvs->offset = start;
+ pvs->view_size = sh_size;
+ }
+}
+
+// Relocate section data. VIEWS points to the section data as views
+// in the output file.
+
+template<int size, bool big_endian>
+void
+Sized_object<size, big_endian>::relocate_sections(const Symbol_table* symtab,
+ const unsigned char* pshdrs,
+ Views* pviews)
+{
+ unsigned int shnum = this->shnum();
+ std::vector<Map_to_output>& map_sections(this->map_to_output());
+ Sized_target<size, big_endian>* target = this->sized_target();
+
+ const unsigned char* p = pshdrs + This::shdr_size;
+ for (unsigned int i = 1; i < shnum; ++i, p += This::shdr_size)
+ {
+ typename This::Shdr shdr(p);
+
+ unsigned int sh_type = shdr.get_sh_type();
+ if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA)
+ continue;
+
+ unsigned int index = shdr.get_sh_info();
+ if (index >= this->shnum())
+ {
+ fprintf(stderr, _("%s: %s: relocation section %u has bad info %u\n"),
+ program_name, this->name().c_str(), i, index);
+ gold_exit(false);
+ }
+
+ if (map_sections[index].output_section == NULL)
+ {
+ // This relocation section is against a section which we
+ // discarded.
+ continue;
+ }
+
+ assert((*pviews)[index].view != NULL);
+
+ if (shdr.get_sh_link() != this->symtab_shnum_)
+ {
+ fprintf(stderr,
+ _("%s: %s: relocation section %u uses unexpected "
+ "symbol table %u\n"),
+ program_name, this->name().c_str(), i, shdr.get_sh_link());
+ gold_exit(false);
+ }
+
+ off_t sh_size = shdr.get_sh_size();
+ const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(),
+ sh_size);
+
+ unsigned int reloc_size;
+ if (sh_type == elfcpp::SHT_REL)
+ reloc_size = elfcpp::Elf_sizes<size>::rel_size;
+ else
+ reloc_size = elfcpp::Elf_sizes<size>::rela_size;
+
+ if (reloc_size != shdr.get_sh_entsize())
+ {
+ fprintf(stderr,
+ _("%s: %s: unexpected entsize for reloc section %u: "
+ "%lu != %u"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(shdr.get_sh_entsize()),
+ reloc_size);
+ gold_exit(false);
+ }
+
+ size_t reloc_count = sh_size / reloc_size;
+ if (reloc_count * reloc_size != sh_size)
+ {
+ fprintf(stderr, _("%s: %s: reloc section %u size %lu uneven"),
+ program_name, this->name().c_str(), i,
+ static_cast<unsigned long>(sh_size));
+ gold_exit(false);
+ }
+
+ target->relocate_section(symtab, this, sh_type, prelocs, reloc_count,
+ this->local_symbol_count_,
+ this->values_,
+ this->symbols_,
+ (*pviews)[index].view,
+ (*pviews)[index].address,
+ (*pviews)[index].view_size);
+ }
+}
+
+// Instantiate the templates we need. We could use the configure
+// script to restrict this to only the ones for implemented targets.
+
+template
+void
+Sized_object<32, false>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Stringpool* sympool,
+ Output_file* of);
+
+template
+void
+Sized_object<32, true>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Stringpool* sympool,
+ Output_file* of);
+
+template
+void
+Sized_object<64, false>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Stringpool* sympool,
+ Output_file* of);
+
+template
+void
+Sized_object<64, true>::do_relocate(const General_options& options,
+ const Symbol_table* symtab,
+ const Stringpool* sympool,
+ Output_file* of);
+
+
+} // End namespace gold.