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>
+
+ * 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
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)
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();
}
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);
}
}
// 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);
+ }
}
}
// 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);
+ }
}
}
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;
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;
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);
}
}
// 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)
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*
objname = _("linker script");
break;
case PREDEFINED:
+ case INCREMENTAL_BASE:
objname = _("linker defined");
break;
default:
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_);
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
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;
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
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;
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
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
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;
}
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;
}
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;
}
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)
{
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)
{
return NULL;
sym->init_constant(name, version, value, symsize, type, binding, visibility,
- nonvis);
+ nonvis, defined == PREDEFINED);
if (oldsym == NULL)
{
&& !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.
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
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
// 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
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
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.