diff options
Diffstat (limited to 'gold/incremental.cc')
-rw-r--r-- | gold/incremental.cc | 135 |
1 files changed, 125 insertions, 10 deletions
diff --git a/gold/incremental.cc b/gold/incremental.cc index ba89e05..3de22f1 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -310,6 +310,10 @@ Sized_incremental_binary<size, big_endian>::setup_readers() } } + // Initialize the map of global symbols. + unsigned int nglobals = this->symtab_reader_.symbol_count(); + this->symbol_map_.resize(nglobals); + this->has_incremental_info_ = true; } @@ -519,6 +523,102 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout( } } +// Apply incremental relocations for symbols whose values have changed. + +template<int size, bool big_endian> +void +Sized_incremental_binary<size, big_endian>::do_apply_incremental_relocs( + const Symbol_table* symtab, + Layout* layout, + Output_file* of) +{ + typedef typename elfcpp::Elf_types<size>::Elf_Addr Address; + typedef typename elfcpp::Elf_types<size>::Elf_Swxword Addend; + Incremental_symtab_reader<big_endian> isymtab(this->symtab_reader()); + Incremental_relocs_reader<size, big_endian> irelocs(this->relocs_reader()); + unsigned int nglobals = isymtab.symbol_count(); + const unsigned int incr_reloc_size = irelocs.reloc_size; + + Relocate_info<size, big_endian> relinfo; + relinfo.symtab = symtab; + relinfo.layout = layout; + relinfo.object = NULL; + relinfo.reloc_shndx = 0; + relinfo.reloc_shdr = NULL; + relinfo.data_shndx = 0; + relinfo.data_shdr = NULL; + + Sized_target<size, big_endian>* target = + parameters->sized_target<size, big_endian>(); + + for (unsigned int i = 0; i < nglobals; i++) + { + const Symbol* gsym = this->global_symbol(i); + + // If the symbol is not referenced from any unchanged input files, + // we do not need to reapply any of its relocations. + if (gsym == NULL) + continue; + + // If the symbol is defined in an unchanged file, we do not need to + // reapply any of its relocations. + if (gsym->source() == Symbol::FROM_OBJECT + && gsym->object()->is_incremental()) + continue; + + gold_debug(DEBUG_INCREMENTAL, + "Applying incremental relocations for global symbol %s [%d]", + gsym->name(), i); + + // Follow the linked list of input symbol table entries for this symbol. + // We don't bother to figure out whether the symbol table entry belongs + // to a changed or unchanged file because it's easier just to apply all + // the relocations -- although we might scribble over an area that has + // been reallocated, we do this before copying any new data into the + // output file. + unsigned int offset = isymtab.get_list_head(i); + while (offset > 0) + { + Incremental_global_symbol_reader<big_endian> sym_info = + this->inputs_reader().global_symbol_reader_at_offset(offset); + unsigned int r_base = sym_info.reloc_offset(); + unsigned int r_count = sym_info.reloc_count(); + + // Apply each relocation for this symbol table entry. + for (unsigned int j = 0; j < r_count; + ++j, r_base += incr_reloc_size) + { + unsigned int r_type = irelocs.get_r_type(r_base); + unsigned int r_shndx = irelocs.get_r_shndx(r_base); + Address r_offset = irelocs.get_r_offset(r_base); + Addend r_addend = irelocs.get_r_addend(r_base); + Output_section* os = this->output_section(r_shndx); + Address address = os->address(); + off_t section_offset = os->offset(); + size_t view_size = os->data_size(); + unsigned char* const view = of->get_output_view(section_offset, + view_size); + + gold_debug(DEBUG_INCREMENTAL, + " %08lx: %s + %d: type %d addend %ld", + (long)(section_offset + r_offset), + os->name(), + (int)r_offset, + r_type, + (long)r_addend); + + target->apply_relocation(&relinfo, r_offset, r_type, r_addend, + gsym, view, address, view_size); + + // FIXME: Do something more efficient if write_output_view + // ever becomes more than a no-op. + of->write_output_view(section_offset, view_size, view); + } + offset = sym_info.next_offset(); + } + } +} + // Get a view of the main symbol table and the symbol string table. template<int size, bool big_endian> @@ -1652,17 +1752,17 @@ Sized_incr_relobj<size, big_endian>::do_add_symbols( elfcpp::Elf_strtab strtab(NULL, 0); this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); - // Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader()); - // Incremental_relocs_reader<size, big_endian> irelocs(this->ibase_->relocs_reader()); - // unsigned int isym_count = isymtab.symbol_count(); - // unsigned int first_global = symtab_count - isym_count; + Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader()); + unsigned int isym_count = isymtab.symbol_count(); + unsigned int first_global = symtab_count - isym_count; unsigned const char* sym_p; for (unsigned int i = 0; i < nsyms; ++i) { Incremental_global_symbol_reader<big_endian> info = this->input_reader_.get_global_symbol_reader(i); - sym_p = symtab_view.data() + info.output_symndx() * sym_size; + unsigned int output_symndx = info.output_symndx(); + sym_p = symtab_view.data() + output_symndx * sym_size; elfcpp::Sym<size, big_endian> gsym(sym_p); const char* name; if (!strtab.get_c_string(gsym.get_st_name(), &name)) @@ -1708,6 +1808,8 @@ Sized_incr_relobj<size, big_endian>::do_add_symbols( this->symbols_[i] = symtab->add_from_incrobj(this, name, NULL, &sym); + this->ibase_->add_global_symbol(output_symndx - first_global, + this->symbols_[i]); } } @@ -1993,6 +2095,19 @@ Sized_incr_relobj<size, big_endian>::do_relocate(const Symbol_table*, off_t off = this->incr_reloc_output_index_ * incr_reloc_size; unsigned int len = this->incr_reloc_count_ * incr_reloc_size; memcpy(view + off, this->incr_relocs_, len); + + // The output section table may have changed, so we need to map + // the old section index to the new section index for each relocation. + for (unsigned int i = 0; i < this->incr_reloc_count_; ++i) + { + unsigned char* pov = view + off + i * incr_reloc_size; + unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(pov + 4); + Output_section* os = this->ibase_->output_section(shndx); + gold_assert(os != NULL); + shndx = os->out_shndx(); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, shndx); + } + of->write_output_view(off, len, view); } @@ -2068,10 +2183,9 @@ Sized_incr_dynobj<size, big_endian>::do_add_symbols( elfcpp::Elf_strtab strtab(NULL, 0); this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); - // Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader()); - // Incremental_relocs_reader<size, big_endian> irelocs(this->ibase_->relocs_reader()); - // unsigned int isym_count = isymtab.symbol_count(); - // unsigned int first_global = symtab_count - isym_count; + Incremental_symtab_reader<big_endian> isymtab(this->ibase_->symtab_reader()); + unsigned int isym_count = isymtab.symbol_count(); + unsigned int first_global = symtab_count - isym_count; unsigned const char* sym_p; for (unsigned int i = 0; i < nsyms; ++i) @@ -2117,6 +2231,8 @@ Sized_incr_dynobj<size, big_endian>::do_add_symbols( this->symbols_[i] = symtab->add_from_incrobj<size, big_endian>(this, name, NULL, &sym); + this->ibase_->add_global_symbol(output_symndx - first_global, + this->symbols_[i]); } } @@ -2152,7 +2268,6 @@ void Sized_incr_dynobj<size, big_endian>::do_for_all_local_got_entries( Got_offset_list::Visitor*) const { - // FIXME: Implement Sized_incr_dynobj::do_for_all_local_got_entries. } // Get the size of a section. |