* 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.
This commit is contained in:
Cary Coutant 2011-06-08 04:05:25 +00:00
parent 26d3c67de1
commit 5146f44856
9 changed files with 200 additions and 46 deletions

View File

@ -1,3 +1,39 @@
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

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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*

View File

@ -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_);

View File

@ -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)
{

View File

@ -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.