aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog38
-rw-r--r--gold/arm.cc242
-rw-r--r--gold/output.cc10
-rw-r--r--gold/output.h15
4 files changed, 248 insertions, 57 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 6dbbced..4f5833b 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,41 @@
+2010-07-13 Doug Kwan <dougkwan@google.com>
+
+ * arm.cc (Arm_input_section::Arm_input_section): For a
+ SHT_ARM_EXIDX section, always keeps the input sections.
+ (Arm_input_section::set_exidx_section_link): New method.
+ (Arm_exidx_input_section::Arm_exidx_input_section): Initialize
+ has_errors_ to false.
+ (Arm_exidx_input_section::has_errors,
+ Arm_exidx_input_section::set_has_errors): New methods.
+ (Arm_exidx_input_section::has_errors_): New data member.
+ (Arm_relobj::get_exidx_shndx_list): New method.
+ (Arm_output_section::append_text_sections_to_list): Do not skip
+ section without SHF_EXECINSTR.
+ (Arm_output_section::fix_exidx_coverage): Skip input sections with
+ errors.
+ (Arm_relobj::make_exidx_input_section): Add new parameter for text
+ section header. Make error messages more verbose. Check for
+ a non-executable section linked to an EXIDX section.
+ (Arm_relobj::do_read_symbols): Remove error checking, which has been
+ moved to Arm_relobj::make_exidx_input_section. Add an assertion to
+ check that there is no deferred EXIDX section if we exit early.
+ Instead of not making an EXIDX section in case of an error, make one
+ and set the has_errors flag of it.
+ (Target_arm::do_finalize_sections): Fix up links of EXIDX sections
+ in a relocatable link.
+ (Target_arm::do_relax): Look for the EXIDX output section instead of
+ assuming that it is called .ARM.exidx.
+ (Target_arm::fix_exidx_coverage): Add a new parameter for input
+ section list. Do not check for SHF_EXECINSTR section flags but
+ skip any input section with errors.
+ * output.cc (Output_section::Output_section): Initialize
+ always_keeps_input_sections_ to false.
+ (Output_section::add_input_section): Check for
+ always_keeps_input_sections_.
+ * output.h (Output_section::always_keeps_input_sections,
+ Output_section::set_always_keeps_input_sections): New methods.
+ (Output_section::always_keeps_input_sections): New data member.
+
2010-07-13 Rafael Espindola <espindola@google.com>
* fileread.cc (try_extra_search_path, find_file): Move to Input_file.
diff --git a/gold/arm.cc b/gold/arm.cc
index ddfe543..aadac32 100644
--- a/gold/arm.cc
+++ b/gold/arm.cc
@@ -1324,7 +1324,10 @@ class Arm_output_section : public Output_section
Arm_output_section(const char* name, elfcpp::Elf_Word type,
elfcpp::Elf_Xword flags)
: Output_section(name, type, flags)
- { }
+ {
+ if (type == elfcpp::SHT_ARM_EXIDX)
+ this->set_always_keeps_input_sections();
+ }
~Arm_output_section()
{ }
@@ -1352,6 +1355,10 @@ class Arm_output_section : public Output_section
Symbol_table* symtab,
bool merge_exidx_entries);
+ // Link an EXIDX section into its corresponding text section.
+ void
+ set_exidx_section_link();
+
private:
// For convenience.
typedef Output_section::Input_section Input_section;
@@ -1376,7 +1383,7 @@ class Arm_exidx_input_section
Arm_exidx_input_section(Relobj* relobj, unsigned int shndx,
unsigned int link, uint32_t size, uint32_t addralign)
: relobj_(relobj), shndx_(shndx), link_(link), size_(size),
- addralign_(addralign)
+ addralign_(addralign), has_errors_(false)
{ }
~Arm_exidx_input_section()
@@ -1409,6 +1416,16 @@ class Arm_exidx_input_section
addralign() const
{ return this->addralign_; }
+ // Whether there are any errors in the EXIDX input section.
+ bool
+ has_errors() const
+ { return this->has_errors_; }
+
+ // Set has-errors flag.
+ void
+ set_has_errors()
+ { this->has_errors_ = true; }
+
private:
// Object containing this.
Relobj* relobj_;
@@ -1420,6 +1437,8 @@ class Arm_exidx_input_section
uint32_t size_;
// Address alignment of this. For ARM 32-bit is sufficient.
uint32_t addralign_;
+ // Whether this has any errors.
+ bool has_errors_;
};
// Arm_relobj class.
@@ -1581,6 +1600,22 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
merge_flags_and_attributes() const
{ return this->merge_flags_and_attributes_; }
+ // Export list of EXIDX section indices.
+ void
+ get_exidx_shndx_list(std::vector<unsigned int>* list) const
+ {
+ list->clear();
+ for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin();
+ p != this->exidx_section_map_.end();
+ ++p)
+ {
+ if (p->second->shndx() == p->first)
+ list->push_back(p->first);
+ }
+ // Sort list to make result independent of implementation of map.
+ std::sort(list->begin(), list->end());
+ }
+
protected:
// Post constructor setup.
void
@@ -1653,7 +1688,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian>
void
make_exidx_input_section(unsigned int shndx,
const elfcpp::Shdr<32, big_endian>& shdr,
- unsigned int text_shndx);
+ unsigned int text_shndx,
+ const elfcpp::Shdr<32, big_endian>& text_shdr);
// Return the output address of either a plain input section or a
// relaxed input section. SHNDX is the section index.
@@ -2764,7 +2800,8 @@ class Target_arm : public Sized_target<32, big_endian>
// Fix .ARM.exidx section coverage.
void
- fix_exidx_coverage(Layout*, Arm_output_section<big_endian>*, Symbol_table*);
+ fix_exidx_coverage(Layout*, const Input_objects*,
+ Arm_output_section<big_endian>*, Symbol_table*);
// Functors for STL set.
struct output_section_address_less_than
@@ -5655,10 +5692,6 @@ void
Arm_output_section<big_endian>::append_text_sections_to_list(
Text_section_list* list)
{
- // We only care about text sections.
- if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0)
- return;
-
gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0);
for (Input_section_list::const_iterator p = this->input_sections().begin();
@@ -5731,9 +5764,10 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
const Arm_exidx_input_section* exidx_input_section =
arm_relobj->exidx_input_section_by_link(shndx);
- // If this text section has no EXIDX section, force an EXIDX_CANTUNWIND
- // entry pointing to the end of the last seen EXIDX section.
- if (exidx_input_section == NULL)
+ // If this text section has no EXIDX section or if the EXIDX section
+ // has errors, force an EXIDX_CANTUNWIND entry pointing to the end
+ // of the last seen EXIDX section.
+ if (exidx_input_section == NULL || exidx_input_section->has_errors())
{
exidx_fixup.add_exidx_cantunwind_as_needed();
continue;
@@ -5817,15 +5851,20 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
if (processed_input_sections.find(Section_id(p->relobj(), p->shndx()))
== processed_input_sections.end())
{
- // We only discard a known EXIDX section because its linked
- // text section has been folded by ICF.
+ // We discard a known EXIDX section because its linked
+ // text section has been folded by ICF. We also discard an
+ // EXIDX section with error, the output does not matter in this
+ // case. We do this to avoid triggering asserts.
Arm_relobj<big_endian>* arm_relobj =
Arm_relobj<big_endian>::as_arm_relobj(p->relobj());
const Arm_exidx_input_section* exidx_input_section =
arm_relobj->exidx_input_section_by_shndx(p->shndx());
gold_assert(exidx_input_section != NULL);
- unsigned int text_shndx = exidx_input_section->link();
- gold_assert(symtab->is_section_folded(p->relobj(), text_shndx));
+ if (!exidx_input_section->has_errors())
+ {
+ unsigned int text_shndx = exidx_input_section->link();
+ gold_assert(symtab->is_section_folded(p->relobj(), text_shndx));
+ }
// Remove this from link. We also need to recount the
// local symbols.
@@ -5844,6 +5883,28 @@ Arm_output_section<big_endian>::fix_exidx_coverage(
this->set_section_offsets_need_adjustment();
}
+// Link EXIDX output sections to text output sections.
+
+template<bool big_endian>
+void
+Arm_output_section<big_endian>::set_exidx_section_link()
+{
+ gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX);
+ if (!this->input_sections().empty())
+ {
+ Input_section_list::const_iterator p = this->input_sections().begin();
+ Arm_relobj<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::as_arm_relobj(p->relobj());
+ unsigned exidx_shndx = p->shndx();
+ const Arm_exidx_input_section* exidx_input_section =
+ arm_relobj->exidx_input_section_by_shndx(exidx_shndx);
+ gold_assert(exidx_input_section != NULL);
+ unsigned int text_shndx = exidx_input_section->link();
+ Output_section* os = arm_relobj->output_section(text_shndx);
+ this->set_link_section(os);
+ }
+}
+
// Arm_relobj methods.
// Determine if an input section is scannable for stub processing. SHDR is
@@ -6445,28 +6506,57 @@ void
Arm_relobj<big_endian>::make_exidx_input_section(
unsigned int shndx,
const elfcpp::Shdr<32, big_endian>& shdr,
- unsigned int text_shndx)
+ unsigned int text_shndx,
+ const elfcpp::Shdr<32, big_endian>& text_shdr)
{
- // Issue an error and ignore this EXIDX section if it points to a text
- // section already has an EXIDX section.
- if (this->exidx_section_map_[text_shndx] != NULL)
- {
- gold_error(_("EXIDX sections %u and %u both link to text section %u "
- "in %s"),
- shndx, this->exidx_section_map_[text_shndx]->shndx(),
- text_shndx, this->name().c_str());
- return;
- }
-
// Create an Arm_exidx_input_section object for this EXIDX section.
Arm_exidx_input_section* exidx_input_section =
new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(),
shdr.get_sh_addralign());
- this->exidx_section_map_[text_shndx] = exidx_input_section;
- // Also map the EXIDX section index to this.
gold_assert(this->exidx_section_map_[shndx] == NULL);
this->exidx_section_map_[shndx] = exidx_input_section;
+
+ if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum())
+ {
+ gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"),
+ this->section_name(shndx).c_str(), shndx, text_shndx,
+ this->name().c_str());
+ exidx_input_section->set_has_errors();
+ }
+ else if (this->exidx_section_map_[text_shndx] != NULL)
+ {
+ unsigned other_exidx_shndx =
+ this->exidx_section_map_[text_shndx]->shndx();
+ gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section"
+ "%s(%u) in %s"),
+ this->section_name(shndx).c_str(), shndx,
+ this->section_name(other_exidx_shndx).c_str(),
+ other_exidx_shndx, this->section_name(text_shndx).c_str(),
+ text_shndx, this->name().c_str());
+ exidx_input_section->set_has_errors();
+ }
+ else
+ this->exidx_section_map_[text_shndx] = exidx_input_section;
+
+ // Check section flags of text section.
+ if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ {
+ gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) "
+ " in %s"),
+ this->section_name(shndx).c_str(), shndx,
+ this->section_name(text_shndx).c_str(), text_shndx,
+ this->name().c_str());
+ exidx_input_section->set_has_errors();
+ }
+ else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0)
+ // I would like to make this an error but currenlty ld just ignores
+ // this.
+ gold_warning(_("EXIDX section %s(%u) links to non-executable section "
+ "%s(%u) in %s"),
+ this->section_name(shndx).c_str(), shndx,
+ this->section_name(text_shndx).c_str(), text_shndx,
+ this->name().c_str());
}
// Read the symbol information.
@@ -6536,19 +6626,21 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX)
{
unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link());
- if (text_shndx >= this->shnum())
- gold_error(_("EXIDX section %u linked to invalid section %u"),
- i, text_shndx);
- else if (text_shndx == elfcpp::SHN_UNDEF)
+ if (text_shndx == elfcpp::SHN_UNDEF)
deferred_exidx_sections.push_back(i);
else
- this->make_exidx_input_section(i, shdr, text_shndx);
+ {
+ elfcpp::Shdr<32, big_endian> text_shdr(pshdrs
+ + text_shndx * shdr_size);
+ this->make_exidx_input_section(i, shdr, text_shndx, text_shdr);
+ }
}
}
// This is rare.
if (!must_merge_flags_and_attributes)
{
+ gold_assert(deferred_exidx_sections.empty());
this->merge_flags_and_attributes_ = false;
return;
}
@@ -6604,15 +6696,14 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd)
{
unsigned int shndx = deferred_exidx_sections[i];
elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size);
- unsigned int text_shndx;
+ unsigned int text_shndx = elfcpp::SHN_UNDEF;
Reloc_map::const_iterator it = reloc_map.find(shndx);
- if (it != reloc_map.end()
- && find_linked_text_section(pshdrs + it->second * shdr_size,
- psyms, &text_shndx))
- this->make_exidx_input_section(shndx, shdr, text_shndx);
- else
- gold_error(_("EXIDX section %u has no linked text section."),
- shndx);
+ if (it != reloc_map.end())
+ find_linked_text_section(pshdrs + it->second * shdr_size,
+ psyms, &text_shndx);
+ elfcpp::Shdr<32, big_endian> text_shdr(pshdrs
+ + text_shndx * shdr_size);
+ this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr);
}
}
}
@@ -8306,6 +8397,17 @@ Target_arm<big_endian>::do_finalize_sections(
attributes_section, false, false, false,
false);
}
+
+ // Fix up links in section EXIDX headers.
+ for (Layout::Section_list::const_iterator p = layout->section_list().begin();
+ p != layout->section_list().end();
+ ++p)
+ if ((*p)->type() == elfcpp::SHT_ARM_EXIDX)
+ {
+ Arm_output_section<big_endian>* os =
+ Arm_output_section<big_endian>::as_arm_output_section(*p);
+ os->set_exidx_section_link();
+ }
}
// Return whether a direct absolute static relocation needs to be applied.
@@ -10969,12 +11071,28 @@ Target_arm<big_endian>::do_relax(
group_sections(layout, stub_group_size, stubs_always_after_branch);
// Also fix .ARM.exidx section coverage.
- Output_section* os = layout->find_output_section(".ARM.exidx");
- if (os != NULL && os->type() == elfcpp::SHT_ARM_EXIDX)
+ Arm_output_section<big_endian>* exidx_output_section = NULL;
+ for (Layout::Section_list::const_iterator p =
+ layout->section_list().begin();
+ p != layout->section_list().end();
+ ++p)
+ if ((*p)->type() == elfcpp::SHT_ARM_EXIDX)
+ {
+ if (exidx_output_section == NULL)
+ exidx_output_section =
+ Arm_output_section<big_endian>::as_arm_output_section(*p);
+ else
+ // We cannot handle this now.
+ gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a "
+ "non-relocatable link"),
+ exidx_output_section->name(),
+ (*p)->name());
+ }
+
+ if (exidx_output_section != NULL)
{
- Arm_output_section<big_endian>* exidx_output_section =
- Arm_output_section<big_endian>::as_arm_output_section(os);
- this->fix_exidx_coverage(layout, exidx_output_section, symtab);
+ this->fix_exidx_coverage(layout, input_objects, exidx_output_section,
+ symtab);
done_exidx_fixup = true;
}
}
@@ -11425,6 +11543,7 @@ template<bool big_endian>
void
Target_arm<big_endian>::fix_exidx_coverage(
Layout* layout,
+ const Input_objects* input_objects,
Arm_output_section<big_endian>* exidx_section,
Symbol_table* symtab)
{
@@ -11437,15 +11556,30 @@ Target_arm<big_endian>::fix_exidx_coverage(
typedef std::set<Output_section*, output_section_address_less_than>
Sorted_output_section_list;
Sorted_output_section_list sorted_output_sections;
- Layout::Section_list section_list;
- layout->get_allocated_sections(&section_list);
- for (Layout::Section_list::const_iterator p = section_list.begin();
- p != section_list.end();
+
+ // Find out all the output sections of input sections pointed by
+ // EXIDX input sections.
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
++p)
{
- // We only care about output sections that contain executable code.
- if (((*p)->flags() & elfcpp::SHF_EXECINSTR) != 0)
- sorted_output_sections.insert(*p);
+ Arm_relobj<big_endian>* arm_relobj =
+ Arm_relobj<big_endian>::as_arm_relobj(*p);
+ std::vector<unsigned int> shndx_list;
+ arm_relobj->get_exidx_shndx_list(&shndx_list);
+ for (size_t i = 0; i < shndx_list.size(); ++i)
+ {
+ const Arm_exidx_input_section* exidx_input_section =
+ arm_relobj->exidx_input_section_by_shndx(shndx_list[i]);
+ gold_assert(exidx_input_section != NULL);
+ if (!exidx_input_section->has_errors())
+ {
+ unsigned int text_shndx = exidx_input_section->link();
+ Output_section *os = arm_relobj->output_section(text_shndx);
+ if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0)
+ sorted_output_sections.insert(os);
+ }
+ }
}
// Go over the output sections in ascending order of output addresses.
diff --git a/gold/output.cc b/gold/output.cc
index 3ac8a3d..a487eb8 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1949,6 +1949,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
is_entsize_zero_(false),
section_offsets_need_adjustment_(false),
is_noload_(false),
+ always_keeps_input_sections_(false),
tls_offset_(0),
checkpoint_(NULL),
lookup_maps_(new Output_section_lookup_maps)
@@ -2038,8 +2039,10 @@ Output_section::add_input_section(Layout* layout,
{
// Keep information about merged input sections for rebuilding fast
// lookup maps if we have sections-script or we do relaxation.
- bool keeps_input_sections =
- have_sections_script || parameters->target().may_relax();
+ bool keeps_input_sections = (this->always_keeps_input_sections_
+ || have_sections_script
+ || parameters->target().may_relax());
+
if (this->add_merge_input_section(object, shndx, sh_flags, entsize,
addralign, keeps_input_sections))
{
@@ -2100,7 +2103,8 @@ Output_section::add_input_section(Layout* layout,
// the future, we keep track of the sections. If the
// --section-ordering-file option is used to specify the order of
// sections, we need to keep track of sections.
- if (have_sections_script
+ if (this->always_keeps_input_sections_
+ || have_sections_script
|| !this->input_sections_.empty()
|| this->may_sort_attached_input_sections()
|| this->must_sort_attached_input_sections()
diff --git a/gold/output.h b/gold/output.h
index 7355718..894773d 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -3468,6 +3468,19 @@ class Output_section : public Output_data
input_sections() const
{ return this->input_sections_; }
+ // Whether this always keeps an input section list
+ bool
+ always_keeps_input_sections() const
+ { return this->always_keeps_input_sections_; }
+
+ // Always keep an input section list.
+ void
+ set_always_keeps_input_sections()
+ {
+ gold_assert(this->current_data_size_for_child() == 0);
+ this->always_keeps_input_sections_ = true;
+ }
+
private:
// We only save enough information to undo the effects of section layout.
class Checkpoint_output_section
@@ -3784,6 +3797,8 @@ class Output_section : public Output_data
bool section_offsets_need_adjustment_ : 1;
// Whether this is a NOLOAD section.
bool is_noload_ : 1;
+ // Whether this always keeps input section.
+ bool always_keeps_input_sections_ : 1;
// For SHT_TLS sections, the offset of this section relative to the base
// of the TLS segment.
uint64_t tls_offset_;