From 94a3fc8b837eb39007fa4e82120f60ec9429317d Mon Sep 17 00:00:00 2001 From: Cary Coutant Date: Fri, 22 Apr 2011 22:39:55 +0000 Subject: [PATCH] * incremental.cc (Sized_incremental_binary::setup_readers): Allocate global symbol map. (Sized_incremental_binary::do_apply_incremental_relocs): New function. (Sized_incr_relobj::do_add_symbols): Add symbols to global symbol map. (Sized_incr_relobj::do_relocate): Remap section indices in incremental relocations. (Sized_incr_dynobj::do_add_symbols): Add symbols to global symbol map. (Sized_incr_dynobj::do_for_all_global_symbols): Remove FIXME. (Sized_incr_dynobj::do_for_all_local_got_entries): Likewise. * incremental.h (Incremental_inputs_reader::global_symbol_reader_at_offset): New function. (Incremental_binary::apply_incremental_relocs): New function. (Incremental_binary::do_apply_incremental_relocs): New function. (Sized_incremental_binary::Sized_incremental_binary): Initialize new data member. (Sized_incremental_binary::add_global_symbol): New function. (Sized_incremental_binary::global_symbol): New function. (Sized_incremental_binary::do_apply_incremental_relocs): New function. (Sized_incremental_binary::symbol_map_): New data member. * layout.cc (Layout_task_runner::run): Apply incremental relocations. * target.h (Sized_target::apply_relocation): New function. * target-reloc.h (apply_relocation): New function. * x86_64.cc (Target_x86_64::apply_relocation): New function. --- gold/ChangeLog | 27 +++++++++ gold/incremental.cc | 135 ++++++++++++++++++++++++++++++++++++++++---- gold/incremental.h | 44 ++++++++++++++- gold/layout.cc | 28 ++++++--- gold/target-reloc.h | 40 +++++++++++++ gold/target.h | 13 +++++ gold/x86_64.cc | 37 ++++++++++++ 7 files changed, 304 insertions(+), 20 deletions(-) diff --git a/gold/ChangeLog b/gold/ChangeLog index 865573e7294..c4c02f66702 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,30 @@ +2011-04-22 Cary Coutant + + * incremental.cc (Sized_incremental_binary::setup_readers): Allocate + global symbol map. + (Sized_incremental_binary::do_apply_incremental_relocs): New function. + (Sized_incr_relobj::do_add_symbols): Add symbols to global symbol map. + (Sized_incr_relobj::do_relocate): Remap section indices in incremental + relocations. + (Sized_incr_dynobj::do_add_symbols): Add symbols to global symbol map. + (Sized_incr_dynobj::do_for_all_global_symbols): Remove FIXME. + (Sized_incr_dynobj::do_for_all_local_got_entries): Likewise. + * incremental.h + (Incremental_inputs_reader::global_symbol_reader_at_offset): New + function. + (Incremental_binary::apply_incremental_relocs): New function. + (Incremental_binary::do_apply_incremental_relocs): New function. + (Sized_incremental_binary::Sized_incremental_binary): Initialize new + data member. + (Sized_incremental_binary::add_global_symbol): New function. + (Sized_incremental_binary::global_symbol): New function. + (Sized_incremental_binary::do_apply_incremental_relocs): New function. + (Sized_incremental_binary::symbol_map_): New data member. + * layout.cc (Layout_task_runner::run): Apply incremental relocations. + * target.h (Sized_target::apply_relocation): New function. + * target-reloc.h (apply_relocation): New function. + * x86_64.cc (Target_x86_64::apply_relocation): New function. + 2011-04-22 Doug Kwan * arm.cc (Arm_output_section::Arm_output_section): Set SHF_LINK_ORDER diff --git a/gold/incremental.cc b/gold/incremental.cc index ba89e0569e3..3de22f197f1 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -310,6 +310,10 @@ Sized_incremental_binary::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::do_reserve_layout( } } +// Apply incremental relocations for symbols whose values have changed. + +template +void +Sized_incremental_binary::do_apply_incremental_relocs( + const Symbol_table* symtab, + Layout* layout, + Output_file* of) +{ + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename elfcpp::Elf_types::Elf_Swxword Addend; + Incremental_symtab_reader isymtab(this->symtab_reader()); + Incremental_relocs_reader irelocs(this->relocs_reader()); + unsigned int nglobals = isymtab.symbol_count(); + const unsigned int incr_reloc_size = irelocs.reloc_size; + + Relocate_info 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* target = + parameters->sized_target(); + + 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 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 @@ -1652,17 +1752,17 @@ Sized_incr_relobj::do_add_symbols( elfcpp::Elf_strtab strtab(NULL, 0); this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); - // Incremental_symtab_reader isymtab(this->ibase_->symtab_reader()); - // Incremental_relocs_reader irelocs(this->ibase_->relocs_reader()); - // unsigned int isym_count = isymtab.symbol_count(); - // unsigned int first_global = symtab_count - isym_count; + Incremental_symtab_reader 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 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 gsym(sym_p); const char* name; if (!strtab.get_c_string(gsym.get_st_name(), &name)) @@ -1708,6 +1808,8 @@ Sized_incr_relobj::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::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::do_add_symbols( elfcpp::Elf_strtab strtab(NULL, 0); this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); - // Incremental_symtab_reader isymtab(this->ibase_->symtab_reader()); - // Incremental_relocs_reader irelocs(this->ibase_->relocs_reader()); - // unsigned int isym_count = isymtab.symbol_count(); - // unsigned int first_global = symtab_count - isym_count; + Incremental_symtab_reader 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::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]); } } @@ -2152,7 +2268,6 @@ void Sized_incr_dynobj::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. diff --git a/gold/incremental.h b/gold/incremental.h index 2b3f0e76bc8..dad5d665aac 100644 --- a/gold/incremental.h +++ b/gold/incremental.h @@ -898,6 +898,14 @@ class Incremental_inputs_reader return Incremental_input_entry_reader(this, offset); } + // Return a reader for the global symbol info at OFFSET. + Incremental_global_symbol_reader + global_symbol_reader_at_offset(unsigned int offset) const + { + const unsigned char* p = this->p_ + offset; + return Incremental_global_symbol_reader(p); + } + private: // Lookup a string in the ELF string table. const char* get_string(unsigned int offset) const @@ -1207,6 +1215,12 @@ class Incremental_binary reserve_layout(unsigned int input_file_index) { this->do_reserve_layout(input_file_index); } + // Apply incremental relocations for symbols whose values have changed. + void + apply_incremental_relocs(const Symbol_table* symtab, Layout* layout, + Output_file* of) + { this->do_apply_incremental_relocs(symtab, layout, of); } + // Functions and types for the elfcpp::Elf_file interface. This // permit us to use Incremental_binary as the File template parameter for // elfcpp::Elf_file. @@ -1279,6 +1293,10 @@ class Incremental_binary virtual void do_reserve_layout(unsigned int input_file_index) = 0; + // Apply incremental relocations for symbols whose values have changed. + virtual void + do_apply_incremental_relocs(const Symbol_table*, Layout*, Output_file*) = 0; + virtual unsigned int do_input_file_count() const = 0; @@ -1307,8 +1325,8 @@ class Sized_incremental_binary : public Incremental_binary const elfcpp::Ehdr& ehdr, Target* target) : Incremental_binary(output, target), elf_file_(this, ehdr), - section_map_(), has_incremental_info_(false), inputs_reader_(), - symtab_reader_(), relocs_reader_(), got_plt_reader_(), + section_map_(), symbol_map_(), has_incremental_info_(false), + inputs_reader_(), symtab_reader_(), relocs_reader_(), got_plt_reader_(), input_entry_readers_() { this->setup_readers(); } @@ -1322,6 +1340,20 @@ class Sized_incremental_binary : public Incremental_binary output_section(unsigned int shndx) { return this->section_map_[shndx]; } + // Map a symbol table entry from the input file to the output symbol table. + // SYMNDX is relative to the first forced-local or global symbol in the + // input file symbol table. + void + add_global_symbol(unsigned int symndx, Symbol* gsym) + { this->symbol_map_[symndx] = gsym; } + + // Map a symbol table entry from the input file to the output symbol table. + // SYMNDX is relative to the first forced-local or global symbol in the + // input file symbol table. + Symbol* + global_symbol(unsigned int symndx) const + { return this->symbol_map_[symndx]; } + // Readers for the incremental info sections. const Incremental_inputs_reader& @@ -1366,6 +1398,11 @@ class Sized_incremental_binary : public Incremental_binary virtual void do_reserve_layout(unsigned int input_file_index); + // Apply incremental relocations for symbols whose values have changed. + virtual void + do_apply_incremental_relocs(const Symbol_table* symtab, Layout* layout, + Output_file* of); + // Proxy class for a sized Incremental_input_entry_reader. class Sized_input_reader : public Input_reader @@ -1435,6 +1472,9 @@ class Sized_incremental_binary : public Incremental_binary // Map section index to an Output_section in the updated layout. std::vector section_map_; + // Map global symbols from the input file to the symbol table. + std::vector symbol_map_; + // Readers for the incremental info sections. bool has_incremental_info_; Incremental_inputs_reader inputs_reader_; diff --git a/gold/layout.cc b/gold/layout.cc index 7afb21f2c4d..e3972040b6c 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -298,10 +298,11 @@ Layout::Relaxation_debug_check::verify_sections( void Layout_task_runner::run(Workqueue* workqueue, const Task* task) { - off_t file_size = this->layout_->finalize(this->input_objects_, - this->symtab_, - this->target_, - task); + Layout* layout = this->layout_; + off_t file_size = layout->finalize(this->input_objects_, + this->symtab_, + this->target_, + task); // Now we know the final size of the output file and we know where // each piece of information goes. @@ -309,11 +310,11 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task) if (this->mapfile_ != NULL) { this->mapfile_->print_discarded_sections(this->input_objects_); - this->layout_->print_to_mapfile(this->mapfile_); + layout->print_to_mapfile(this->mapfile_); } Output_file* of; - if (this->layout_->incremental_base() == NULL) + if (layout->incremental_base() == NULL) { of = new Output_file(parameters->options().output_file_name()); if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF) @@ -322,13 +323,24 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task) } else { - of = this->layout_->incremental_base()->output_file(); + of = layout->incremental_base()->output_file(); + + // Apply the incremental relocations for symbols whose values + // have changed. We do this before we resize the file and start + // writing anything else to it, so that we can read the old + // incremental information from the file before (possibly) + // overwriting it. + if (parameters->incremental_update()) + layout->incremental_base()->apply_incremental_relocs(this->symtab_, + this->layout_, + of); + of->resize(file_size); } // Queue up the final set of tasks. gold::queue_final_tasks(this->options_, this->input_objects_, - this->symtab_, this->layout_, workqueue, of); + this->symtab_, layout, workqueue, of); } // Layout methods. diff --git a/gold/target-reloc.h b/gold/target-reloc.h index 2d12fa21e0f..17c9c99fb23 100644 --- a/gold/target-reloc.h +++ b/gold/target-reloc.h @@ -362,6 +362,46 @@ relocate_section( } } +// Apply an incremental relocation. + +template +void +apply_relocation(const Relocate_info* relinfo, + Target_type* target, + typename elfcpp::Elf_types::Elf_Addr r_offset, + unsigned int r_type, + typename elfcpp::Elf_types::Elf_Swxword r_addend, + const Symbol* gsym, + unsigned char* view, + typename elfcpp::Elf_types::Elf_Addr address, + section_size_type view_size) +{ + // Construct the ELF relocation in a temporary buffer. + const int reloc_size = elfcpp::Elf_sizes<64>::rela_size; + unsigned char relbuf[reloc_size]; + elfcpp::Rela<64, false> rel(relbuf); + elfcpp::Rela_write<64, false> orel(relbuf); + orel.put_r_offset(r_offset); + orel.put_r_info(elfcpp::elf_r_info<64>(0, r_type)); + orel.put_r_addend(r_addend); + + // Setup a Symbol_value for the global symbol. + const Sized_symbol<64>* sym = static_cast*>(gsym); + Symbol_value<64> symval; + gold_assert(sym->has_symtab_index() && sym->symtab_index() != -1U); + symval.set_output_symtab_index(sym->symtab_index()); + symval.set_output_value(sym->value()); + if (gsym->type() == elfcpp::STT_TLS) + symval.set_is_tls_symbol(); + else if (gsym->type() == elfcpp::STT_GNU_IFUNC) + symval.set_is_ifunc_symbol(); + + Relocate relocate; + relocate.relocate(relinfo, target, NULL, -1U, rel, r_type, sym, &symval, + view + r_offset, address + r_offset, view_size); +} + // This class may be used as a typical class for the // Scan_relocatable_reloc parameter to scan_relocatable_relocs. The // template parameter Classify_reloc must be a class type which diff --git a/gold/target.h b/gold/target.h index 85af8d37c67..b86efc46a61 100644 --- a/gold/target.h +++ b/gold/target.h @@ -795,6 +795,19 @@ class Sized_target : public Target plt_entry_size() const { gold_unreachable(); } + // Apply an incremental relocation. + + virtual void + apply_relocation(const Relocate_info* /* relinfo */, + typename elfcpp::Elf_types::Elf_Addr /* r_offset */, + unsigned int /* r_type */, + typename elfcpp::Elf_types::Elf_Swxword /* r_addend */, + const Symbol* /* gsym */, + unsigned char* /* view */, + typename elfcpp::Elf_types::Elf_Addr /* address */, + section_size_type /* view_size */) + { gold_unreachable(); } + protected: Sized_target(const Target::Target_info* pti) : Target(pti) diff --git a/gold/x86_64.cc b/gold/x86_64.cc index 5ba15c45d0e..e4a70433e57 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -345,6 +345,17 @@ class Target_x86_64 : public Target_freebsd<64, false> unsigned int plt_entry_size() const; + // Apply an incremental relocation. + void + apply_relocation(const Relocate_info<64, false>* relinfo, + elfcpp::Elf_types<64>::Elf_Addr r_offset, + unsigned int r_type, + elfcpp::Elf_types<64>::Elf_Swxword r_addend, + const Symbol* gsym, + unsigned char* view, + elfcpp::Elf_types<64>::Elf_Addr address, + section_size_type view_size); + // Add a new reloc argument, returning the index in the vector. size_t add_tlsdesc_info(Sized_relobj<64, false>* object, unsigned int r_sym) @@ -3014,6 +3025,32 @@ Target_x86_64::relocate_section( reloc_symbol_changes); } +// Apply an incremental relocation. Incremental relocations always refer +// to global symbols. + +void +Target_x86_64::apply_relocation( + const Relocate_info<64, false>* relinfo, + elfcpp::Elf_types<64>::Elf_Addr r_offset, + unsigned int r_type, + elfcpp::Elf_types<64>::Elf_Swxword r_addend, + const Symbol* gsym, + unsigned char* view, + elfcpp::Elf_types<64>::Elf_Addr address, + section_size_type view_size) +{ + gold::apply_relocation<64, false, Target_x86_64, Target_x86_64::Relocate>( + relinfo, + this, + r_offset, + r_type, + r_addend, + gsym, + view, + address, + view_size); +} + // Return the size of a relocation while scanning during a relocatable // link. -- 2.30.2