2010-01-29 Doug Kwan <dougkwan@google.com>

* arm.cc (Arm_relobj::Arm_relobj): Initialize new data member
	output_local_symbol_count_needs_update_.
	(Arm_relobj::output_local_symbol_count_needs_update,
	 Arm_relobj::set_output_local_symbol_count_needs_update,
	 Arm_relobj::update_output_local_symbol_count): New methods.
	(Arm_relobj::output_local_symbol_count_needs_update_): New data
	member.
	(Arm_exidx_cantunwind::do_fixed_endian_write): Write address
	of pointed function as in a R_ARM_PREL31 relocation.
	(Arm_output_section<big_endian>::fix_exidx_coverage): Mark objects
	for output local symbol count updating.
	(Target_arm::do_relax): Update output local symbol counts in objects
	if necessary.
	* object.h (Sized_relobj::set_output_local_symbol_count): New method.
This commit is contained in:
Doug Kwan 2010-01-29 18:23:18 +00:00
parent b0e28b39b7
commit e7eca48cb2
3 changed files with 169 additions and 6 deletions

View File

@ -1,3 +1,20 @@
2010-01-29 Doug Kwan <dougkwan@google.com>
* arm.cc (Arm_relobj::Arm_relobj): Initialize new data member
output_local_symbol_count_needs_update_.
(Arm_relobj::output_local_symbol_count_needs_update,
Arm_relobj::set_output_local_symbol_count_needs_update,
Arm_relobj::update_output_local_symbol_count): New methods.
(Arm_relobj::output_local_symbol_count_needs_update_): New data
member.
(Arm_exidx_cantunwind::do_fixed_endian_write): Write address
of pointed function as in a R_ARM_PREL31 relocation.
(Arm_output_section<big_endian>::fix_exidx_coverage): Mark objects
for output local symbol count updating.
(Target_arm::do_relax): Update output local symbol counts in objects
if necessary.
* object.h (Sized_relobj::set_output_local_symbol_count): New method.
2010-01-29 Viktor Kutuzov <vkutuzov@accesssoftek.com>
* arm.cc: Added support for the ARM relocations:

View File

