diff options
-rw-r--r-- | gold/ChangeLog | 36 | ||||
-rw-r--r-- | gold/common.cc | 45 | ||||
-rw-r--r-- | gold/incremental-dump.cc | 6 | ||||
-rw-r--r-- | gold/incremental.cc | 80 | ||||
-rw-r--r-- | gold/output.cc | 10 | ||||
-rw-r--r-- | gold/output.h | 5 | ||||
-rw-r--r-- | gold/resolve.cc | 3 | ||||
-rw-r--r-- | gold/symtab.cc | 37 | ||||
-rw-r--r-- | gold/symtab.h | 24 |
9 files changed, 200 insertions, 46 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 2626867..867d776 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,5 +1,41 @@ 2011-06-07 Cary Coutant <ccoutant@google.com> + * common.cc (Symbol_table::do_allocate_commons_list): For incremental + update, allocate common from bss section's free list. + * incremental-dump.cc (dump_incremental_inputs): Print flag for + linker-defined symbols. + * incremental.cc (Sized_incremental_binary::do_process_got_plt): + Skip GOT and PLT entries that are no longer referenced. + (Output_section_incremental_inputs::write_info_blocks): Mark + linker-defined symbols. + (Sized_incr_relobj::do_add_symbols): Process linker-defined symbols. + * output.cc (Output_section::allocate): New function. + * output.h (Output_section::allocate): New function. + * resolve.cc (Symbol_table::report_resolve_problem): Add case for + linker-defined symbols. + (Symbol::override_base_with_special): Copy is_predefined_ flag. + * symtab.cc (Symbol::init_fields): Initialize is_predefined_ flag. + (Symbol::init_base_output_data): Likewise. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Sized_symbol::init_output_data): Likewise. + (Sized_symbol::init_output_segment): Likewise. + (Sized_symbol::init_constant): Likewise. + (Symbol_table::do_define_in_output_data): Likewise. + (Symbol_table::do_define_in_output_segment): Likewise. + (Symbol_table::do_define_as_constant): Likewise. + * symtab.h (Symbol::is_predefined): New function. + (Symbol::init_base_output_data): Add is_predefined parameter. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Symbol::is_predefined_): New data member. + (Sized_symbol::init_output_data): Add is_predefined parameter. + (Sized_symbol::init_output_segment): Likewise. + (Sized_symbol::init_constant): Likewise. + (enum Symbol_table::Defined): Add INCREMENTAL_BASE. + +2011-06-07 Cary Coutant <ccoutant@google.com> + * copy-relocs.cc (Copy_relocs::copy_reloc): Call make_copy_reloc instead of emit_copy_reloc. (Copy_relocs::emit_copy_reloc): Refactor. diff --git a/gold/common.cc b/gold/common.cc index 6acd2b5..bffa829 100644 --- a/gold/common.cc +++ b/gold/common.cc @@ -286,12 +286,23 @@ Symbol_table::do_allocate_commons_list( gold_unreachable(); } - Output_data_space* poc = new Output_data_space(addralign, ds_name); - Output_section* os = layout->add_output_section_data(name, - elfcpp::SHT_NOBITS, - flags, poc, - ORDER_INVALID, - false); + Output_data_space* poc; + Output_section* os; + + if (!parameters->incremental_update()) + { + poc = new Output_data_space(addralign, ds_name); + os = layout->add_output_section_data(name, elfcpp::SHT_NOBITS, flags, + poc, ORDER_INVALID, false); + } + else + { + // When doing an incremental update, we need to allocate each common + // directly from the output section's free list. + poc = NULL; + os = layout->find_output_section(name); + } + if (os != NULL) { if (commons_section_type == COMMONS_SMALL) @@ -329,12 +340,26 @@ Symbol_table::do_allocate_commons_list( if (mapfile != NULL) mapfile->report_allocate_common(sym, ssym->symsize()); - off = align_address(off, ssym->value()); - ssym->allocate_common(poc, off); - off += ssym->symsize(); + if (poc != NULL) + { + off = align_address(off, ssym->value()); + ssym->allocate_common(poc, off); + off += ssym->symsize(); + } + else + { + // For an incremental update, allocate from the free list. + off = os->allocate(ssym->symsize(), ssym->value()); + if (off == -1) + gold_fatal(_("out of patch space in section %s; " + "relink with --incremental-full"), + os->name()); + ssym->allocate_common(os, off); + } } - poc->set_current_data_size(off); + if (poc != NULL) + poc->set_current_data_size(off); commons->clear(); } diff --git a/gold/incremental-dump.cc b/gold/incremental-dump.cc index e7e838a..fb3d25f 100644 --- a/gold/incremental-dump.cc +++ b/gold/incremental-dump.cc @@ -322,12 +322,14 @@ dump_incremental_inputs(const char* argv0, const char* filename, symname = "<unknown>"; printf(" %6d %6d %8d %8d %8d %8d %-5s %s\n", output_symndx, - info.shndx(), + info.shndx() == -1U ? -1 : info.shndx(), input_file.get_symbol_offset(symndx), info.next_offset(), info.reloc_count(), info.reloc_offset(), - info.shndx() != elfcpp::SHN_UNDEF ? "DEF" : "UNDEF", + (info.shndx() == -1U + ? "BASE" + : info.shndx() == 0 ? "UNDEF" : "DEF"), symname); } } diff --git a/gold/incremental.cc b/gold/incremental.cc index 98f09d0..c92bb07 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -630,10 +630,14 @@ Sized_incremental_binary<size, big_endian>::do_process_got_plt( // FIXME: This should really be a fatal error (corrupt input). gold_assert(symndx >= first_global && symndx < symtab_count); Symbol* sym = this->global_symbol(symndx - first_global); - gold_debug(DEBUG_INCREMENTAL, - "GOT entry %d, type %02x: %s", - i, got_type, sym->name()); - target->reserve_global_got_entry(i, sym, got_type); + // Add the GOT entry only if the symbol is still referenced. + if (sym != NULL && sym->in_reg()) + { + gold_debug(DEBUG_INCREMENTAL, + "GOT entry %d, type %02x: %s", + i, got_type, sym->name()); + target->reserve_global_got_entry(i, sym, got_type); + } } } @@ -644,10 +648,14 @@ Sized_incremental_binary<size, big_endian>::do_process_got_plt( // FIXME: This should really be a fatal error (corrupt input). gold_assert(plt_desc >= first_global && plt_desc < symtab_count); Symbol* sym = this->global_symbol(plt_desc - first_global); - gold_debug(DEBUG_INCREMENTAL, - "PLT entry %d: %s", - i, sym->name()); - target->register_global_plt_entry(i, sym); + // Add the PLT entry only if the symbol is still referenced. + if (sym->in_reg()) + { + gold_debug(DEBUG_INCREMENTAL, + "PLT entry %d: %s", + i, sym->name()); + target->register_global_plt_entry(i, sym); + } } } @@ -1548,14 +1556,24 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks( if (sym->is_forwarder()) sym = this->symtab_->resolve_forwards(sym); unsigned int shndx = 0; - if (sym->source() == Symbol::FROM_OBJECT - && sym->object() == obj - && sym->is_defined()) + if (sym->source() != Symbol::FROM_OBJECT) + { + // The symbol was defined by the linker (e.g., common). + // We mark these symbols with a special SHNDX of -1, + // but exclude linker-predefined symbols and symbols + // copied from shared objects. + if (!sym->is_predefined() + && !sym->is_copied_from_dynobj()) + shndx = -1U; + } + else if (sym->object() == obj && sym->is_defined()) { bool is_ordinary; unsigned int orig_shndx = sym->shndx(&is_ordinary); if (is_ordinary) shndx = index_map[orig_shndx]; + else + shndx = 1; } unsigned int symtab_index = sym->symtab_index(); unsigned int chain = 0; @@ -2026,7 +2044,7 @@ Sized_relobj_incr<size, big_endian>::do_add_symbols( st_bind = elfcpp::STB_GLOBAL; unsigned int input_shndx = info.shndx(); - if (input_shndx == 0) + if (input_shndx == 0 || input_shndx == -1U) { shndx = elfcpp::SHN_UNDEF; v = 0; @@ -2053,10 +2071,40 @@ Sized_relobj_incr<size, big_endian>::do_add_symbols( osym.put_st_other(gsym.get_st_other()); osym.put_st_shndx(shndx); - this->symbols_[i] = - symtab->add_from_incrobj(this, name, NULL, &sym); - this->ibase_->add_global_symbol(output_symndx - first_global, - this->symbols_[i]); + Symbol* res = symtab->add_from_incrobj(this, name, NULL, &sym); + + // If this is a linker-defined symbol that hasn't yet been defined, + // define it now. + if (input_shndx == -1U && !res->is_defined()) + { + shndx = gsym.get_st_shndx(); + v = gsym.get_st_value(); + Elf_size_type symsize = gsym.get_st_size(); + if (shndx == elfcpp::SHN_ABS) + { + symtab->define_as_constant(name, NULL, + Symbol_table::INCREMENTAL_BASE, + v, symsize, st_type, st_bind, + gsym.get_st_visibility(), 0, + false, false); + } + else + { + Output_section* os = this->ibase_->output_section(shndx); + gold_assert(os != NULL && os->has_fixed_layout()); + v -= os->address(); + if (symsize > 0) + os->reserve(v, symsize); + symtab->define_in_output_data(name, NULL, + Symbol_table::INCREMENTAL_BASE, + os, v, symsize, st_type, st_bind, + gsym.get_st_visibility(), 0, + false, false); + } + } + + this->symbols_[i] = res; + this->ibase_->add_global_symbol(output_symndx - first_global, res); } } diff --git a/gold/output.cc b/gold/output.cc index 3f6cb70..0134d33 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -3726,12 +3726,22 @@ Output_section::set_fixed_layout(uint64_t sh_addr, off_t sh_offset, // Reserve space within the fixed layout for the section. Used for // incremental update links. + void Output_section::reserve(uint64_t sh_offset, uint64_t sh_size) { this->free_list_.remove(sh_offset, sh_offset + sh_size); } +// Allocate space from the free list for the section. Used for +// incremental update links. + +off_t +Output_section::allocate(off_t len, uint64_t addralign) +{ + return this->free_list_.allocate(len, addralign, 0); +} + // Output segment methods. Output_segment::Output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) diff --git a/gold/output.h b/gold/output.h index 86c308f..72d1dba 100644 --- a/gold/output.h +++ b/gold/output.h @@ -3432,6 +3432,11 @@ class Output_section : public Output_data void reserve(uint64_t sh_offset, uint64_t sh_size); + // Allocate space from the free list for the section. Used for + // incremental update links. + off_t + allocate(off_t len, uint64_t addralign); + protected: // Return the output section--i.e., the object itself. Output_section* diff --git a/gold/resolve.cc b/gold/resolve.cc index a9a89fa..fd0fea6 100644 --- a/gold/resolve.cc +++ b/gold/resolve.cc @@ -830,6 +830,7 @@ Symbol_table::report_resolve_problem(bool is_error, const char* msg, objname = _("linker script"); break; case PREDEFINED: + case INCREMENTAL_BASE: objname = _("linker defined"); break; default: @@ -908,6 +909,8 @@ Symbol::override_base_with_special(const Symbol* from) if (from->needs_dynsym_value_) this->needs_dynsym_value_ = true; + this->is_predefined_ = from->is_predefined_; + // We shouldn't see these flags. If we do, we need to handle them // somehow. gold_assert(!from->is_forwarder_); diff --git a/gold/symtab.cc b/gold/symtab.cc index 12e2762..92f83af 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -79,6 +79,7 @@ Symbol::init_fields(const char* name, const char* version, this->is_defined_in_discarded_section_ = false; this->undef_binding_set_ = false; this->undef_binding_weak_ = false; + this->is_predefined_ = false; } // Return the demangled version of the symbol's name, but only @@ -133,7 +134,8 @@ void Symbol::init_base_output_data(const char* name, const char* version, Output_data* od, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, - unsigned char nonvis, bool offset_is_from_end) + unsigned char nonvis, bool offset_is_from_end, + bool is_predefined) { this->init_fields(name, version, type, binding, visibility, nonvis); this->u_.in_output_data.output_data = od; @@ -141,6 +143,7 @@ Symbol::init_base_output_data(const char* name, const char* version, this->source_ = IN_OUTPUT_DATA; this->in_reg_ = true; this->in_real_elf_ = true; + this->is_predefined_ = is_predefined; } // Initialize the fields in the base class Symbol for a symbol defined @@ -151,7 +154,8 @@ Symbol::init_base_output_segment(const char* name, const char* version, Output_segment* os, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, - Segment_offset_base offset_base) + Segment_offset_base offset_base, + bool is_predefined) { this->init_fields(name, version, type, binding, visibility, nonvis); this->u_.in_output_segment.output_segment = os; @@ -159,6 +163,7 @@ Symbol::init_base_output_segment(const char* name, const char* version, this->source_ = IN_OUTPUT_SEGMENT; this->in_reg_ = true; this->in_real_elf_ = true; + this->is_predefined_ = is_predefined; } // Initialize the fields in the base class Symbol for a symbol defined @@ -167,12 +172,14 @@ Symbol::init_base_output_segment(const char* name, const char* version, void Symbol::init_base_constant(const char* name, const char* version, elfcpp::STT type, elfcpp::STB binding, - elfcpp::STV visibility, unsigned char nonvis) + elfcpp::STV visibility, unsigned char nonvis, + bool is_predefined) { this->init_fields(name, version, type, binding, visibility, nonvis); this->source_ = IS_CONSTANT; this->in_reg_ = true; this->in_real_elf_ = true; + this->is_predefined_ = is_predefined; } // Initialize the fields in the base class Symbol for an undefined @@ -227,10 +234,11 @@ Sized_symbol<size>::init_output_data(const char* name, const char* version, elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, - bool offset_is_from_end) + bool offset_is_from_end, + bool is_predefined) { this->init_base_output_data(name, version, od, type, binding, visibility, - nonvis, offset_is_from_end); + nonvis, offset_is_from_end, is_predefined); this->value_ = value; this->symsize_ = symsize; } @@ -246,10 +254,11 @@ Sized_symbol<size>::init_output_segment(const char* name, const char* version, elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, - Segment_offset_base offset_base) + Segment_offset_base offset_base, + bool is_predefined) { this->init_base_output_segment(name, version, os, type, binding, visibility, - nonvis, offset_base); + nonvis, offset_base, is_predefined); this->value_ = value; this->symsize_ = symsize; } @@ -262,9 +271,11 @@ void Sized_symbol<size>::init_constant(const char* name, const char* version, Value_type value, Size_type symsize, elfcpp::STT type, elfcpp::STB binding, - elfcpp::STV visibility, unsigned char nonvis) + elfcpp::STV visibility, unsigned char nonvis, + bool is_predefined) { - this->init_base_constant(name, version, type, binding, visibility, nonvis); + this->init_base_constant(name, version, type, binding, visibility, nonvis, + is_predefined); this->value_ = value; this->symsize_ = symsize; } @@ -1843,7 +1854,8 @@ Symbol_table::do_define_in_output_data( return NULL; sym->init_output_data(name, version, od, value, symsize, type, binding, - visibility, nonvis, offset_is_from_end); + visibility, nonvis, offset_is_from_end, + defined == PREDEFINED); if (oldsym == NULL) { @@ -1956,7 +1968,8 @@ Symbol_table::do_define_in_output_segment( return NULL; sym->init_output_segment(name, version, os, value, symsize, type, binding, - visibility, nonvis, offset_base); + visibility, nonvis, offset_base, + defined == PREDEFINED); if (oldsym == NULL) { @@ -2068,7 +2081,7 @@ Symbol_table::do_define_as_constant( return NULL; sym->init_constant(name, version, value, symsize, type, binding, visibility, - nonvis); + nonvis, defined == PREDEFINED); if (oldsym == NULL) { diff --git a/gold/symtab.h b/gold/symtab.h index 43e3efa..51c31d5 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -803,6 +803,11 @@ class Symbol && !this->is_func()); } + // Return true if this symbol was predefined by the linker. + bool + is_predefined() const + { return this->is_predefined_; } + protected: // Instances of this class should always be created at a specific // size. @@ -828,7 +833,8 @@ class Symbol void init_base_output_data(const char* name, const char* version, Output_data*, elfcpp::STT, elfcpp::STB, elfcpp::STV, - unsigned char nonvis, bool offset_is_from_end); + unsigned char nonvis, bool offset_is_from_end, + bool is_predefined); // Initialize fields for an Output_segment. void @@ -836,13 +842,14 @@ class Symbol Output_segment* os, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, unsigned char nonvis, - Segment_offset_base offset_base); + Segment_offset_base offset_base, + bool is_predefined); // Initialize fields for a constant. void init_base_constant(const char* name, const char* version, elfcpp::STT type, elfcpp::STB binding, elfcpp::STV visibility, - unsigned char nonvis); + unsigned char nonvis, bool is_predefined); // Initialize fields for an undefined symbol. void @@ -991,6 +998,8 @@ class Symbol // True if this symbol was a weak undef resolved by a dynamic def // (bit 33). bool undef_binding_weak_ : 1; + // True if this symbol is a predefined linker symbol (bit 34). + bool is_predefined_ : 1; }; // The parts of a symbol which are size specific. Using a template @@ -1020,20 +1029,20 @@ class Sized_symbol : public Symbol init_output_data(const char* name, const char* version, Output_data*, Value_type value, Size_type symsize, elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis, - bool offset_is_from_end); + bool offset_is_from_end, bool is_predefined); // Initialize fields for an Output_segment. void init_output_segment(const char* name, const char* version, Output_segment*, Value_type value, Size_type symsize, elfcpp::STT, elfcpp::STB, elfcpp::STV, unsigned char nonvis, - Segment_offset_base offset_base); + Segment_offset_base offset_base, bool is_predefined); // Initialize fields for a constant. void init_constant(const char* name, const char* version, Value_type value, Size_type symsize, elfcpp::STT, elfcpp::STB, elfcpp::STV, - unsigned char nonvis); + unsigned char nonvis, bool is_predefined); // Initialize fields for an undefined symbol. void @@ -1250,6 +1259,9 @@ class Symbol_table SCRIPT, // Predefined by the linker. PREDEFINED, + // Defined by the linker during an incremental base link, but not + // a predefined symbol (e.g., common, defined in script). + INCREMENTAL_BASE, }; // The order in which we sort common symbols. |