@ -1399,7 +1399,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
: Sized_relobj<32, big_endian>(name, input_file, offset, ehdr),
stub_tables_(), local_symbol_is_thumb_function_(),
attributes_section_data_(NULL), mapping_symbols_info_(),
section_has_cortex_a8_workaround_(NULL), exidx_section_map_()
section_has_cortex_a8_workaround_(NULL), exidx_section_map_(),
output_local_symbol_count_needs_update_(false)
{ }
~Arm_relobj()
@ -1524,6 +1525,20 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
: NULL);
}
// Whether output local symbol count needs updating.
bool
output_local_symbol_count_needs_update() const
{ return this->output_local_symbol_count_needs_update_; }
// Set output_local_symbol_count_needs_update flag to be true.
void
set_output_local_symbol_count_needs_update()
{ this->output_local_symbol_count_needs_update_ = true; }
// Update output local symbol count at the end of relaxation.
void
update_output_local_symbol_count();
protected:
// Post constructor setup.
void
@ -1600,6 +1615,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
std::vector<bool>* section_has_cortex_a8_workaround_;
// Map a text section to its associated .ARM.exidx section, if there is one.
Exidx_section_map exidx_section_map_;
// Whether output local symbol count needs updating.
bool output_local_symbol_count_needs_update_;
};
// Arm_dynobj class.
@ -4866,7 +4883,10 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of)
// Write out the entry. The first word either points to the beginning
// or after the end of a text section. The second word is the special
// EXIDX_CANTUNWIND value.
elfcpp::Swap<32, big_endian>::writeval(wv, output_address);
uint32_t prel31_offset = output_address - this->address();
if (utils::has_overflow<31>(offset))
gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry"));
elfcpp::Swap<32, big_endian>::writeval(wv, prel31_offset & 0x7fffffffU);
elfcpp::Swap<32, big_endian>::writeval(wv + 1, elfcpp::EXIDX_CANTUNWIND);
of->write_output_view(this->offset(), oview_size, oview);
@ -5469,6 +5489,10 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
// The whole EXIDX section got merged. Remove it from output.
gold_assert(section_offset_map == NULL);
exidx_relobj->set_output_section(exidx_shndx, NULL);
// All local symbols defined in this input section will be dropped.
// We need to adjust output local symbol count.
arm_relobj->set_output_local_symbol_count_needs_update();
}
else if (deleted_bytes > 0)
{
@ -5480,6 +5504,11 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
*section_offset_map, deleted_bytes);
this->add_relaxed_input_section(merged_section);
arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx);
// All local symbols defined in discarded portions of this input
// section will be dropped. We need to adjust output local symbol
// count.
arm_relobj->set_output_local_symbol_count_needs_update();
}
else
{
@ -6106,6 +6135,99 @@ Arm_relobj<big_endian>::do_gc_process_relocs(Symbol_table* symtab,
}
}
// Update output local symbol count. Owing to EXIDX entry merging, some local
// symbols will be removed in output. Adjust output local symbol count
// accordingly. We can only changed the static output local symbol count. It
// is too late to change the dynamic symbols.
template<bool big_endian>
void
Arm_relobj<big_endian>::update_output_local_symbol_count()
{
// Caller should check that this needs updating. We want caller checking
// because output_local_symbol_count_needs_update() is most likely inlined.
gold_assert(this->output_local_symbol_count_needs_update_);
gold_assert(this->symtab_shndx() != -1U);
if (this->symtab_shndx() == 0)
{
// This object has no symbols. Weird but legal.
return;
}
// Read the symbol table section header.
const unsigned int symtab_shndx = this->symtab_shndx();
elfcpp::Shdr<32, big_endian>
symtabshdr(this, this->elf_file()->section_header(symtab_shndx));
gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB);
// Read the local symbols.
const int sym_size = elfcpp::Elf_sizes<32>::sym_size;
const unsigned int loccount = this->local_symbol_count();
gold_assert(loccount == symtabshdr.get_sh_info());
off_t locsize = loccount * sym_size;
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize, true, true);
// Loop over the local symbols.
typedef typename Sized_relobj<32, big_endian>::Output_sections
Output_sections;
const Output_sections& out_sections(this->output_sections());
unsigned int shnum = this->shnum();
unsigned int count = 0;
// Skip the first, dummy, symbol.
psyms += sym_size;
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
{
elfcpp::Sym<32, big_endian> sym(psyms);
Symbol_value<32>& lv((*this->local_values())[i]);
// This local symbol was already discarded by do_count_local_symbols.
if (!lv.needs_output_symtab_entry())
continue;
bool is_ordinary;
unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(),
&is_ordinary);
if (shndx < shnum)
{
Output_section* os = out_sections[shndx];
// This local symbol no longer has an output section. Discard it.
if (os == NULL)
{
lv.set_no_output_symtab_entry();
continue;
}
// Currently we only discard parts of EXIDX input sections.
// We explicitly check for a merged EXIDX input section to avoid
// calling Output_section_data::output_offset unless necessary.
if ((this->get_output_section_offset(shndx) == invalid_address)
&& (this->exidx_input_section_by_shndx(shndx) != NULL))
{
section_offset_type output_offset =
os->output_offset(this, shndx, lv.input_value());
if (output_offset == -1)
{
// This symbol is defined in a part of an EXIDX input section
// that is discarded due to entry merging.
lv.set_no_output_symtab_entry();
continue;
}
}
}
++count;
}
this->set_output_local_symbol_count(count);
this->output_local_symbol_count_needs_update_ = false;
}
// Arm_dynobj methods.
// Read the symbol information.
@ -6777,6 +6899,8 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab,
break;
case elfcpp::R_ARM_REL32:
break;
case elfcpp::R_ARM_PREL31:
{
// Make a dynamic relocation if necessary.
@ -9569,10 +9693,27 @@ Target_arm<big_endian>::do_relax(
// Finalize the stubs in the last relaxation pass.
if (!continue_relaxation)
for (Stub_table_iterator sp = this->stub_tables_.begin();
(sp != this->stub_tables_.end()) && !any_stub_table_changed;
++sp)
(*sp)->finalize_stubs();
{
for (Stub_table_iterator sp = this->stub_tables_.begin();
(sp != this->stub_tables_.end()) && !any_stub_table_changed;
++sp)
(*sp)->finalize_stubs();
// Update output local symbol counts of objects if necessary.
for (Input_objects::Relobj_iterator op = input_objects->relobj_begin();
op != input_objects->relobj_end();
++op)
{
Arm_relobj<big_endian>* arm_relobj =
Arm_relobj<big_endian>::as_arm_relobj(*op);
// Update output local symbol counts. We need to discard local
// symbols defined in parts of input sections that are discarded by
// relaxation.
if (arm_relobj->output_local_symbol_count_needs_update())
arm_relobj->update_output_local_symbol_count();
}
}
return continue_relaxation;
}

View File

@ -1689,6 +1689,11 @@ class Sized_relobj : public Relobj
do_relocate_sections(const Symbol_table* symtab, const Layout* layout,
const unsigned char* pshdrs, Views* pviews);
// Allow a child to set output local symbol count.
void
set_output_local_symbol_count(unsigned int value)
{ this->output_local_symbol_count_ = value; }
private:
// For convenience.
typedef Sized_relobj<size, big_endian> This;